diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9f9287b6..ca7666e1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,7 +42,6 @@ set(COMMON_SOURCES
src/main.cpp
src/smartlistmodel.cpp
src/utils.cpp
- src/pixbufmanipulator.cpp
src/rendermanager.cpp
src/connectivitymonitor.cpp
src/mainapplication.cpp
@@ -85,7 +84,6 @@ set(COMMON_HEADERS
src/globalsystemtray.h
src/appsettingsmanager.h
src/webchathelpers.h
- src/pixbufmanipulator.h
src/rendermanager.h
src/connectivitymonitor.h
src/jamiavatartheme.h
diff --git a/jami-qt.pro b/jami-qt.pro
index 20dfb494..473442d6 100644
--- a/jami-qt.pro
+++ b/jami-qt.pro
@@ -111,6 +111,7 @@ unix {
# Input
HEADERS += \
+ src/avatarimageprovider.h \
src/networkmanager.h \
src/smartlistmodel.h \
src/updatemanager.h \
@@ -123,7 +124,6 @@ HEADERS += \
src/globalsystemtray.h \
src/appsettingsmanager.h \
src/webchathelpers.h \
- src/pixbufmanipulator.h \
src/rendermanager.h \
src/connectivitymonitor.h \
src/jamiavatartheme.h \
@@ -168,7 +168,6 @@ SOURCES += \
src/main.cpp \
src/smartlistmodel.cpp \
src/utils.cpp \
- src/pixbufmanipulator.cpp \
src/rendermanager.cpp \
src/connectivitymonitor.cpp \
src/mainapplication.cpp \
diff --git a/qml.qrc b/qml.qrc
index e9cc0f52..1c03e350 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -97,7 +97,6 @@
src/mainview/components/ProjectCreditsScrollView.qml
src/mainview/components/AccountComboBoxPopup.qml
src/mainview/components/ConversationSmartListViewItemDelegate.qml
- src/mainview/components/ConversationSmartListUserImage.qml
src/mainview/components/SidePanelTabBar.qml
src/mainview/components/WelcomePageQrDialog.qml
src/commoncomponents/GeneralMenuItem.qml
@@ -137,5 +136,6 @@
src/commoncomponents/SimpleMessageDialog.qml
src/commoncomponents/ResponsiveImage.qml
src/commoncomponents/PresenceIndicator.qml
+ src/commoncomponents/AvatarImage.qml
diff --git a/src/accountadapter.cpp b/src/accountadapter.cpp
index 269ee2ef..f88a4ade 100644
--- a/src/accountadapter.cpp
+++ b/src/accountadapter.cpp
@@ -373,13 +373,15 @@ AccountAdapter::connectAccount(const QString& accountId)
&lrc::api::NewAccountModel::profileUpdated,
[this](const QString& accountId) {
if (LRCInstance::getCurrAccId() == accountId)
- emit accountStatusChanged();
+ emit accountStatusChanged(accountId);
});
accountStatusChangedConnection_
= QObject::connect(accInfo.accountModel,
&lrc::api::NewAccountModel::accountStatusChanged,
- [this] { emit accountStatusChanged(); });
+ [this](const QString& accountId) {
+ emit accountStatusChanged(accountId);
+ });
contactAddedConnection_
= QObject::connect(accInfo.contactModel.get(),
diff --git a/src/accountadapter.h b/src/accountadapter.h
index 291f067a..3d45333b 100644
--- a/src/accountadapter.h
+++ b/src/accountadapter.h
@@ -110,7 +110,7 @@ signals:
/*
* Trigger other components to reconnect account related signals.
*/
- void accountStatusChanged();
+ void accountStatusChanged(QString accountId = {});
void updateConversationForAddedContact();
/*
* send report failure to QML to make it show the right UI state .
diff --git a/src/accountlistmodel.cpp b/src/accountlistmodel.cpp
index 389037a6..c397b0f9 100644
--- a/src/accountlistmodel.cpp
+++ b/src/accountlistmodel.cpp
@@ -21,10 +21,7 @@
#include
-#include "globalinstances.h"
-
#include "lrcinstance.h"
-#include "pixbufmanipulator.h"
#include "utils.h"
AccountListModel::AccountListModel(QObject* parent)
@@ -68,6 +65,8 @@ AccountListModel::data(const QModelIndex& index, int role) const
auto& accountInfo = LRCInstance::accountModel().getAccountInfo(accountList.at(index.row()));
+ // Since we are using image provider right now, image url representation should be unique to
+ // be able to use the image cache, account avatar will only be updated once PictureUid changed
switch (role) {
case Role::Alias:
return QVariant(Utils::bestNameForAccount(accountInfo));
@@ -77,11 +76,10 @@ AccountListModel::data(const QModelIndex& index, int role) const
return QVariant(static_cast(accountInfo.profileInfo.type));
case Role::Status:
return QVariant(static_cast(accountInfo.status));
- case Role::Picture:
- return QString::fromLatin1(
- Utils::QImageToByteArray(Utils::accountPhoto(accountInfo)).toBase64().data());
case Role::ID:
return QVariant(accountInfo.id);
+ case Role::PictureUid:
+ return avatarUidMap_[accountInfo.id];
}
return QVariant();
}
@@ -92,10 +90,10 @@ AccountListModel::roleNames() const
QHash roles;
roles[Alias] = "Alias";
roles[Username] = "Username";
- roles[Picture] = "Picture";
roles[Type] = "Type";
roles[Status] = "Status";
roles[ID] = "ID";
+ roles[PictureUid] = "PictureUid";
return roles;
}
@@ -134,5 +132,28 @@ void
AccountListModel::reset()
{
beginResetModel();
+ fillAvatarUidMap(LRCInstance::accountModel().getAccountList());
endResetModel();
}
+
+void
+AccountListModel::updateAvatarUid(const QString& accountId)
+{
+ avatarUidMap_[accountId] = Utils::generateUid();
+}
+
+void
+AccountListModel::fillAvatarUidMap(const QStringList& accountList)
+{
+ if (accountList.size() == 0) {
+ avatarUidMap_.clear();
+ return;
+ }
+
+ if (avatarUidMap_.isEmpty() || accountList.size() != avatarUidMap_.size()) {
+ for (int i = 0; i < accountList.size(); ++i) {
+ if (!avatarUidMap_.contains(accountList.at(i)))
+ avatarUidMap_.insert(accountList.at(i), Utils::generateUid());
+ }
+ }
+}
diff --git a/src/accountlistmodel.h b/src/accountlistmodel.h
index 6741871d..b1d24789 100644
--- a/src/accountlistmodel.h
+++ b/src/accountlistmodel.h
@@ -30,7 +30,7 @@ class AccountListModel : public QAbstractListModel
Q_OBJECT
public:
- enum Role { Alias = Qt::UserRole + 1, Username, Picture, Type, Status, ID };
+ enum Role { Alias = Qt::UserRole + 1, Username, Type, Status, ID, PictureUid };
Q_ENUM(Role)
explicit AccountListModel(QObject* parent = 0);
@@ -55,4 +55,17 @@ public:
* This function is to reset the model when there's new account added.
*/
Q_INVOKABLE void reset();
+
+ /*
+ * This function is to update avatar uuid when there's an avatar changed.
+ */
+ Q_INVOKABLE void updateAvatarUid(const QString& accountId);
+
+private:
+ /*
+ * Give a uuid for each account avatar and it will serve PictureUid role
+ */
+ void fillAvatarUidMap(const QStringList& accountList);
+
+ QMap avatarUidMap_;
};
diff --git a/src/accountstomigratelistmodel.cpp b/src/accountstomigratelistmodel.cpp
index 98fd1a99..be9309fc 100644
--- a/src/accountstomigratelistmodel.cpp
+++ b/src/accountstomigratelistmodel.cpp
@@ -92,9 +92,6 @@ AccountsToMigrateListModel::data(const QModelIndex& index, int role) const
return QVariant(avatarInfo.confProperties.username);
case Role::Alias:
return QVariant(LRCInstance::accountModel().getAccountInfo(accountId).profileInfo.alias);
- case Role::Picture:
- return QString::fromLatin1(
- Utils::QImageToByteArray(Utils::accountPhoto(avatarInfo)).toBase64().data());
}
return QVariant();
}
@@ -108,7 +105,6 @@ AccountsToMigrateListModel::roleNames() const
roles[ManagerUri] = "ManagerUri";
roles[Username] = "Username";
roles[Alias] = "Alias";
- roles[Picture] = "Picture";
return roles;
}
diff --git a/src/accountstomigratelistmodel.h b/src/accountstomigratelistmodel.h
index 71abed75..6a35f80d 100644
--- a/src/accountstomigratelistmodel.h
+++ b/src/accountstomigratelistmodel.h
@@ -31,14 +31,7 @@ class AccountsToMigrateListModel : public QAbstractListModel
{
Q_OBJECT
public:
- enum Role {
- Account_ID = Qt::UserRole + 1,
- ManagerUsername,
- ManagerUri,
- Username,
- Alias,
- Picture
- };
+ enum Role { Account_ID = Qt::UserRole + 1, ManagerUsername, ManagerUri, Username, Alias };
Q_ENUM(Role)
explicit AccountsToMigrateListModel(QObject* parent = 0);
diff --git a/src/avatarimageprovider.h b/src/avatarimageprovider.h
new file mode 100644
index 00000000..b0cafc1c
--- /dev/null
+++ b/src/avatarimageprovider.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 by Savoir-faire Linux
+ * Author: Mingrui Zhang
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include "utils.h"
+
+#include
+#include
+
+class AvatarImageProvider : public QObject, public QQuickImageProvider
+{
+public:
+ AvatarImageProvider()
+ : QQuickImageProvider(QQuickImageProvider::Image,
+ QQmlImageProviderBase::ForceAsynchronousImageLoading)
+ {}
+
+ /*
+ * Request function
+ * id could be
+ * 1. account_ + account id
+ * 2. file_ + file path
+ * 3. contact_+ contact uri
+ * 4. conversation_+ conversation uid
+ */
+ QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize) override
+ {
+ Q_UNUSED(size)
+
+ auto idInfo = id.split("_");
+ // Id type -> account_
+ auto idType = idInfo[1];
+ // Id content -> every after account_
+ auto idContent = id.mid(id.indexOf(idType) + idType.length() + 1);
+
+ if (idContent.isEmpty())
+ return QImage();
+
+ if (idType == "account") {
+ return Utils::accountPhoto(LRCInstance::accountModel().getAccountInfo(idContent),
+ requestedSize);
+ } else if (idType == "conversation") {
+ auto* convModel = LRCInstance::getCurrentAccountInfo().conversationModel.get();
+ const auto& conv = convModel->getConversationForUID(idContent);
+ return Utils::contactPhoto(conv.participants[0], requestedSize);
+ } else if (idType == "contact") {
+ return Utils::contactPhoto(idContent, requestedSize);
+ } else {
+ auto image = Utils::cropImage(QImage(idContent));
+ return image.scaled(requestedSize,
+ Qt::KeepAspectRatioByExpanding,
+ Qt::SmoothTransformation);
+ }
+ }
+};
diff --git a/src/bannedlistmodel.cpp b/src/bannedlistmodel.cpp
index b07e6cb6..684f5b44 100644
--- a/src/bannedlistmodel.cpp
+++ b/src/bannedlistmodel.cpp
@@ -61,12 +61,6 @@ BannedListModel::data(const QModelIndex& index, int role) const
return QVariant(contactInfo.registeredName);
case Role::ContactID:
return QVariant(contactInfo.profileInfo.uri);
- case Role::ContactPicture:
- QImage avatarImage = Utils::fallbackAvatar(contactInfo.profileInfo.uri,
- contactInfo.registeredName,
- QSize(48, 48));
-
- return QString::fromLatin1(Utils::QImageToByteArray(avatarImage).toBase64().data());
}
return QVariant();
}
@@ -77,7 +71,6 @@ BannedListModel::roleNames() const
QHash roles;
roles[ContactName] = "ContactName";
roles[ContactID] = "ContactID";
- roles[ContactPicture] = "ContactPicture";
return roles;
}
diff --git a/src/bannedlistmodel.h b/src/bannedlistmodel.h
index f664b9b5..28a2951e 100644
--- a/src/bannedlistmodel.h
+++ b/src/bannedlistmodel.h
@@ -27,7 +27,7 @@ class BannedListModel : public QAbstractListModel
BannedListModel(const BannedListModel& cpy);
public:
- enum Role { ContactName = Qt::UserRole + 1, ContactID, ContactPicture };
+ enum Role { ContactName = Qt::UserRole + 1, ContactID };
Q_ENUM(Role)
explicit BannedListModel(QObject* parent = nullptr);
diff --git a/src/commoncomponents/AccountMigrationDialog.qml b/src/commoncomponents/AccountMigrationDialog.qml
index 838f1131..e9e8aae4 100644
--- a/src/commoncomponents/AccountMigrationDialog.qml
+++ b/src/commoncomponents/AccountMigrationDialog.qml
@@ -42,7 +42,6 @@ Window {
property bool nonOperationClosing: true
property bool successState : true
- property string imgBase64: ""
signal accountMigrationFinished
@@ -88,8 +87,7 @@ Window {
accountID = accountsToMigrateListModel.data(accountsToMigrateListModel.index(
0, 0), AccountsToMigrateListModel.Account_ID)
- imgBase64 = accountsToMigrateListModel.data(accountsToMigrateListModel.index(
- 0, 0), AccountsToMigrateListModel.Picture)
+ avatarImg.updateImage(accountID)
connectionMigrationEnded.enabled = false
migrationPushButton.enabled = false
@@ -284,17 +282,13 @@ Window {
anchors.fill: parent
color: "transparent"
- Image {
+ AvatarImage {
id: avatarImg
anchors.fill: parent
- source: {
- if (imgBase64.length === 0) {
- return ""
- } else {
- return "data:image/png;base64," + imgBase64
- }
- }
+
+ showPresenceIndicator: false
+
fillMode: Image.PreserveAspectCrop
layer.enabled: true
layer.effect: OpacityMask {
diff --git a/src/commoncomponents/AvatarImage.qml b/src/commoncomponents/AvatarImage.qml
new file mode 100644
index 00000000..28497a43
--- /dev/null
+++ b/src/commoncomponents/AvatarImage.qml
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2020 by Savoir-faire Linux
+ * Author: Mingrui Zhang
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Window 2.14
+import net.jami.Models 1.0
+
+Item {
+ id: root
+
+ // FromUrl here is for grabToImage image url
+ enum Mode {
+ FromAccount = 0,
+ FromFile,
+ FromContactUri,
+ FromConvUid,
+ FromUrl,
+ Default
+ }
+
+ property alias fillMode: rootImage.fillMode
+ property alias sourceSize: rootImage.sourceSize
+ property int mode: AvatarImage.Mode.FromAccount
+ property string imageProviderIdPrefix: {
+ switch(mode) {
+ case AvatarImage.Mode.FromAccount:
+ return "account_"
+ case AvatarImage.Mode.FromFile:
+ return "file_"
+ case AvatarImage.Mode.FromContactUri:
+ return "contact_"
+ case AvatarImage.Mode.FromConvUid:
+ return "conversation_"
+ default:
+ return ""
+ }
+ }
+
+ // Full request url example: forceUpdateUrl_xxxxxxx_account_xxxxxxxx
+ property string imageProviderUrl: "image://avatarImage/" + forceUpdateUrl + "_" +
+ imageProviderIdPrefix
+ property string imageId: ""
+ property string defaultImgUrl: "qrc:/images/default_avatar_overlay.svg"
+ property string forceUpdateUrl: Date.now()
+ property alias presenceStatus: presenceIndicator.status
+ property bool showPresenceIndicator: true
+ property int unreadMessagesCount: 0
+
+ signal imageIsReady
+
+ function updateImage(updatedId, oneTimeForceUpdateUrl) {
+ imageId = updatedId
+ if (oneTimeForceUpdateUrl === undefined)
+ forceUpdateUrl = Date.now()
+ else
+ forceUpdateUrl = oneTimeForceUpdateUrl
+
+ if (mode === AvatarImage.Mode.FromUrl)
+ rootImage.source = imageId
+ else if (imageId)
+ rootImage.source = imageProviderUrl + imageId
+ }
+
+ onModeChanged: {
+ if (mode === AvatarImage.Mode.Default)
+ rootImage.source = defaultImgUrl
+ }
+
+ Image {
+ id: rootImage
+
+ anchors.fill: root
+
+ smooth: false
+ antialiasing: true
+
+ sourceSize.width: Math.max(24, width)
+ sourceSize.height: Math.max(24, height)
+
+ fillMode: Image.PreserveAspectFit
+
+ onStatusChanged: {
+ if (status === Image.Ready) {
+ rootImageOverlay.state = ""
+ rootImageOverlay.state = "rootImageLoading"
+ }
+ }
+
+ Component.onCompleted: {
+ if (imageId)
+ return source = imageProviderUrl + imageId
+ return source = ""
+ }
+
+ Image {
+ id: rootImageOverlay
+
+ anchors.fill: rootImage
+
+ smooth: false
+ antialiasing: true
+
+ sourceSize.width: Math.max(24, width)
+ sourceSize.height: Math.max(24, height)
+
+ fillMode: Image.PreserveAspectFit
+
+ onOpacityChanged: {
+ if (opacity === 0)
+ source = rootImage.source
+ }
+
+ onStatusChanged: {
+ if (status === Image.Ready && opacity === 0) {
+ opacity = 1
+ root.imageIsReady()
+ }
+ }
+
+ states: State {
+ name: "rootImageLoading"
+ PropertyChanges { target: rootImageOverlay; opacity: 0}
+ }
+
+ transitions: Transition {
+ NumberAnimation { properties: "opacity"; easing.type: Easing.InOutQuad; duration: 400}
+ }
+ }
+ }
+
+ PresenceIndicator {
+ id: presenceIndicator
+
+ anchors.right: root.right
+ anchors.bottom: root.bottom
+
+ size: root.width * 0.3
+
+ visible: showPresenceIndicator
+ }
+
+ Rectangle {
+ id: unreadMessageCountRect
+
+ anchors.right: root.right
+ anchors.top: root.top
+
+ width: root.width * 0.3
+ height: root.width * 0.3
+
+ visible: unreadMessagesCount > 0
+
+ Text {
+ id: unreadMessageCounttext
+
+ anchors.centerIn: unreadMessageCountRect
+
+ text: unreadMessagesCount > 9 ? "…" : unreadMessagesCount
+ color: "white"
+ font.pointSize: JamiTheme.textFontSize - 2
+ }
+
+ radius: 30
+ color: JamiTheme.notificationRed
+ }
+
+}
diff --git a/src/commoncomponents/PhotoboothView.qml b/src/commoncomponents/PhotoboothView.qml
index f2800493..1b7e2a0e 100644
--- a/src/commoncomponents/PhotoboothView.qml
+++ b/src/commoncomponents/PhotoboothView.qml
@@ -10,9 +10,10 @@ import net.jami.Adapters 1.0
ColumnLayout {
property bool takePhotoState: false
property bool hasAvatar: false
- property bool isDefaultIcon: false
- property string imgBase64: ""
+ // saveToConfig is to specify whether the image should be saved to account config
+ property bool saveToConfig: false
property string fileName: ""
+ property var boothImg: ""
property int boothWidth: 224
@@ -20,9 +21,6 @@ ColumnLayout {
buttonsRowLayout.height +
JamiTheme.preferredMarginSize / 2
- signal imageAcquired
- signal imageCleared
-
function startBooth(force = false){
hasAvatar = false
AccountAdapter.startPreviewing(force)
@@ -39,12 +37,15 @@ ColumnLayout {
takePhotoState = false
}
- function setAvatarPixmap(avatarPixmapBase64, defaultValue = false){
- imgBase64 = avatarPixmapBase64
- stopBooth()
- if(defaultValue){
- isDefaultIcon = defaultValue
- }
+ function setAvatarImage(mode = AvatarImage.Mode.FromAccount,
+ imageId = AccountAdapter.currentAccountId){
+ if (mode === AvatarImage.Mode.Default)
+ boothImg = ""
+
+ avatarImg.mode = mode
+
+ if (imageId)
+ avatarImg.updateImage(imageId)
}
onVisibleChanged: {
@@ -68,14 +69,13 @@ ColumnLayout {
onAccepted: {
fileName = file
if (fileName.length === 0) {
- imageCleared()
+ SettingsAdapter.clearCurrentAvatar()
+ setAvatarImage()
return
}
- imgBase64 = UtilsAdapter.getCroppedImageBase64FromFile(
- UtilsAdapter.getAbsPath(fileName),
- boothWidth)
- imageAcquired()
- stopBooth()
+
+ setAvatarImage(AvatarImage.Mode.FromFile,
+ UtilsAdapter.getAbsPath(fileName))
}
}
@@ -96,29 +96,40 @@ ColumnLayout {
color: "grey"
radius: height / 2
- Image {
+ AvatarImage {
id: avatarImg
anchors.fill: parent
- source: {
- if(imgBase64.length === 0){
- return "qrc:/images/default_avatar_overlay.svg"
- } else {
- return "data:image/png;base64," + imgBase64
- }
- }
+
+ imageId: AccountAdapter.currentAccountId
+
+ showPresenceIndicator: false
+
fillMode: Image.PreserveAspectCrop
+
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: avatarImg.width
height: avatarImg.height
radius: {
- var size = ((avatarImg.width <= avatarImg.height)? avatarImg.width:avatarImg.height)
- return size /2
+ var size = ((avatarImg.width <= avatarImg.height) ?
+ avatarImg.width:avatarImg.height)
+ return size / 2
}
}
}
+
+ onImageIsReady: {
+ // Once image is loaded (updated), save to boothImg
+ avatarImg.grabToImage(function(result) {
+ if (mode !== AvatarImage.Mode.Default)
+ boothImg = result.image
+
+ if (saveToConfig)
+ SettingsAdapter.setCurrAccAvatar(result.image)
+ })
+ }
}
}
}
@@ -126,9 +137,7 @@ ColumnLayout {
PhotoboothPreviewRender {
id:previewWidget
- onHideBooth:{
- stopBooth()
- }
+ onHideBooth: stopBooth()
visible: takePhotoState
focus: visible
@@ -143,8 +152,9 @@ ColumnLayout {
width: previewWidget.width
height: previewWidget.height
radius: {
- var size = ((previewWidget.width <= previewWidget.height)? previewWidget.width:previewWidget.height)
- return size /2
+ var size = ((previewWidget.width <= previewWidget.height) ?
+ previewWidget.width:previewWidget.height)
+ return size / 2
}
}
}
@@ -191,7 +201,6 @@ ColumnLayout {
radius: height / 6
source: {
-
if(takePhotoState) {
toolTipText = qsTr("Take photo")
return cameraAltIconUrl
@@ -205,9 +214,9 @@ ColumnLayout {
return addPhotoIconUrl
}
}
+
onClicked: {
if(!takePhotoState){
- imageCleared()
startBooth()
return
} else {
@@ -215,11 +224,13 @@ ColumnLayout {
flashOverlay.visible = true
flashAnimation.restart()
- // run concurrent function call to take photo
- imgBase64 = previewWidget.takeCroppedPhotoToBase64(boothWidth)
- hasAvatar = true
- imageAcquired()
- stopBooth()
+ previewWidget.grabToImage(function(result) {
+
+ setAvatarImage(AvatarImage.Mode.FromUrl, result.url)
+
+ hasAvatar = true
+ stopBooth()
+ })
}
}
}
diff --git a/src/conversationsadapter.cpp b/src/conversationsadapter.cpp
index b9333b27..27d83640 100644
--- a/src/conversationsadapter.cpp
+++ b/src/conversationsadapter.cpp
@@ -209,6 +209,14 @@ ConversationsAdapter::connectConversationModel(bool updateFilter)
emit modelSorted(QVariant::fromValue(conversation.uid));
});
+ contactProfileUpdatedConnection_
+ = QObject::connect(LRCInstance::getCurrentAccountInfo().contactModel.get(),
+ &lrc::api::ContactModel::profileUpdated,
+ [this](const QString& contactUri) {
+ conversationSmartListModel_->updateContactAvatarUid(contactUri);
+ emit updateListViewRequested();
+ });
+
modelUpdatedConnection_ = QObject::connect(currentConversationModel,
&lrc::api::ConversationModel::conversationUpdated,
[this](const QString& convUid) {
@@ -262,7 +270,7 @@ ConversationsAdapter::connectConversationModel(bool updateFilter)
&lrc::api::ConversationModel::searchStatusChanged,
[this](const QString& status) { emit showSearchStatus(status); });
- // This connection is ideal when separated search results list.
+ // This connection is ideal when separated search results list.
// This signal is guaranteed to fire just after filterChanged during a search if results are
// changed, and once before filterChanged when calling setFilter.
// NOTE: Currently, when searching, the entire conversation list will be copied 2-3 times each
@@ -295,6 +303,7 @@ ConversationsAdapter::disconnectConversationModel()
QObject::disconnect(interactionRemovedConnection_);
QObject::disconnect(searchStatusChangedConnection_);
QObject::disconnect(searchResultUpdatedConnection_);
+ QObject::disconnect(contactProfileUpdatedConnection_);
}
void
diff --git a/src/conversationsadapter.h b/src/conversationsadapter.h
index abd97368..6fc23a0a 100644
--- a/src/conversationsadapter.h
+++ b/src/conversationsadapter.h
@@ -82,6 +82,7 @@ private:
QMetaObject::Connection newConversationConnection_;
QMetaObject::Connection conversationRemovedConnection_;
QMetaObject::Connection conversationClearedConnection;
+ QMetaObject::Connection contactProfileUpdatedConnection_;
QMetaObject::Connection selectedCallChanged_;
QMetaObject::Connection smartlistSelectionConnection_;
QMetaObject::Connection interactionRemovedConnection_;
diff --git a/src/lrcinstance.h b/src/lrcinstance.h
index ebebd20d..909806e8 100644
--- a/src/lrcinstance.h
+++ b/src/lrcinstance.h
@@ -336,15 +336,6 @@ public:
return -1;
}
- static const QPixmap getCurrAccPixmap()
- {
- return instance()
- .accountListModel_
- .data(instance().accountListModel_.index(getCurrentAccountIndex()),
- AccountListModel::Role::Picture)
- .value();
- }
-
static void setAvatarForAccount(const QPixmap& avatarPixmap, const QString& accountID)
{
QByteArray ba;
diff --git a/src/mainapplication.cpp b/src/mainapplication.cpp
index 654387d2..33b3f2d4 100644
--- a/src/mainapplication.cpp
+++ b/src/mainapplication.cpp
@@ -26,10 +26,8 @@
#include "globalsystemtray.h"
#include "qmlregister.h"
#include "qrimageprovider.h"
-#include "pixbufmanipulator.h"
#include "tintedbuttonimageprovider.h"
-
-#include "globalinstances.h"
+#include "avatarimageprovider.h"
#include
#include
@@ -148,7 +146,6 @@ MainApplication::init()
gnutls_global_init();
#endif
- GlobalInstances::setPixmapManipulator(std::make_unique());
initLrc(results[opts::UPDATEURL].toString(), connectivityMonitor_);
#ifdef Q_OS_WIN
@@ -322,6 +319,7 @@ MainApplication::initQmlEngine()
engine_->addImageProvider(QLatin1String("qrImage"), new QrImageProvider());
engine_->addImageProvider(QLatin1String("tintedPixmap"), new TintedButtonImageProvider());
+ engine_->addImageProvider(QLatin1String("avatarImage"), new AvatarImageProvider());
engine_->load(QUrl(QStringLiteral("qrc:/src/MainApplicationWindow.qml")));
}
diff --git a/src/mainview/MainView.qml b/src/mainview/MainView.qml
index a757276c..3d61b27b 100644
--- a/src/mainview/MainView.qml
+++ b/src/mainview/MainView.qml
@@ -308,8 +308,8 @@ Window {
mainViewWindowSidePanel.forceReselectConversationSmartListCurrentIndex()
}
- function onAccountStatusChanged() {
- accountComboBox.resetAccountListModel()
+ function onAccountStatusChanged(accountId) {
+ accountComboBox.resetAccountListModel(accountId)
}
}
diff --git a/src/mainview/components/AccountComboBox.qml b/src/mainview/components/AccountComboBox.qml
index 53f4dff9..76f2beb8 100644
--- a/src/mainview/components/AccountComboBox.qml
+++ b/src/mainview/components/AccountComboBox.qml
@@ -31,7 +31,8 @@ ComboBox {
signal settingBtnClicked
// Reset accountListModel.
- function resetAccountListModel() {
+ function resetAccountListModel(accountId) {
+ accountListModel.updateAvatarUid(accountId)
accountListModel.reset()
}
@@ -39,9 +40,11 @@ ComboBox {
target: accountListModel
function onModelReset() {
- userImageRoot.source = "data:image/png;base64," + accountListModel.data(
- accountListModel.index(0, 0), AccountListModel.Picture)
- currentAccountPresenceIndicator.status =
+ userImageRoot.updateImage(
+ AccountAdapter.currentAccountId,
+ accountListModel.data(
+ accountListModel.index(0, 0), AccountListModel.PictureUid))
+ userImageRoot.presenceStatus =
accountListModel.data(accountListModel.index(0, 0), AccountListModel.Status)
textMetricsUserAliasRoot.text = accountListModel.data(accountListModel.index(0,0),
AccountListModel.Alias)
@@ -50,34 +53,20 @@ ComboBox {
}
}
- Image {
+ AvatarImage {
id: userImageRoot
anchors.left: root.left
anchors.leftMargin: 16
anchors.verticalCenter: root.verticalCenter
- width: 30
- height: 30
+ width: 40
+ height: 40
- fillMode: Image.PreserveAspectFit
+ imageId: AccountAdapter.currentAccountId
- // Base 64 format
- source: "data:image/png;base64," + accountListModel.data(
- accountListModel.index(0, 0), AccountListModel.Picture)
- mipmap: true
-
- PresenceIndicator {
- id: currentAccountPresenceIndicator
-
- anchors.right: userImageRoot.right
- anchors.rightMargin: -2
- anchors.bottom: userImageRoot.bottom
- anchors.bottomMargin: -2
-
- status: accountListModel.data(accountListModel.index(0, 0),
- AccountListModel.Status)
- }
+ presenceStatus: accountListModel.data(accountListModel.index(0, 0),
+ AccountListModel.Status)
}
Text {
@@ -251,8 +240,6 @@ ComboBox {
}
}
-
-
indicator: null
// Overwrite the combo box pop up to add footer (for add accounts).
diff --git a/src/mainview/components/AccountComboBoxPopup.qml b/src/mainview/components/AccountComboBoxPopup.qml
index a40318cf..70869f91 100644
--- a/src/mainview/components/AccountComboBoxPopup.qml
+++ b/src/mainview/components/AccountComboBoxPopup.qml
@@ -45,42 +45,29 @@ Popup {
contentItem: ListView {
id: comboBoxPopupListView
-
// In list view, index is an interger.
clip: true
model: accountListModel
implicitHeight: contentHeight
delegate: ItemDelegate {
- Image {
+ AvatarImage {
id: userImage
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
- width: 30
- height: 30
+ width: 40
+ height: 40
- fillMode: Image.PreserveAspectFit
- mipmap: true
+ presenceStatus: Status
- // Role::Picture
- source: {
- var data = accountListModel.data(accountListModel.index(index, 0),
- AccountListModel.Picture)
- if (data === undefined) {
- return ""
- }
- return "data:image/png;base64," + data
- }
-
- PresenceIndicator {
- anchors.right: userImage.right
- anchors.rightMargin: -2
- anchors.bottom: userImage.bottom
- anchors.bottomMargin: -2
-
- status: Status
+ Component.onCompleted: {
+ return updateImage(
+ accountListModel.data(
+ accountListModel.index(index, 0), AccountListModel.ID),
+ accountListModel.data(
+ accountListModel.index(index, 0), AccountListModel.PictureUid))
}
}
diff --git a/src/mainview/components/AudioCallPage.qml b/src/mainview/components/AudioCallPage.qml
index 56a7ed12..74508ac7 100644
--- a/src/mainview/components/AudioCallPage.qml
+++ b/src/mainview/components/AudioCallPage.qml
@@ -28,7 +28,6 @@ import "../../commoncomponents"
Rectangle {
id: audioCallPageRect
- property string contactImgSource: ""
property string bestName: "Best Name"
property string bestId: "Best Id"
@@ -37,8 +36,7 @@ Rectangle {
signal showFullScreenReqested
function updateUI(accountId, convUid) {
- contactImgSource = "data:image/png;base64," + UtilsAdapter.getContactImageString(
- accountId, convUid)
+ contactImage.updateImage(convUid)
bestName = UtilsAdapter.getBestName(accountId, convUid)
var id = UtilsAdapter.getBestId(accountId, convUid)
@@ -162,7 +160,7 @@ Rectangle {
ColumnLayout {
id: audioCallPageRectColumnLayout
- Image {
+ AvatarImage {
id: contactImage
Layout.alignment: Qt.AlignCenter
@@ -170,9 +168,8 @@ Rectangle {
Layout.preferredWidth: 100
Layout.preferredHeight: 100
- fillMode: Image.PreserveAspectFit
- source: contactImgSource
- asynchronous: true
+ mode: AvatarImage.Mode.FromConvUid
+ showPresenceIndicator: false
}
Text {
diff --git a/src/mainview/components/ContactPicker.qml b/src/mainview/components/ContactPicker.qml
index 92e669ee..11db11f9 100644
--- a/src/mainview/components/ContactPicker.qml
+++ b/src/mainview/components/ContactPicker.qml
@@ -125,8 +125,6 @@ Popup {
}
onAboutToShow: {
-
-
// Reset the model on each show.
contactPickerListView.model = ContactAdapter.getContactSelectableModel(
type)
diff --git a/src/mainview/components/ContactPickerItemDelegate.qml b/src/mainview/components/ContactPickerItemDelegate.qml
index 531e9719..e9aa9b62 100644
--- a/src/mainview/components/ContactPickerItemDelegate.qml
+++ b/src/mainview/components/ContactPickerItemDelegate.qml
@@ -26,7 +26,7 @@ import "../../commoncomponents"
ItemDelegate {
id: contactPickerItemDelegate
- Image {
+ AvatarImage {
id: contactPickerContactImage
anchors.left: parent.left
@@ -36,9 +36,8 @@ ItemDelegate {
width: 40
height: 40
- fillMode: Image.PreserveAspectFit
- source: "data:image/png;base64," + Picture
- mipmap: true
+ mode: AvatarImage.Mode.FromContactUri
+ imageId: URI
}
Rectangle {
diff --git a/src/mainview/components/ConversationSmartListUserImage.qml b/src/mainview/components/ConversationSmartListUserImage.qml
deleted file mode 100644
index 77281612..00000000
--- a/src/mainview/components/ConversationSmartListUserImage.qml
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2020 by Savoir-faire Linux
- * Author: Mingrui Zhang
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-import QtQuick 2.14
-import QtQuick.Controls 2.14
-import QtQuick.Layouts 1.14
-import net.jami.Models 1.0
-import "../../commoncomponents"
-
-Image {
- id: userImage
-
- width: 40
- height: 40
-
- fillMode: Image.PreserveAspectFit
- source: "data:image/png;base64," + Picture
- mipmap: true
-
- PresenceIndicator {
- anchors.right: userImage.right
- anchors.bottom: userImage.bottom
-
- visible: Presence === undefined ? false : Presence
- }
-
- Rectangle {
- id: unreadMessageCountRect
-
- anchors.right: userImage.right
- anchors.rightMargin: -2
- anchors.top: userImage.top
- anchors.topMargin: -2
-
- width: 14
- height: 14
-
- visible: UnreadMessagesCount > 0
-
- Text {
- id: unreadMessageCounttext
-
- anchors.centerIn: unreadMessageCountRect
-
- text: UnreadMessagesCount > 9 ? "···" : UnreadMessagesCount
- color: "white"
- font.pointSize: JamiTheme.textFontSize
- }
-
- radius: 30
- color: JamiTheme.notificationRed
- }
-}
diff --git a/src/mainview/components/ConversationSmartListView.qml b/src/mainview/components/ConversationSmartListView.qml
index 109f6918..4c362da8 100644
--- a/src/mainview/components/ConversationSmartListView.qml
+++ b/src/mainview/components/ConversationSmartListView.qml
@@ -89,6 +89,8 @@ ListView {
delegate: ConversationSmartListViewItemDelegate {
id: smartListItemDelegate
+
+ onUpdateContactAvatarUidRequested: root.model.updateContactAvatarUid(uid)
}
ScrollIndicator.vertical: ScrollIndicator {}
diff --git a/src/mainview/components/ConversationSmartListViewItemDelegate.qml b/src/mainview/components/ConversationSmartListViewItemDelegate.qml
index f2489e5a..a7f08197 100644
--- a/src/mainview/components/ConversationSmartListViewItemDelegate.qml
+++ b/src/mainview/components/ConversationSmartListViewItemDelegate.qml
@@ -30,6 +30,8 @@ ItemDelegate {
property int lastInteractionPreferredWidth: 80
+ signal updateContactAvatarUidRequested(string uid)
+
function convUid() {
return UID
}
@@ -76,14 +78,29 @@ ItemDelegate {
}
}
- ConversationSmartListUserImage {
+ AvatarImage {
id: conversationSmartListUserImage
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 16
- }
+ width: 40
+ height: 40
+
+ mode: AvatarImage.Mode.FromContactUri
+
+ showPresenceIndicator: Presence === undefined ? false : Presence
+
+ unreadMessagesCount: UnreadMessagesCount
+
+ Component.onCompleted: {
+ var contactUid = URI
+ if (ContactType === Profile.Type.TEMPORARY)
+ updateContactAvatarUidRequested(contactUid)
+ updateImage(contactUid, PictureUid)
+ }
+ }
RowLayout {
id: rowUsernameAndLastInteractionDate
@@ -202,7 +219,7 @@ ItemDelegate {
userProfile.aliasText = DisplayName
userProfile.registeredNameText = DisplayID
userProfile.idText = URI
- userProfile.contactPicBase64 = Picture
+ userProfile.contactImageUid = UID
smartListContextMenu.openMenu()
} else if (mouse.button === Qt.LeftButton) {
conversationSmartListView.currentIndex = -1
diff --git a/src/mainview/components/ParticipantOverlay.qml b/src/mainview/components/ParticipantOverlay.qml
index c98faa52..e952bc52 100644
--- a/src/mainview/components/ParticipantOverlay.qml
+++ b/src/mainview/components/ParticipantOverlay.qml
@@ -39,6 +39,7 @@ Rectangle {
participantName.text = name
}
+ // TODO: try to use AvatarImage as well
function setAvatar(avatar) {
if (avatar === "") {
opacity = 0
diff --git a/src/mainview/components/UserInfoCallPage.qml b/src/mainview/components/UserInfoCallPage.qml
index 2275bfd4..98598f28 100644
--- a/src/mainview/components/UserInfoCallPage.qml
+++ b/src/mainview/components/UserInfoCallPage.qml
@@ -30,13 +30,11 @@ Rectangle {
id: userInfoCallRect
property int buttonPreferredSize: 48
- property string contactImgSource: ""
property string bestName: "Best Name"
property string bestId: "Best Id"
function updateUI(accountId, convUid) {
- contactImgSource = "data:image/png;base64," + UtilsAdapter.getContactImageString(
- accountId, convUid)
+ contactImg.updateImage(convUid)
bestName = UtilsAdapter.getBestName(accountId, convUid)
var id = UtilsAdapter.getBestId(accountId, convUid)
bestId = (bestName !== id) ? id : ""
@@ -74,7 +72,7 @@ Rectangle {
onClicked: mainViewWindow.showWelcomeView()
}
- Image {
+ AvatarImage {
id: contactImg
Layout.alignment: Qt.AlignCenter
@@ -83,9 +81,8 @@ Rectangle {
Layout.preferredWidth: 100
Layout.preferredHeight: 100
- fillMode: Image.PreserveAspectFit
- source: contactImgSource
- asynchronous: true
+ mode: AvatarImage.Mode.FromConvUid
+ showPresenceIndicator: false
}
Rectangle {
diff --git a/src/mainview/components/UserProfile.qml b/src/mainview/components/UserProfile.qml
index 4914d7eb..31f6543c 100644
--- a/src/mainview/components/UserProfile.qml
+++ b/src/mainview/components/UserProfile.qml
@@ -28,7 +28,7 @@ BaseDialog {
id: root
property string responsibleConvUid: ""
- property string contactPicBase64: ""
+ property string contactImageUid: ""
property string aliasText: ""
property string registeredNameText: ""
property string idText: ""
@@ -53,17 +53,17 @@ BaseDialog {
rowSpacing: 16
columnSpacing: 24
- Image {
+ AvatarImage {
id: contactImage
Layout.alignment: Qt.AlignRight
- Layout.preferredWidth: 130
+ Layout.preferredWidth: preferredImgSize
sourceSize.width: preferredImgSize
sourceSize.height: preferredImgSize
- fillMode: Image.PreserveAspectFit
- mipmap: true
+ mode: AvatarImage.Mode.FromConvUid
+ showPresenceIndicator: false
}
// Visible when user alias is not empty or equals to id.
@@ -196,8 +196,5 @@ BaseDialog {
contactQrImage.source = "image://qrImage/contact_" + responsibleConvUid
}
- onContactPicBase64Changed: {
- if (contactPicBase64 !== "")
- contactImage.source = "data:image/png;base64," + contactPicBase64
- }
+ onContactImageUidChanged: contactImage.updateImage(contactImageUid)
}
diff --git a/src/messagesadapter.cpp b/src/messagesadapter.cpp
index f1e556b8..da93bd50 100644
--- a/src/messagesadapter.cpp
+++ b/src/messagesadapter.cpp
@@ -450,14 +450,14 @@ MessagesAdapter::setConversationProfileData(const lrc::api::conversation::Info&
auto& contact = accInfo->contactModel->getContact(contactUri);
auto bestName = Utils::bestNameForConversation(convInfo, *convModel);
setInvitation(contact.profileInfo.type == lrc::api::profile::Type::PENDING
- || contact.profileInfo.type == lrc::api::profile::Type::TEMPORARY,
+ || contact.profileInfo.type == lrc::api::profile::Type::TEMPORARY,
bestName,
contactUri);
if (!contact.profileInfo.avatar.isEmpty()) {
setSenderImage(contactUri, contact.profileInfo.avatar);
} else {
- auto avatar = Utils::conversationPhoto(convInfo.uid, *accInfo, true);
+ auto avatar = Utils::contactPhoto(convInfo.participants[0]);
QByteArray ba;
QBuffer bu(&ba);
avatar.save(&bu, "PNG");
diff --git a/src/pixbufmanipulator.cpp b/src/pixbufmanipulator.cpp
deleted file mode 100644
index 4860e722..00000000
--- a/src/pixbufmanipulator.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2015-2020 by Savoir-faire Linux
- * Author: Edric Ladent Milaret
- * Author: Anthony Léonard
- * Author: Olivier Soldano
- * Author: Andreas Traczyk
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "pixbufmanipulator.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "globalinstances.h"
-
-#include
-#include
-#include
-#include
-
-#include "utils.h"
-#undef interface
-
-QVariant
-PixbufManipulator::personPhoto(const QByteArray& data, const QString& type)
-{
- QImage avatar;
- const bool ret = avatar.loadFromData(QByteArray::fromBase64(data), type.toLatin1());
- if (!ret) {
- qDebug() << "vCard image loading failed";
- return QVariant();
- }
- return QPixmap::fromImage(Utils::getCirclePhoto(avatar, avatar.size().width()));
-}
-
-QVariant
-PixbufManipulator::numberCategoryIcon(const QVariant& p,
- const QSize& size,
- bool displayPresence,
- bool isPresent)
-{
- Q_UNUSED(p)
- Q_UNUSED(size)
- Q_UNUSED(displayPresence)
- Q_UNUSED(isPresent)
- return QVariant();
-}
-
-QByteArray
-PixbufManipulator::toByteArray(const QVariant& pxm)
-{
- auto image = pxm.value();
- QByteArray ba = Utils::QImageToByteArray(image);
- return ba;
-}
-
-QVariant
-PixbufManipulator::userActionIcon(const UserActionElement& state) const
-{
- Q_UNUSED(state)
- return QVariant();
-}
-
-QVariant
-PixbufManipulator::decorationRole(const QModelIndex& index)
-{
- Q_UNUSED(index)
- return QVariant();
-}
-
-QVariant
-PixbufManipulator::decorationRole(const lrc::api::conversation::Info& conversationInfo,
- const lrc::api::account::Info& accountInfo)
-{
- QImage photo;
- auto contacts = conversationInfo.participants;
- if (contacts.empty()) {
- return QVariant::fromValue(photo);
- }
- try {
- /*
- * Get first contact photo.
- */
- auto contactUri = contacts.front();
- auto contactInfo = accountInfo.contactModel->getContact(contactUri);
- auto contactPhoto = contactInfo.profileInfo.avatar;
- auto bestName = Utils::bestNameForContact(contactInfo);
- auto bestId = Utils::bestIdForContact(contactInfo);
- if (accountInfo.profileInfo.type == lrc::api::profile::Type::SIP
- && contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY) {
- photo = Utils::fallbackAvatar(QString(), QString());
- } else if (contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY
- && contactInfo.profileInfo.uri.isEmpty()) {
- photo = Utils::fallbackAvatar(QString(), QString());
- } else if (!contactPhoto.isEmpty()) {
- QByteArray byteArray = contactPhoto.toLocal8Bit();
- photo = personPhoto(byteArray, nullptr).value();
- if (photo.isNull()) {
- auto avatarName = contactInfo.profileInfo.uri == bestName ? QString() : bestName;
- photo = Utils::fallbackAvatar("ring:" + contactInfo.profileInfo.uri, avatarName);
- }
- } else {
- auto avatarName = contactInfo.profileInfo.uri == bestName ? QString() : bestName;
- photo = Utils::fallbackAvatar("ring:" + contactInfo.profileInfo.uri, avatarName);
- }
- } catch (...) {
- }
- return QVariant::fromValue(Utils::scaleAndFrame(photo));
-}
diff --git a/src/pixbufmanipulator.h b/src/pixbufmanipulator.h
deleted file mode 100644
index 7788f652..00000000
--- a/src/pixbufmanipulator.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2015-2020 by Savoir-faire Linux
- * Author: Edric Ladent Milaret
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#pragma once
-
-#include
-
-#include
-#include
-
-Q_DECLARE_METATYPE(QImage);
-
-class Person;
-
-QByteArray QImageToByteArray(QImage image);
-
-class PixbufManipulator : public Interfaces::PixmapManipulatorI
-{
-public:
- QVariant personPhoto(const QByteArray& data, const QString& type = "PNG") override;
-
- /*
- * TODO: the following methods return an empty QVariant/QByteArray.
- */
- QVariant numberCategoryIcon(const QVariant& p,
- const QSize& size,
- bool displayPresence = false,
- bool isPresent = false) override;
- QByteArray toByteArray(const QVariant& pxm) override;
- QVariant userActionIcon(const UserActionElement& state) const override;
- QVariant decorationRole(const QModelIndex& index) override;
- QVariant decorationRole(const lrc::api::conversation::Info& conversation,
- const lrc::api::account::Info& accountInfo) override;
-};
diff --git a/src/previewrenderer.cpp b/src/previewrenderer.cpp
index d5c72a14..92cd0f0c 100644
--- a/src/previewrenderer.cpp
+++ b/src/previewrenderer.cpp
@@ -112,24 +112,6 @@ PhotoboothPreviewRender::PhotoboothPreviewRender(QQuickItem* parent)
PhotoboothPreviewRender::~PhotoboothPreviewRender() {}
-QImage
-PhotoboothPreviewRender::takePhoto()
-{
- if (auto previewImage = LRCInstance::renderer()->getPreviewFrame()) {
- return previewImage->copy();
- }
- return QImage();
-}
-
-QString
-PhotoboothPreviewRender::takeCroppedPhotoToBase64(int size)
-{
- auto image = Utils::cropImage(takePhoto());
- auto avatar = image.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
-
- return QString::fromLatin1(Utils::QImageToByteArray(avatar).toBase64().data());
-}
-
void
PhotoboothPreviewRender::paint(QPainter* painter)
{
diff --git a/src/previewrenderer.h b/src/previewrenderer.h
index 6a2a6686..55249b12 100644
--- a/src/previewrenderer.h
+++ b/src/previewrenderer.h
@@ -63,9 +63,6 @@ public:
explicit PhotoboothPreviewRender(QQuickItem* parent = 0);
virtual ~PhotoboothPreviewRender();
- QImage takePhoto();
- Q_INVOKABLE QString takeCroppedPhotoToBase64(int size);
-
signals:
void hideBooth();
diff --git a/src/settingsadapter.cpp b/src/settingsadapter.cpp
index 8b6213ac..a704512f 100644
--- a/src/settingsadapter.cpp
+++ b/src/settingsadapter.cpp
@@ -263,15 +263,6 @@ SettingsAdapter::getAccountBestName()
return Utils::bestNameForAccount(LRCInstance::getCurrentAccountInfo());
}
-QString
-SettingsAdapter::getAvatarImage_Base64(int avatarSize)
-{
- auto& accountInfo = LRCInstance::getCurrentAccountInfo();
- auto avatar = Utils::accountPhoto(accountInfo, {avatarSize, avatarSize});
-
- return QString::fromLatin1(Utils::QImageToByteArray(avatar).toBase64().data());
-}
-
bool
SettingsAdapter::getIsDefaultAvatar()
{
@@ -280,18 +271,10 @@ SettingsAdapter::getIsDefaultAvatar()
return accountInfo.profileInfo.avatar.isEmpty();
}
-bool
-SettingsAdapter::setCurrAccAvatar(QString avatarImgBase64)
+void
+SettingsAdapter::setCurrAccAvatar(QVariant avatarImg)
{
- QImage avatarImg;
- const bool ret = avatarImg.loadFromData(QByteArray::fromBase64(avatarImgBase64.toLatin1()));
- if (!ret) {
- qDebug() << "Current avatar loading from base64 fail";
- return false;
- } else {
- LRCInstance::setCurrAccAvatar(QPixmap::fromImage(avatarImg));
- }
- return true;
+ LRCInstance::setCurrAccAvatar(QPixmap::fromImage(avatarImg.value()));
}
void
diff --git a/src/settingsadapter.h b/src/settingsadapter.h
index 78a5164f..db621f59 100644
--- a/src/settingsadapter.h
+++ b/src/settingsadapter.h
@@ -94,9 +94,8 @@ public:
Q_INVOKABLE QString getAccountBestName();
// getters and setters of avatar image
- Q_INVOKABLE QString getAvatarImage_Base64(int avatarSize);
Q_INVOKABLE bool getIsDefaultAvatar();
- Q_INVOKABLE bool setCurrAccAvatar(QString avatarImgBase64);
+ Q_INVOKABLE void setCurrAccAvatar(QVariant avatarImg);
Q_INVOKABLE void clearCurrentAvatar();
/*
diff --git a/src/settingsview/components/AccountProfile.qml b/src/settingsview/components/AccountProfile.qml
index 0f896370..41a8719e 100644
--- a/src/settingsview/components/AccountProfile.qml
+++ b/src/settingsview/components/AccountProfile.qml
@@ -52,7 +52,7 @@ ColumnLayout {
}
function setAvatar() {
- currentAccountAvatar.setAvatarPixmap(SettingsAdapter.getAvatarImage_Base64(currentAccountAvatar.boothWidth), SettingsAdapter.getIsDefaultAvatar())
+ currentAccountAvatar.setAvatarImage()
}
function stopBooth() {
@@ -79,14 +79,8 @@ ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
+ saveToConfig: true
boothWidth: 180
-
- onImageAcquired: SettingsAdapter.setCurrAccAvatar(imgBase64)
-
- onImageCleared: {
- SettingsAdapter.clearCurrentAvatar()
- setAvatar()
- }
}
MaterialLineEdit {
diff --git a/src/settingsview/components/BannedContacts.qml b/src/settingsview/components/BannedContacts.qml
index 6bce03f1..f40592f6 100644
--- a/src/settingsview/components/BannedContacts.qml
+++ b/src/settingsview/components/BannedContacts.qml
@@ -137,7 +137,6 @@ ColumnLayout {
contactName : ContactName
contactID: ContactID
- contactPicture_base64: ContactPicture
onClicked: bannedListWidget.currentIndex = index
diff --git a/src/settingsview/components/BannedItemDelegate.qml b/src/settingsview/components/BannedItemDelegate.qml
index ca93d18f..e20dc921 100644
--- a/src/settingsview/components/BannedItemDelegate.qml
+++ b/src/settingsview/components/BannedItemDelegate.qml
@@ -31,12 +31,13 @@ ItemDelegate {
property string contactName : ""
property string contactID: ""
- property string contactPicture_base64:""
signal btnReAddContactClicked
highlighted: ListView.isCurrentItem
+ onContactIDChanged: avatarImg.updateImage(contactID)
+
RowLayout {
anchors.fill: parent
@@ -52,11 +53,14 @@ ItemDelegate {
background: Rectangle {
anchors.fill: parent
color: "transparent"
- Image {
+ AvatarImage {
id: avatarImg
anchors.fill: parent
- source: contactPicture_base64 === "" ? "" : "data:image/png;base64," + contactPicture_base64
+
+ mode: AvatarImage.Mode.FromContactUri
+ showPresenceIndicator: false
+
fillMode: Image.PreserveAspectCrop
layer.enabled: true
layer.effect: OpacityMask {
diff --git a/src/smartlistmodel.cpp b/src/smartlistmodel.cpp
index 3fd0b47f..439a6c1f 100644
--- a/src/smartlistmodel.cpp
+++ b/src/smartlistmodel.cpp
@@ -21,12 +21,8 @@
#include "smartlistmodel.h"
#include "lrcinstance.h"
-#include "pixbufmanipulator.h"
#include "utils.h"
-#include "api/contactmodel.h"
-#include "globalinstances.h"
-
#include
SmartListModel::SmartListModel(QObject* parent,
@@ -148,7 +144,6 @@ SmartListModel::roleNames() const
QHash roles;
roles[DisplayName] = "DisplayName";
roles[DisplayID] = "DisplayID";
- roles[Picture] = "Picture";
roles[Presence] = "Presence";
roles[URI] = "URI";
roles[UnreadMessagesCount] = "UnreadMessagesCount";
@@ -163,6 +158,7 @@ SmartListModel::roleNames() const
roles[SectionName] = "SectionName";
roles[AccountId] = "AccountId";
roles[Draft] = "Draft";
+ roles[PictureUid] = "PictureUid";
return roles;
}
@@ -183,6 +179,8 @@ void
SmartListModel::fillConversationsList()
{
beginResetModel();
+ fillContactAvatarUidMap(LRCInstance::getCurrentAccountInfo().contactModel->getAllContacts());
+
auto* convModel = LRCInstance::getCurrentConversationModel();
conversations_.clear();
@@ -208,6 +206,39 @@ SmartListModel::updateConversation(const QString& convUid)
}
}
+void
+SmartListModel::updateContactAvatarUid(const QString& contactUri)
+{
+ contactAvatarUidMap_[contactUri] = Utils::generateUid();
+}
+
+void
+SmartListModel::fillContactAvatarUidMap(const ContactModel::ContactInfoMap& contacts)
+{
+ if (contacts.size() == 0) {
+ contactAvatarUidMap_.clear();
+ return;
+ }
+
+ if (contactAvatarUidMap_.isEmpty() || contacts.size() != contactAvatarUidMap_.size()) {
+ bool useContacts = contacts.size() > contactAvatarUidMap_.size();
+ auto contactsKeyList = contacts.keys();
+ auto contactAvatarUidMapKeyList = contactAvatarUidMap_.keys();
+
+ for (int i = 0;
+ i < (useContacts ? contactsKeyList.size() : contactAvatarUidMapKeyList.size());
+ ++i) {
+ // Insert or update
+ if (i < contactsKeyList.size() && !contactAvatarUidMap_.contains(contactsKeyList.at(i)))
+ contactAvatarUidMap_.insert(contactsKeyList.at(i), Utils::generateUid());
+ // Remove
+ if (i < contactAvatarUidMapKeyList.size()
+ && !contacts.contains(contactAvatarUidMapKeyList.at(i)))
+ contactAvatarUidMap_.remove(contactAvatarUidMapKeyList.at(i));
+ }
+ }
+}
+
void
SmartListModel::toggleSection(const QString& section)
{
@@ -241,12 +272,10 @@ SmartListModel::getConversationItemData(const conversation::Info& item,
return QVariant();
}
auto& contactModel = accountInfo.contactModel;
+
+ // Since we are using image provider right now, image url representation should be unique to
+ // be able to use the image cache, account avatar will only be updated once PictureUid changed
switch (role) {
- case Role::Picture: {
- auto contactImage
- = GlobalInstances::pixmapManipulator().decorationRole(item, accountInfo).value();
- return QString::fromLatin1(Utils::QImageToByteArray(contactImage).toBase64().data());
- }
case Role::DisplayName: {
if (!item.participants.isEmpty()) {
auto& contact = contactModel->getContact(item.participants[0]);
@@ -268,10 +297,15 @@ SmartListModel::getConversationItemData(const conversation::Info& item,
}
return QVariant(false);
}
+ case Role::PictureUid: {
+ if (!item.participants.isEmpty()) {
+ return QVariant(contactAvatarUidMap_[item.participants[0]]);
+ }
+ return QVariant("");
+ }
case Role::URI: {
if (!item.participants.isEmpty()) {
- auto& contact = contactModel->getContact(item.participants[0]);
- return QVariant(contact.profileInfo.uri);
+ return QVariant(item.participants[0]);
}
return QVariant("");
}
@@ -331,13 +365,13 @@ SmartListModel::getConversationItemData(const conversation::Info& item,
if (!convInfo.uid.isEmpty()) {
auto* callModel = LRCInstance::getCurrentCallModel();
const auto call = callModel->getCall(convInfo.callId);
- return QVariant(callModel->hasCall(convInfo.callId)
- && ((!call.isOutgoing
- && (call.status == lrc::api::call::Status::IN_PROGRESS
- || call.status == lrc::api::call::Status::PAUSED
- || call.status == lrc::api::call::Status::INCOMING_RINGING))
- || (call.isOutgoing
- && call.status != lrc::api::call::Status::ENDED)));
+ return QVariant(
+ callModel->hasCall(convInfo.callId)
+ && ((!call.isOutgoing
+ && (call.status == lrc::api::call::Status::IN_PROGRESS
+ || call.status == lrc::api::call::Status::PAUSED
+ || call.status == lrc::api::call::Status::INCOMING_RINGING))
+ || (call.isOutgoing && call.status != lrc::api::call::Status::ENDED)));
}
return QVariant(false);
}
diff --git a/src/smartlistmodel.h b/src/smartlistmodel.h
index 9bb56900..ccf7a0fe 100644
--- a/src/smartlistmodel.h
+++ b/src/smartlistmodel.h
@@ -24,6 +24,7 @@
#include "api/contact.h"
#include "api/conversation.h"
#include "api/conversationmodel.h"
+#include "api/contactmodel.h"
#include
@@ -42,7 +43,6 @@ public:
enum Role {
DisplayName = Qt::UserRole + 1,
DisplayID,
- Picture,
Presence,
URI,
UnreadMessagesCount,
@@ -58,6 +58,7 @@ public:
CallState,
SectionName,
AccountId,
+ PictureUid,
Draft
};
Q_ENUM(Role)
@@ -85,15 +86,28 @@ public:
Q_INVOKABLE void fillConversationsList();
Q_INVOKABLE void updateConversation(const QString& conv);
+ /*
+ * This function is to update contact avatar uuid for current account when there's an contact
+ * avatar changed.
+ */
+ Q_INVOKABLE void updateContactAvatarUid(const QString& contactUri);
+
private:
QVariant getConversationItemData(const ConversationInfo& item,
const AccountInfo& accountInfo,
int role) const;
+
+ /*
+ * Give a uuid for each contact avatar for current account and it will serve PictureUid role
+ */
+ void fillContactAvatarUidMap(const ContactModel::ContactInfoMap& contacts);
+
/*
* List sectioning.
*/
Type listModelType_;
QMap sectionState_;
QMap conferenceables_;
+ QMap contactAvatarUidMap_;
ConversationModel::ConversationQueue conversations_;
};
diff --git a/src/utils.cpp b/src/utils.cpp
index b215d236..b2d06641 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -25,9 +25,7 @@
#include "globalsystemtray.h"
#include "jamiavatartheme.h"
#include "lrcinstance.h"
-#include "pixbufmanipulator.h"
-#include
#include
#include
@@ -43,6 +41,7 @@
#include
#include
#include
+#include
#ifdef Q_OS_WIN
#include
@@ -245,14 +244,52 @@ Utils::GetISODate()
#endif
}
-QString
-Utils::getContactImageString(const QString& accountId, const QString& uid)
+QImage
+Utils::contactPhoto(const QString& contactUri, const QSize& size)
{
- return QString::fromLatin1(
- Utils::QImageToByteArray(
- Utils::conversationPhoto(uid, LRCInstance::getAccountInfo(accountId)))
- .toBase64()
- .data());
+ QImage photo;
+
+ try {
+ /*
+ * Get first contact photo.
+ */
+ auto& accountInfo = LRCInstance::accountModel().getAccountInfo(LRCInstance::getCurrAccId());
+ auto contactInfo = accountInfo.contactModel->getContact(contactUri);
+ auto contactPhoto = contactInfo.profileInfo.avatar;
+ auto bestName = Utils::bestNameForContact(contactInfo);
+ auto bestId = Utils::bestIdForContact(contactInfo);
+ if (accountInfo.profileInfo.type == lrc::api::profile::Type::SIP
+ && contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY) {
+ photo = Utils::fallbackAvatar(QString(), QString());
+ } else if (contactInfo.profileInfo.type == lrc::api::profile::Type::TEMPORARY
+ && contactInfo.profileInfo.uri.isEmpty()) {
+ photo = Utils::fallbackAvatar(QString(), QString());
+ } else if (!contactPhoto.isEmpty()) {
+ QByteArray byteArray = contactPhoto.toLocal8Bit();
+ photo = contactPhotoFromBase64(byteArray, nullptr);
+ if (photo.isNull()) {
+ auto avatarName = contactInfo.profileInfo.uri == bestName ? QString() : bestName;
+ photo = Utils::fallbackAvatar("ring:" + contactInfo.profileInfo.uri, avatarName);
+ }
+ } else {
+ auto avatarName = contactInfo.profileInfo.uri == bestName ? QString() : bestName;
+ photo = Utils::fallbackAvatar("ring:" + contactInfo.profileInfo.uri, avatarName);
+ }
+ } catch (...) {
+ }
+ return Utils::scaleAndFrame(photo, size);
+}
+
+QImage
+Utils::contactPhotoFromBase64(const QByteArray& data, const QString& type)
+{
+ QImage avatar;
+ const bool ret = avatar.loadFromData(QByteArray::fromBase64(data), type.toLatin1());
+ if (!ret) {
+ qDebug() << "Utils: vCard image loading failed";
+ return QImage();
+ }
+ return Utils::getCirclePhoto(avatar, avatar.size().width());
}
QImage
@@ -549,21 +586,6 @@ Utils::getReplyMessageBox(QWidget* widget, const QString& title, const QString&
return false;
}
-QImage
-Utils::conversationPhoto(const QString& convUid,
- const lrc::api::account::Info& accountInfo,
- bool filtered)
-{
- auto* convModel = LRCInstance::getCurrentConversationModel();
- const auto convInfo = convModel->getConversationForUID(convUid);
- if (!convInfo.uid.isEmpty()) {
- return GlobalInstances::pixmapManipulator()
- .decorationRole(convInfo, accountInfo)
- .value();
- }
- return QImage();
-}
-
QColor
Utils::getAvatarColor(const QString& canonicalUri)
{
@@ -587,10 +609,12 @@ Utils::getAvatarColor(const QString& canonicalUri)
QImage
Utils::fallbackAvatar(const QString& canonicalUriStr, const QString& letterStr, const QSize& size)
{
+ auto sizeToUse = size.height() >= defaultAvatarSize.height() ? size : defaultAvatarSize;
+
/*
* We start with a transparent avatar.
*/
- QImage avatar(size, QImage::Format_ARGB32);
+ QImage avatar(sizeToUse, QImage::Format_ARGB32);
avatar.fill(Qt::transparent);
/*
@@ -651,7 +675,7 @@ Utils::fallbackAvatar(const QString& canonicalUriStr, const QString& letterStr,
painter.drawPixmap(overlayRect, QPixmap(":/images/default_avatar_overlay.svg"));
}
- return avatar;
+ return avatar.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
QImage
@@ -802,7 +826,7 @@ Utils::accountPhoto(const lrc::api::account::Info& accountInfo, const QSize& siz
QImage photo;
if (!accountInfo.profileInfo.avatar.isEmpty()) {
QByteArray ba = accountInfo.profileInfo.avatar.toLocal8Bit();
- photo = GlobalInstances::pixmapManipulator().personPhoto(ba, nullptr).value();
+ photo = contactPhotoFromBase64(ba, nullptr);
} else {
auto bestId = bestIdForAccount(accountInfo);
auto bestName = bestNameForAccount(accountInfo);
@@ -843,3 +867,9 @@ Utils::isImage(const QString& fileExt)
return true;
return false;
}
+
+QString
+Utils::generateUid()
+{
+ return QUuid::createUuid().toString();
+}
diff --git a/src/utils.h b/src/utils.h
index ccecb875..2e74d031 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -100,11 +100,9 @@ bool getReplyMessageBox(QWidget* widget, const QString& title, const QString& te
* Image manipulation
*/
static const QSize defaultAvatarSize {128, 128};
-QString getContactImageString(const QString& accountId, const QString& uid);
+QImage contactPhotoFromBase64(const QByteArray& data, const QString& type);
+QImage contactPhoto(const QString& contactUri, const QSize& size = defaultAvatarSize);
QImage getCirclePhoto(const QImage original, int sizePhoto);
-QImage conversationPhoto(const QString& convUid,
- const lrc::api::account::Info& accountInfo,
- bool filtered = false);
QColor getAvatarColor(const QString& canonicalUri);
QImage fallbackAvatar(const QString& canonicalUriStr,
const QString& letterStr = QString(),
@@ -123,6 +121,7 @@ QImage cropImage(const QImage& img);
QPixmap pixmapFromSvg(const QString& svg_resource, const QSize& size);
QImage setupQRCode(QString ringID, int margin);
bool isImage(const QString& fileExt);
+QString generateUid();
/*
* Misc
diff --git a/src/utilsadapter.cpp b/src/utilsadapter.cpp
index d69d7049..137d4dd5 100644
--- a/src/utilsadapter.cpp
+++ b/src/utilsadapter.cpp
@@ -105,12 +105,6 @@ UtilsAdapter::checkStartupLink()
return Utils::CheckStartupLink(L"Jami");
}
-const QString
-UtilsAdapter::getContactImageString(const QString& accountId, const QString& uid)
-{
- return Utils::getContactImageString(accountId, uid);
-}
-
const QString
UtilsAdapter::getBestName(const QString& accountId, const QString& uid)
{
@@ -356,17 +350,6 @@ UtilsAdapter::getAbsPath(QString path)
#endif
}
-QString
-UtilsAdapter::getCroppedImageBase64FromFile(QString fileName, int size)
-{
- auto image = Utils::cropImage(QImage(fileName));
- auto croppedImage = image.scaled(size,
- size,
- Qt::KeepAspectRatioByExpanding,
- Qt::SmoothTransformation);
- return QString::fromLatin1(Utils::QImageToByteArray(croppedImage).toBase64().data());
-}
-
bool
UtilsAdapter::checkShowPluginsButton()
{
diff --git a/src/utilsadapter.h b/src/utilsadapter.h
index 9a30e12c..36e0658c 100644
--- a/src/utilsadapter.h
+++ b/src/utilsadapter.h
@@ -44,7 +44,6 @@ public:
Q_INVOKABLE bool createStartupLink();
Q_INVOKABLE QString GetRingtonePath();
Q_INVOKABLE bool checkStartupLink();
- Q_INVOKABLE const QString getContactImageString(const QString& accountId, const QString& uid);
Q_INVOKABLE void removeConversation(const QString& accountId,
const QString& uid,
bool banContact = false);
@@ -77,7 +76,6 @@ public:
Q_INVOKABLE QString toFileInfoName(QString inputFileName);
Q_INVOKABLE QString toFileAbsolutepath(QString inputFileName);
Q_INVOKABLE QString getAbsPath(QString path);
- Q_INVOKABLE QString getCroppedImageBase64FromFile(QString fileName, int size);
Q_INVOKABLE bool checkShowPluginsButton();
Q_INVOKABLE QString fileName(const QString& path);
Q_INVOKABLE QString getExt(const QString& path);
diff --git a/src/wizardview/WizardView.qml b/src/wizardview/WizardView.qml
index 154b7bd3..e836c060 100644
--- a/src/wizardview/WizardView.qml
+++ b/src/wizardview/WizardView.qml
@@ -385,14 +385,13 @@ Rectangle {
}
onSaveProfile: {
- SettingsAdapter.setCurrAccAvatar(profilePage.boothImgBase64)
+ if (profilePage.profileImg)
+ SettingsAdapter.setCurrAccAvatar(profilePage.profileImg)
AccountAdapter.setCurrAccDisplayName(profilePage.displayName)
leave()
}
- onLeavePage: {
- leave()
- }
+ onLeavePage: leave()
}
}
}
diff --git a/src/wizardview/components/CreateSIPAccountPage.qml b/src/wizardview/components/CreateSIPAccountPage.qml
index 2e7f8570..f077aebf 100644
--- a/src/wizardview/components/CreateSIPAccountPage.qml
+++ b/src/wizardview/components/CreateSIPAccountPage.qml
@@ -32,8 +32,6 @@ Rectangle {
property alias text_sipPasswordEditAlias: sipPasswordEdit.text
property int preferredHeight: createSIPAccountPageColumnLayout.implicitHeight
- property var boothImgBase64: null
-
signal createAccount
signal leavePage
diff --git a/src/wizardview/components/ProfilePage.qml b/src/wizardview/components/ProfilePage.qml
index 612b4f46..adc7ac5d 100644
--- a/src/wizardview/components/ProfilePage.qml
+++ b/src/wizardview/components/ProfilePage.qml
@@ -26,11 +26,13 @@ import "../../commoncomponents"
Rectangle {
id: root
+ property alias profileImg: setAvatarWidget.boothImg
property int preferredHeight: profilePageColumnLayout.implicitHeight
function initializeOnShowUp() {
+ setAvatarWidget.hasAvatar = false
+ setAvatarWidget.setAvatarImage(AvatarImage.Mode.Default, "")
clearAllTextFields()
- boothImgBase64 = ""
saveProfileBtn.spinnerTriggered = true
}
@@ -48,7 +50,6 @@ Rectangle {
signal saveProfile
property var showBottom: false
- property alias boothImgBase64: setAvatarWidget.imgBase64
property alias displayName: aliasEdit.text
property bool isRdv: false