1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-07-08 09:35:24 +02:00

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
This commit is contained in:
Andreas Traczyk 2021-07-15 17:20:37 -04:00
parent 275530746a
commit ab4c68adb5
6 changed files with 149 additions and 128 deletions

View file

@ -26,39 +26,34 @@ import net.jami.Models 1.0
import net.jami.Adapters 1.0 import net.jami.Adapters 1.0
import net.jami.Constants 1.0 import net.jami.Constants 1.0
ColumnLayout { Item {
id: root id: root
enum Mode { Static, Previewing } property bool isPreviewing: false
property int mode: PhotoboothView.Mode.Static
property alias imageId: avatar.imageId property alias imageId: avatar.imageId
required property real avatarSize
property int size: 224 width: avatarSize
height: boothLayout.height
signal avatarSet
function startBooth() { function startBooth() {
AccountAdapter.startPreviewing(false) AccountAdapter.startPreviewing(false)
mode = PhotoboothView.Mode.Previewing isPreviewing = true
} }
function stopBooth(){ function stopBooth(){
if (!AccountAdapter.hasVideoCall()) { if (!AccountAdapter.hasVideoCall()) {
AccountAdapter.stopPreviewing() AccountAdapter.stopPreviewing()
} }
mode = PhotoboothView.Mode.Static isPreviewing = false
} }
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (!visible) {
mode = PhotoboothView.Mode.Static
} else {
stopBooth() stopBooth()
} }
} }
spacing: 0
JamiFileDialog { JamiFileDialog {
id: importFromFileDialog id: importFromFileDialog
@ -74,125 +69,139 @@ ColumnLayout {
onAccepted: { onAccepted: {
var filePath = UtilsAdapter.getAbsPath(file) var filePath = UtilsAdapter.getAbsPath(file)
AccountAdapter.setCurrentAccountAvatarFile(filePath) AccountAdapter.setCurrentAccountAvatarFile(filePath)
avatarSet()
} }
} }
Item { ColumnLayout {
id: imageLayer id: boothLayout
Layout.preferredWidth: size spacing: JamiTheme.preferredMarginSize / 2
Layout.preferredHeight: size
Layout.alignment: Qt.AlignHCenter
Avatar { Item {
id: avatar id: imageLayer
anchors.fill: parent
anchors.margins: 1
visible: !preview.visible
fillMode: Image.PreserveAspectCrop
showPresenceIndicator: false
}
PhotoboothPreviewRender {
id: preview
anchors.fill: parent
anchors.margins: 1
visible: mode === PhotoboothView.Mode.Previewing
onRenderingStopped: stopBooth()
lrcInstance: LRCInstance
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: size
height: size
radius: size / 2
}
}
}
Rectangle {
id: flashRect
anchors.fill: parent
anchors.margins: 0
radius: size / 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
Layout.preferredWidth: avatarSize
Layout.preferredHeight: avatarSize
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
radius: JamiTheme.primaryRadius
imageColor: JamiTheme.textColor Avatar {
toolTipText: JamiStrings.takePhoto id: avatar
source: mode === PhotoboothView.Mode.Static ? anchors.fill: parent
"qrc:/images/icons/baseline-camera_alt-24px.svg" : anchors.margins: 1
"qrc:/images/icons/round-add_a_photo-24px.svg"
onClicked: { visible: !preview.visible
if (mode === PhotoboothView.Mode.Previewing) {
flashAnimation.start() fillMode: Image.PreserveAspectCrop
AccountAdapter.setCurrentAccountAvatarBase64( showPresenceIndicator: false
preview.takePhoto(size)) }
avatarSet()
PhotoboothPreviewRender {
id: preview
anchors.fill: parent
anchors.margins: 1
visible: isPreviewing
onRenderingStopped: stopBooth()
lrcInstance: LRCInstance
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: avatarSize
height: avatarSize
radius: avatarSize / 2
}
}
}
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: childrenRect.height
Layout.bottomMargin: parent.spacing
Layout.alignment: Qt.AlignHCenter
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
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: {
stopBooth() stopBooth()
return AccountAdapter.setCurrentAccountAvatarBase64()
} }
startBooth()
} }
}
PushButton { PushButton {
id: importButton id: importButton
Layout.preferredWidth: JamiTheme.preferredFieldHeight Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: JamiTheme.preferredFieldHeight radius: JamiTheme.primaryRadius
Layout.alignment: Qt.AlignHCenter source: "qrc:/images/icons/round-folder-24px.svg"
toolTipText: JamiStrings.importFromFile
imageColor: JamiTheme.textColor
radius: JamiTheme.primaryRadius onClicked: {
source: "qrc:/images/icons/round-folder-24px.svg" stopBooth()
importFromFileDialog.open()
toolTipText: JamiStrings.importFromFile }
imageColor: JamiTheme.textColor
onClicked: {
stopBooth()
importFromFileDialog.open()
} }
} }
} }

View file

@ -400,6 +400,7 @@ Item {
// PhotoBoothView // PhotoBoothView
property string chooseAvatarImage: qsTr("Choose a picture as avatar") property string chooseAvatarImage: qsTr("Choose a picture as avatar")
property string importFromFile: qsTr("Import avatar from image file") property string importFromFile: qsTr("Import avatar from image file")
property string clearAvatar: qsTr("Clear avatar image")
property string takePhoto: qsTr("Take photo") property string takePhoto: qsTr("Take photo")
// PluginSettingsPage // PluginSettingsPage

View file

@ -44,8 +44,21 @@ LRCInstance::LRCInstance(migrateCallback willMigrateCb,
accountModel().setTopAccount(currentAccountId_); accountModel().setTopAccount(currentAccountId_);
Q_EMIT accountListChanged(); Q_EMIT accountListChanged();
auto profileInfo = getCurrentAccountInfo().profileInfo;
// update type // 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 // set the current account if any

View file

@ -57,6 +57,7 @@ class LRCInstance : public QObject
QML_PROPERTY(QString, selectedConvUid) QML_PROPERTY(QString, selectedConvUid)
QML_PROPERTY(QString, currentAccountId) QML_PROPERTY(QString, currentAccountId)
QML_RO_PROPERTY(lrc::api::profile::Type, currentAccountType) QML_RO_PROPERTY(lrc::api::profile::Type, currentAccountType)
QML_PROPERTY(bool, currentAccountAvatarSet)
public: public:
explicit LRCInstance(migrateCallback willMigrateCb = {}, explicit LRCInstance(migrateCallback willMigrateCb = {},

View file

@ -66,12 +66,10 @@ ColumnLayout {
PhotoboothView { PhotoboothView {
id: currentAccountAvatar id: currentAccountAvatar
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
imageId: LRCInstance.currentAccountId imageId: LRCInstance.currentAccountId
avatarSize: 180
size: 180
} }
MaterialLineEdit { MaterialLineEdit {

View file

@ -32,11 +32,10 @@ Rectangle {
// trigger a default avatar prior to account generation // trigger a default avatar prior to account generation
property string createdAccountId: "dummy" property string createdAccountId: "dummy"
property int preferredHeight: profilePageColumnLayout.implicitHeight property int preferredHeight: profilePageColumnLayout.implicitHeight
property var showBottom: false property bool showBottom: false
property alias displayName: aliasEdit.text property alias displayName: aliasEdit.text
property bool isRdv: false property bool isRdv: false
property alias avatarBooth: setAvatarWidget property alias avatarBooth: setAvatarWidget
property bool avatarSet
signal leavePage signal leavePage
signal saveProfile signal saveProfile
@ -45,7 +44,6 @@ Rectangle {
createdAccountId = "dummy" createdAccountId = "dummy"
clearAllTextFields() clearAllTextFields()
saveProfileBtn.spinnerTriggered = true saveProfileBtn.spinnerTriggered = true
avatarSet = false
} }
function clearAllTextFields() { function clearAllTextFields() {
@ -99,13 +97,14 @@ Rectangle {
id: setAvatarWidget id: setAvatarWidget
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: size
Layout.fillHeight: true
imageId: createdAccountId imageId: createdAccountId
onAvatarSet: root.avatarSet = true avatarSize: 200
size: 200 onVisibleChanged: {
if (visible)
LRCInstance.currentAccountAvatarSet = false
}
} }
MaterialLineEdit { MaterialLineEdit {
@ -127,7 +126,7 @@ Rectangle {
fieldLayoutWidth: saveProfileBtn.width fieldLayoutWidth: saveProfileBtn.width
onTextEdited: { onTextEdited: {
if (root.avatarSet) if (LRCInstance.currentAccountAvatarSet)
return return
if (text.length === 0) { if (text.length === 0) {
lastFirstChar = "" lastFirstChar = ""