From ab4c68adb58ef9b6e66bd2d03c27e76ad7e8f05d Mon Sep 17 00:00:00 2001
From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
Date: Thu, 15 Jul 2021 17:20:37 -0400
Subject: [PATCH] avatars: add clear feature to photobooth

A property is provided to notify of changes to the content of the
current account's stored avatar. If one is stored, then a button
used to clear the avatar becomes available.

Gitlab: #473
Change-Id: I37640acaea3ca43e5abd14678d68b4eeebb3829e
---
 src/commoncomponents/PhotoboothView.qml       | 211 +++++++++---------
 src/constant/JamiStrings.qml                  |   1 +
 src/lrcinstance.cpp                           |  15 +-
 src/lrcinstance.h                             |   1 +
 .../components/AccountProfile.qml             |   4 +-
 src/wizardview/components/ProfilePage.qml     |  15 +-
 6 files changed, 134 insertions(+), 113 deletions(-)

diff --git a/src/commoncomponents/PhotoboothView.qml b/src/commoncomponents/PhotoboothView.qml
index 4269a9244..6772e9884 100644
--- a/src/commoncomponents/PhotoboothView.qml
+++ b/src/commoncomponents/PhotoboothView.qml
@@ -26,39 +26,34 @@ import net.jami.Models 1.0
 import net.jami.Adapters 1.0
 import net.jami.Constants 1.0
 
-ColumnLayout {
+Item {
     id: root
 
-    enum Mode { Static, Previewing }
-    property int mode: PhotoboothView.Mode.Static
+    property bool isPreviewing: false
     property alias imageId: avatar.imageId
+    required property real avatarSize
 
-    property int size: 224
-
-    signal avatarSet
+    width: avatarSize
+    height: boothLayout.height
 
     function startBooth() {
         AccountAdapter.startPreviewing(false)
-        mode = PhotoboothView.Mode.Previewing
+        isPreviewing = true
     }
 
     function stopBooth(){
         if (!AccountAdapter.hasVideoCall()) {
             AccountAdapter.stopPreviewing()
         }
-        mode = PhotoboothView.Mode.Static
+        isPreviewing = false
     }
 
     onVisibleChanged: {
-        if (visible) {
-            mode = PhotoboothView.Mode.Static
-        } else {
+        if (!visible) {
             stopBooth()
         }
     }
 
-    spacing: 0
-
     JamiFileDialog {
         id: importFromFileDialog
 
@@ -74,125 +69,139 @@ ColumnLayout {
         onAccepted: {
             var filePath = UtilsAdapter.getAbsPath(file)
             AccountAdapter.setCurrentAccountAvatarFile(filePath)
-            avatarSet()
         }
     }
 
-    Item {
-        id: imageLayer
-
-        Layout.preferredWidth: size
-        Layout.preferredHeight: size
-        Layout.alignment: Qt.AlignHCenter
-
-        Avatar {
-            id: avatar
+    ColumnLayout {
+        id: boothLayout
 
-            anchors.fill: parent
-            anchors.margins: 1
+        spacing: JamiTheme.preferredMarginSize / 2
 
-            visible: !preview.visible
+        Item {
+            id: imageLayer
 
-            fillMode: Image.PreserveAspectCrop
-            showPresenceIndicator: false
-        }
-
-        PhotoboothPreviewRender {
-            id: preview
+            Layout.preferredWidth: avatarSize
+            Layout.preferredHeight: avatarSize
+            Layout.alignment: Qt.AlignHCenter
 
-            anchors.fill: parent
-            anchors.margins: 1
+            Avatar {
+                id: avatar
 
-            visible: mode === PhotoboothView.Mode.Previewing
+                anchors.fill: parent
+                anchors.margins: 1
 
-            onRenderingStopped: stopBooth()
-            lrcInstance: LRCInstance
+                visible: !preview.visible
 
-            layer.enabled: true
-            layer.effect: OpacityMask {
-                maskSource: Rectangle {
-                    width: size
-                    height: size
-                    radius: size / 2
-                }
+                fillMode: Image.PreserveAspectCrop
+                showPresenceIndicator: false
             }
-        }
 
-        Rectangle {
-            id: flashRect
+            PhotoboothPreviewRender {
+                id: preview
+
+                anchors.fill: parent
+                anchors.margins: 1
 
-            anchors.fill: parent
-            anchors.margins: 0
-            radius: size / 2
-            color: "white"
-            opacity: 0
+                visible: isPreviewing
 
-            SequentialAnimation {
-                id: flashAnimation
+                onRenderingStopped: stopBooth()
+                lrcInstance: LRCInstance
 
-                NumberAnimation {
-                    target: flashRect; property: "opacity"
-                    to: 1; duration: 0
+                layer.enabled: true
+                layer.effect: OpacityMask {
+                    maskSource: Rectangle {
+                        width: avatarSize
+                        height: avatarSize
+                        radius: avatarSize / 2
+                    }
                 }
-                NumberAnimation {
-                    target: flashRect; property: "opacity"
-                    to: 0; duration: 500
+            }
+
+            Rectangle {
+                id: flashRect
+
+                anchors.fill: parent
+                anchors.margins: 0
+                radius: avatarSize / 2
+                color: "white"
+                opacity: 0
+
+                SequentialAnimation {
+                    id: flashAnimation
+
+                    NumberAnimation {
+                        target: flashRect; property: "opacity"
+                        to: 1; duration: 0
+                    }
+                    NumberAnimation {
+                        target: flashRect; property: "opacity"
+                        to: 0; duration: 500
+                    }
                 }
             }
         }
-    }
 
-    RowLayout {
-        id: buttonsRowLayout
-
-        Layout.fillWidth: true
-        Layout.preferredHeight: JamiTheme.preferredFieldHeight
-        Layout.topMargin: JamiTheme.preferredMarginSize / 2
-        Layout.alignment: Qt.AlignHCenter
-
-        PushButton {
-            id: takePhotoButton
+        RowLayout {
+            id: buttonsRowLayout
 
+            Layout.fillWidth: true
+            Layout.preferredHeight: childrenRect.height
+            Layout.bottomMargin: parent.spacing
             Layout.alignment: Qt.AlignHCenter
-            radius: JamiTheme.primaryRadius
 
-            imageColor: JamiTheme.textColor
-            toolTipText: JamiStrings.takePhoto
+            PushButton {
+                id: takePhotoButton
+
+                Layout.alignment: Qt.AlignHCenter
+                radius: JamiTheme.primaryRadius
+                imageColor: JamiTheme.textColor
+                toolTipText: JamiStrings.takePhoto
+                source: isPreviewing ?
+                            "qrc:/images/icons/round-add_a_photo-24px.svg" :
+                            "qrc:/images/icons/baseline-camera_alt-24px.svg"
+
+                onClicked: {
+                    if (isPreviewing) {
+                        flashAnimation.start()
+                        AccountAdapter.setCurrentAccountAvatarBase64(
+                                    preview.takePhoto(avatarSize))
+                        stopBooth()
+                        return
+                    }
+
+                    startBooth()
+                }
+            }
+
+            PushButton {
+                id: clearButton
 
-            source: mode === PhotoboothView.Mode.Static ?
-                        "qrc:/images/icons/baseline-camera_alt-24px.svg" :
-                        "qrc:/images/icons/round-add_a_photo-24px.svg"
+                visible: LRCInstance.currentAccountAvatarSet
+                Layout.alignment: Qt.AlignHCenter
+                radius: JamiTheme.primaryRadius
+                source: "qrc:/images/icons/round-close-24px.svg"
+                toolTipText: JamiStrings.clearAvatar
+                imageColor: JamiTheme.textColor
 
-            onClicked: {
-                if (mode === PhotoboothView.Mode.Previewing) {
-                    flashAnimation.start()
-                    AccountAdapter.setCurrentAccountAvatarBase64(
-                                preview.takePhoto(size))
-                    avatarSet()
+                onClicked: {
                     stopBooth()
-                    return
+                    AccountAdapter.setCurrentAccountAvatarBase64()
                 }
-
-                startBooth()
             }
-        }
-
-        PushButton {
-            id: importButton
-
-            Layout.preferredWidth: JamiTheme.preferredFieldHeight
-            Layout.preferredHeight: JamiTheme.preferredFieldHeight
-            Layout.alignment: Qt.AlignHCenter
 
-            radius: JamiTheme.primaryRadius
-            source: "qrc:/images/icons/round-folder-24px.svg"
+            PushButton {
+                id: importButton
 
-            toolTipText: JamiStrings.importFromFile
-            imageColor: JamiTheme.textColor
+                Layout.alignment: Qt.AlignHCenter
+                radius: JamiTheme.primaryRadius
+                source: "qrc:/images/icons/round-folder-24px.svg"
+                toolTipText: JamiStrings.importFromFile
+                imageColor: JamiTheme.textColor
 
-            onClicked: {
-                stopBooth()
-                importFromFileDialog.open()
+                onClicked: {
+                    stopBooth()
+                    importFromFileDialog.open()
+                }
             }
         }
     }
diff --git a/src/constant/JamiStrings.qml b/src/constant/JamiStrings.qml
index 333c60200..8f905f357 100644
--- a/src/constant/JamiStrings.qml
+++ b/src/constant/JamiStrings.qml
@@ -400,6 +400,7 @@ Item {
     // PhotoBoothView
     property string chooseAvatarImage: qsTr("Choose a picture as avatar")
     property string importFromFile: qsTr("Import avatar from image file")
+    property string clearAvatar: qsTr("Clear avatar image")
     property string takePhoto: qsTr("Take photo")
 
     // PluginSettingsPage
diff --git a/src/lrcinstance.cpp b/src/lrcinstance.cpp
index 028ce40a0..9380a2375 100644
--- a/src/lrcinstance.cpp
+++ b/src/lrcinstance.cpp
@@ -44,8 +44,21 @@ LRCInstance::LRCInstance(migrateCallback willMigrateCb,
         accountModel().setTopAccount(currentAccountId_);
         Q_EMIT accountListChanged();
 
+        auto profileInfo = getCurrentAccountInfo().profileInfo;
+
         // update type
-        set_currentAccountType(getCurrentAccountInfo().profileInfo.type);
+        set_currentAccountType(profileInfo.type);
+
+        // notify if the avatar is stored locally
+        set_currentAccountAvatarSet(!profileInfo.avatar.isEmpty());
+    });
+
+    connect(&accountModel(), &NewAccountModel::profileUpdated, [this](const QString& id) {
+        if (id != currentAccountId_)
+            return;
+
+        auto profileInfo = getCurrentAccountInfo().profileInfo;
+        set_currentAccountAvatarSet(!getCurrentAccountInfo().profileInfo.avatar.isEmpty());
     });
 
     // set the current account if any
diff --git a/src/lrcinstance.h b/src/lrcinstance.h
index b4e1b2f78..2182600c5 100644
--- a/src/lrcinstance.h
+++ b/src/lrcinstance.h
@@ -57,6 +57,7 @@ class LRCInstance : public QObject
     QML_PROPERTY(QString, selectedConvUid)
     QML_PROPERTY(QString, currentAccountId)
     QML_RO_PROPERTY(lrc::api::profile::Type, currentAccountType)
+    QML_PROPERTY(bool, currentAccountAvatarSet)
 
 public:
     explicit LRCInstance(migrateCallback willMigrateCb = {},
diff --git a/src/settingsview/components/AccountProfile.qml b/src/settingsview/components/AccountProfile.qml
index 229904276..8f3d0a15e 100644
--- a/src/settingsview/components/AccountProfile.qml
+++ b/src/settingsview/components/AccountProfile.qml
@@ -66,12 +66,10 @@ ColumnLayout {
     PhotoboothView {
         id: currentAccountAvatar
 
-        Layout.fillWidth: true
         Layout.alignment: Qt.AlignCenter
 
         imageId: LRCInstance.currentAccountId
-
-        size: 180
+        avatarSize: 180
     }
 
     MaterialLineEdit {
diff --git a/src/wizardview/components/ProfilePage.qml b/src/wizardview/components/ProfilePage.qml
index 13dd1b48f..a92c16f83 100644
--- a/src/wizardview/components/ProfilePage.qml
+++ b/src/wizardview/components/ProfilePage.qml
@@ -32,11 +32,10 @@ Rectangle {
     // trigger a default avatar prior to account generation
     property string createdAccountId: "dummy"
     property int preferredHeight: profilePageColumnLayout.implicitHeight
-    property var showBottom: false
+    property bool showBottom: false
     property alias displayName: aliasEdit.text
     property bool isRdv: false
     property alias avatarBooth: setAvatarWidget
-    property bool avatarSet
 
     signal leavePage
     signal saveProfile
@@ -45,7 +44,6 @@ Rectangle {
         createdAccountId = "dummy"
         clearAllTextFields()
         saveProfileBtn.spinnerTriggered = true
-        avatarSet = false
     }
 
     function clearAllTextFields() {
@@ -99,13 +97,14 @@ Rectangle {
             id: setAvatarWidget
 
             Layout.alignment: Qt.AlignCenter
-            Layout.preferredWidth: size
-            Layout.fillHeight: true
 
             imageId: createdAccountId
-            onAvatarSet: root.avatarSet = true
+            avatarSize: 200
 
-            size: 200
+            onVisibleChanged: {
+                if (visible)
+                    LRCInstance.currentAccountAvatarSet = false
+            }
         }
 
         MaterialLineEdit {
@@ -127,7 +126,7 @@ Rectangle {
             fieldLayoutWidth: saveProfileBtn.width
 
             onTextEdited: {
-                if (root.avatarSet)
+                if (LRCInstance.currentAccountAvatarSet)
                     return
                 if (text.length === 0) {
                     lastFirstChar = ""
-- 
GitLab