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