From 3debb0974030143216ec3a54523076fe774abe2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Mon, 28 Mar 2022 09:54:32 -0400
Subject: [PATCH] video-split: follow up patch

+ Finish layout fixing
+ Clean warning
+ protect elements
+ update copyrights

GitLab: #476
Change-Id: Ib3270b5d37d63aa99a576d48574b62801df37258
---
 src/callparticipantsmodel.cpp                 |  27 ++-
 src/callparticipantsmodel.h                   |   3 +-
 .../ContactMessageDelegate.qml                |   8 +-
 src/commoncomponents/EditableLineEdit.qml     |   2 +-
 src/currentconversation.cpp                   |   9 +-
 src/mainapplication.cpp                       |   2 +-
 src/mainview/components/AccountComboBox.qml   |   3 +-
 src/mainview/components/AddMemberPanel.qml    |   4 +-
 src/mainview/components/CallActionBar.qml     |   4 +-
 src/mainview/components/ChatView.qml          |   4 +-
 src/mainview/components/NewSwarmPage.qml      |   2 +-
 .../components/ParticipantControlLayout.qml   |   7 +
 .../components/ParticipantOverlay.qml         |   2 +-
 .../components/ParticipantOverlayMenu.qml     |   5 +-
 src/mainview/components/ParticipantsLayer.qml | 175 +++++++++---------
 src/mainview/components/SwarmDetailsPanel.qml |   6 +-
 .../SwarmParticipantContextMenu.qml           |   2 +-
 src/utils.cpp                                 |   2 +
 src/utilsadapter.cpp                          |   6 +-
 src/wizardview/components/ProfilePage.qml     |   3 +-
 20 files changed, 151 insertions(+), 125 deletions(-)

diff --git a/src/callparticipantsmodel.cpp b/src/callparticipantsmodel.cpp
index 3cf22439c..6bdd2ca06 100644
--- a/src/callparticipantsmodel.cpp
+++ b/src/callparticipantsmodel.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 by Savoir-faire Linux
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
  * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -37,6 +37,7 @@ CallParticipantsModel::rowCount(const QModelIndex& parent) const
 {
     if (parent.isValid())
         return 0;
+    // Internal call, so no need to protect participants_ as locked higher
     return participants_.size();
 }
 
@@ -47,6 +48,7 @@ CallParticipantsModel::data(const QModelIndex& index, int role) const
         return QVariant();
 
     using namespace CallParticipant;
+    // Internal call, so no need to protect participants_ as locked higher
     auto participant = participants_.at(index.row());
 
     switch (role) {
@@ -96,6 +98,7 @@ CallParticipantsModel::roleNames() const
 void
 CallParticipantsModel::addParticipant(int index, const QVariant& infos)
 {
+    std::lock_guard<std::mutex> lk(participantsMtx_);
     if (index > participants_.size())
         return;
     beginInsertRows(QModelIndex(), index, index);
@@ -111,18 +114,22 @@ CallParticipantsModel::addParticipant(int index, const QVariant& infos)
 void
 CallParticipantsModel::updateParticipant(int index, const QVariant& infos)
 {
-    if (participants_.size() <= index)
-        return;
-    auto it = participants_.begin() + index;
-    (*it) = CallParticipant::Item {infos.toJsonObject()};
-
-    callId_ = participants_[index].item["callId"].toString();
+    {
+        std::lock_guard<std::mutex> lk(participantsMtx_);
+        if (participants_.size() <= index)
+            return;
+        auto it = participants_.begin() + index;
+        (*it) = CallParticipant::Item {infos.toJsonObject()};
+
+        callId_ = participants_[index].item["callId"].toString();
+    }
     Q_EMIT dataChanged(createIndex(index, 0), createIndex(index, 0));
 }
 
 void
 CallParticipantsModel::removeParticipant(int index)
 {
+    std::lock_guard<std::mutex> lk(participantsMtx_);
     if (participants_.size() <= index)
         return;
     callId_ = participants_[index].item["callId"].toString();
@@ -140,13 +147,17 @@ CallParticipantsModel::setParticipants(const QString& callId, const QVariantList
 {
     callId_ = callId;
 
+    std::lock_guard<std::mutex> lk(participantsMtx_);
     participants_.clear();
     reset();
 
     if (!participants.isEmpty()) {
         int idx = 0;
         for (const auto& participant : participants) {
-            addParticipant(idx, participant);
+            beginInsertRows(QModelIndex(), idx, idx);
+            auto it = participants_.begin() + idx;
+            participants_.insert(it, CallParticipant::Item {participant.toJsonObject()});
+            endInsertRows();
             idx++;
         }
     }
diff --git a/src/callparticipantsmodel.h b/src/callparticipantsmodel.h
index 0273bfb19..b02d4cbc8 100644
--- a/src/callparticipantsmodel.h
+++ b/src/callparticipantsmodel.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 by Savoir-faire Linux
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
  * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -178,6 +178,7 @@ Q_SIGNALS:
 private:
     LRCInstance* lrcInstance_ {nullptr};
 
+    std::mutex participantsMtx_;
     QList<CallParticipant::Item> participants_ {};
     QString callId_;
     LayoutType layout_;
diff --git a/src/commoncomponents/ContactMessageDelegate.qml b/src/commoncomponents/ContactMessageDelegate.qml
index 8c8c07776..700dbef18 100644
--- a/src/commoncomponents/ContactMessageDelegate.qml
+++ b/src/commoncomponents/ContactMessageDelegate.qml
@@ -42,7 +42,7 @@ Column {
 
         anchors.horizontalCenter: parent.horizontalCenter
 
-        width: childrenRect.width + 12
+        width: childrenRect.width
         height: JamiTheme.contactMessageAvatarSize + 12
         radius: JamiTheme.contactMessageAvatarSize / 2 + 6
 
@@ -51,11 +51,11 @@ Column {
         border.color: CurrentConversation.isCoreDialog ? JamiTheme.messageInBgColor : CurrentConversation.color
 
         RowLayout {
-
             anchors.verticalCenter: parent.verticalCenter
-            anchors.horizontalCenter: parent.horizontalCenter
 
             Avatar {
+                Layout.leftMargin: 6
+
                 width: JamiTheme.contactMessageAvatarSize
                 height: JamiTheme.contactMessageAvatarSize
                 visible: ActionUri !== ""
@@ -66,6 +66,8 @@ Column {
             }
 
             Label {
+                Layout.rightMargin: 6
+
                 id: textLabel
                 width: parent.width
                 text: Body
diff --git a/src/commoncomponents/EditableLineEdit.qml b/src/commoncomponents/EditableLineEdit.qml
index 0473d49a5..f097fe9ad 100644
--- a/src/commoncomponents/EditableLineEdit.qml
+++ b/src/commoncomponents/EditableLineEdit.qml
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 by Savoir-faire Linux
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
  * Author: Sébastien blin <sebastien.blin@savoirfairelinux.com>
  * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
diff --git a/src/currentconversation.cpp b/src/currentconversation.cpp
index 7a07fb8af..dfa7176b8 100644
--- a/src/currentconversation.cpp
+++ b/src/currentconversation.cpp
@@ -77,15 +77,16 @@ CurrentConversation::updateData()
             // It can be used to display add contact/conversation UI and
             // is consistently determined by the peer's uri being equal to
             // the conversation id.
-            set_isTemporary(isCoreDialog_ ? convId == uris_.at(0) : false);
+            auto members = accInfo.conversationModel->peersForConversation(convId);
+            set_isTemporary(isCoreDialog_ ? convId == members.at(0) : false);
 
             auto isContact {false};
             if (isCoreDialog_)
                 try {
-                    auto& contact = accInfo.contactModel->getContact(uris_.at(0));
+                    auto& contact = accInfo.contactModel->getContact(members.at(0));
                     isContact = contact.profileInfo.type != profile::Type::TEMPORARY;
-                } catch (...) {
-                    qInfo() << "Contact not found";
+                } catch (const std::exception& e) {
+                    qInfo() << "Contact not found: " << e.what();
                 }
             set_isContact(isContact);
         }
diff --git a/src/mainapplication.cpp b/src/mainapplication.cpp
index 66318d4bf..d031de734 100644
--- a/src/mainapplication.cpp
+++ b/src/mainapplication.cpp
@@ -217,7 +217,7 @@ MainApplication::handleUriAction(const QString& arg)
     if (arg.isEmpty() && !runOptions_[Option::StartUri].isNull()) {
         uri = runOptions_[Option::StartUri].toString();
         qDebug() << "URI action invoked by run option" << uri;
-    } else {
+    } else if (!arg.isEmpty()) {
         uri = arg;
         qDebug() << "URI action invoked by secondary instance" << uri;
     }
diff --git a/src/mainview/components/AccountComboBox.qml b/src/mainview/components/AccountComboBox.qml
index 7dba72f5d..3ced41965 100644
--- a/src/mainview/components/AccountComboBox.qml
+++ b/src/mainview/components/AccountComboBox.qml
@@ -61,9 +61,8 @@ Label {
 
     background: Rectangle {
         id: background
+        anchors.fill: parent
 
-        implicitWidth: root.width
-        implicitHeight: root.height
         color: root.popup.opened ?
                    Qt.lighter(JamiTheme.hoverColor, 1.0) :
                    mouseArea.containsMouse ?
diff --git a/src/mainview/components/AddMemberPanel.qml b/src/mainview/components/AddMemberPanel.qml
index 95cb7db6f..b6bfbc86c 100644
--- a/src/mainview/components/AddMemberPanel.qml
+++ b/src/mainview/components/AddMemberPanel.qml
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 by Savoir-faire Linux
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
  * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -69,7 +69,7 @@ Rectangle {
                 enabled: visible
                 target: CurrentConversation
 
-                onUrisChanged: {
+                function onUrisChanged(uris) {
                     model = ContactAdapter.getContactSelectableModel(type)
                 }
             }
diff --git a/src/mainview/components/CallActionBar.qml b/src/mainview/components/CallActionBar.qml
index 939c8ea96..e1d9ced46 100644
--- a/src/mainview/components/CallActionBar.qml
+++ b/src/mainview/components/CallActionBar.qml
@@ -169,11 +169,11 @@ Control {
                 var muteState = CallAdapter.getMuteState(CurrentAccount.uri)
                 var modMuted = muteState === CallAdapter.MODERATOR_MUTED
                     || muteState === CallAdapter.BOTH_MUTED
-                if (isAudioMuted && modMuted) {
+                if (muteAudioAction.checked && modMuted) {
                     muteAlertActive = true
                     muteAlertMessage = JamiStrings.participantModIsStillMuted
                 }
-                CallAdapter.muteThisCallToggle(!isAudioMuted)
+                CallAdapter.muteThisCallToggle(!muteAudioAction.checked)
             }
             checkable: true
             icon.source: checked ?
diff --git a/src/mainview/components/ChatView.qml b/src/mainview/components/ChatView.qml
index c9b34bfb0..3b038bb38 100644
--- a/src/mainview/components/ChatView.qml
+++ b/src/mainview/components/ChatView.qml
@@ -86,8 +86,8 @@ Rectangle {
             Connections {
                 target: CurrentConversation
 
-                onUrisChanged: {
-                    if (CurrentConversation.uris.length >= 8 && addMemberPanel.visible) {
+                function onUrisChanged(uris) {
+                    if (uris && uris.length >= 8 && addMemberPanel.visible) {
                         swarmDetailsPanel.visible = false
                         addMemberPanel.visible = !addMemberPanel.visible
                     }
diff --git a/src/mainview/components/NewSwarmPage.qml b/src/mainview/components/NewSwarmPage.qml
index 10def09f9..e28a629cf 100644
--- a/src/mainview/components/NewSwarmPage.qml
+++ b/src/mainview/components/NewSwarmPage.qml
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 by Savoir-faire Linux
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
  * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/src/mainview/components/ParticipantControlLayout.qml b/src/mainview/components/ParticipantControlLayout.qml
index a6af75765..b80bc6c4d 100644
--- a/src/mainview/components/ParticipantControlLayout.qml
+++ b/src/mainview/components/ParticipantControlLayout.qml
@@ -32,6 +32,8 @@ RowLayout {
                                  + minimizeParticipant.visible
                                  + hangupParticipant.visible
 
+    spacing: 8
+
     ParticipantOverlayButton {
         id: toggleModerator
 
@@ -39,6 +41,7 @@ RowLayout {
         preferredSize: iconButtonPreferredSize
         Layout.preferredHeight: buttonPreferredSize
         Layout.preferredWidth: buttonPreferredSize
+        Layout.alignment: Qt.AlignVCenter
         source: JamiResources.moderator_svg
         onClicked: CallAdapter.setModerator(uri, showSetModerator)
         toolTipText: showSetModerator? JamiStrings.setModerator
@@ -52,6 +55,7 @@ RowLayout {
         preferredSize: iconButtonPreferredSize
         Layout.preferredHeight: buttonPreferredSize
         Layout.preferredWidth: buttonPreferredSize
+        Layout.alignment: Qt.AlignVCenter
         source: showModeratorMute ?
                     JamiResources.micro_black_24dp_svg :
                     JamiResources.micro_off_black_24dp_svg
@@ -83,6 +87,7 @@ RowLayout {
         preferredSize: iconButtonPreferredSize
         Layout.preferredHeight: buttonPreferredSize
         Layout.preferredWidth: buttonPreferredSize
+        Layout.alignment: Qt.AlignVCenter
         source: JamiResources.open_in_full_24dp_svg
         onClicked: CallAdapter.maximizeParticipant(uri)
         toolTipText: JamiStrings.maximizeParticipant
@@ -95,6 +100,7 @@ RowLayout {
         preferredSize: iconButtonPreferredSize
         Layout.preferredHeight: buttonPreferredSize
         Layout.preferredWidth: buttonPreferredSize
+        Layout.alignment: Qt.AlignVCenter
         source: JamiResources.close_fullscreen_24dp_svg
         onClicked: CallAdapter.minimizeParticipant(uri)
         toolTipText: JamiStrings.minimizeParticipant
@@ -107,6 +113,7 @@ RowLayout {
         preferredSize: iconButtonPreferredSize
         Layout.preferredHeight: buttonPreferredSize
         Layout.preferredWidth: buttonPreferredSize
+        Layout.alignment: Qt.AlignVCenter
         source: JamiResources.ic_hangup_participant_24dp_svg
         onClicked: CallAdapter.hangupParticipant(uri)
         toolTipText: JamiStrings.hangupParticipant
diff --git a/src/mainview/components/ParticipantOverlay.qml b/src/mainview/components/ParticipantOverlay.qml
index 012a3268b..2c7b4f720 100644
--- a/src/mainview/components/ParticipantOverlay.qml
+++ b/src/mainview/components/ParticipantOverlay.qml
@@ -93,7 +93,7 @@ Item {
         id: mediaDistRender
         anchors.fill: parent
         rendererId: root.sinkId
-        crop: true
+        crop: !participantIsActive
 
         underlayItems: Avatar {
             property real componentSize: Math.min(mediaDistRender.contentRect.width / 2, mediaDistRender.contentRect.height / 2)
diff --git a/src/mainview/components/ParticipantOverlayMenu.qml b/src/mainview/components/ParticipantOverlayMenu.qml
index 114257c8b..0b85b5906 100644
--- a/src/mainview/components/ParticipantOverlayMenu.qml
+++ b/src/mainview/components/ParticipantOverlayMenu.qml
@@ -85,7 +85,7 @@ Item {
         id: barComponent
 
         Control {
-            width: barButtons.implicitWidth
+            width: barButtons.implicitWidth + 16
             height: shapeHeight
             hoverEnabled: false
 
@@ -104,6 +104,9 @@ Item {
 
             ParticipantControlLayout {
                 id: barButtons
+                anchors.fill: parent
+                anchors.leftMargin: 8
+                anchors.rightMargin: 8
             }
         }
     }
diff --git a/src/mainview/components/ParticipantsLayer.qml b/src/mainview/components/ParticipantsLayer.qml
index 454cfaf69..31e45d862 100644
--- a/src/mainview/components/ParticipantsLayer.qml
+++ b/src/mainview/components/ParticipantsLayer.qml
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020-2022 by Savoir-faire Linux
+ * Copyright (C) 2020-2022 Savoir-faire Linux Inc.
  * Authors: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
  *          Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
  *
@@ -141,9 +141,95 @@ Item {
                         radius: JamiTheme.primaryRadius
                     }
                 }
+
                 Item {
                     Layout.fillHeight: true
                     Layout.fillWidth: true
+                    Layout.margins: 4
+
+                    // GENERIC
+                    Flow {
+                        id: commonParticipantsFlow
+                        anchors.fill: parent
+
+                        anchors.leftMargin: {
+                            if (!inLine)
+                                return 0
+                            var showed = Math.min(genericParticipantsRect.showable, columns)
+                            return Math.max(0, Math.ceil((parent.width - componentWidth * showed) / 2))
+                        }
+
+                        spacing: 4
+                        property int columns: {
+                            if (inLine)
+                                return commonParticipants.count
+                            var ratio = Math.floor(root.width / root.height)
+                            // If ratio is 2 we can have 2 times more elements on each columns
+                            var wantedCol = Math.max(1, Math.round(Math.sqrt(commonParticipants.count) * ratio))
+                            var cols =  Math.min(commonParticipants.count, wantedCol)
+                            // Optimize with the rows (eg 7 with ratio 2 should have 4 and 3 items, not 6 and 1)
+                            var rows = Math.max(1, Math.ceil(commonParticipants.count/cols))
+                            return Math.min(Math.ceil(commonParticipants.count / rows), cols)
+                        }
+                        property int rows: Math.max(1, Math.ceil(commonParticipants.count/columns))
+                        property int componentWidth: {
+                            if (inLine)
+                                return height
+                            var totalSpacing = commonParticipantsFlow.spacing * commonParticipantsFlow.columns
+                            return Math.floor((commonParticipantsFlow.width - totalSpacing)/ commonParticipantsFlow.columns)
+                        }
+
+                        Repeater {
+                            id: commonParticipants
+
+                            model: GenericParticipantsFilterModel
+                            delegate: Loader {
+                                sourceComponent: callVideoMedia
+                                active: root.visible
+                                asynchronous: true
+                                visible: {
+                                    if (status !== Loader.Ready)
+                                        return false
+                                    if (inLine)
+                                        return index >= genericParticipantsRect.currentPos
+                                                && index < genericParticipantsRect.currentPos + genericParticipantsRect.showable
+                                    return true
+                                }
+                                width: commonParticipantsFlow.componentWidth + leftMargin_
+                                height: {
+                                    if (inLine || commonParticipantsFlow.rows === 1)
+                                        return genericParticipantsRect.height
+                                    var totalSpacing = commonParticipantsFlow.spacing * commonParticipantsFlow.rows
+                                    return Math.floor((genericParticipantsRect.height - totalSpacing)/ commonParticipantsFlow.rows)
+                                }
+
+                                property int leftMargin_: {
+                                    if (inLine || commonParticipantsFlow.rows === 1)
+                                        return 0
+                                    var lastParticipants = (commonParticipants.count % commonParticipantsFlow.columns)
+                                    if (lastParticipants !== 0 && index === commonParticipants.count - lastParticipants) {
+                                        var compW = commonParticipantsFlow.componentWidth + commonParticipantsFlow.spacing
+                                        var lastLineW = lastParticipants * compW
+                                        return Math.floor((commonParticipantsFlow.width - lastLineW) / 2)
+                                    }
+                                    return 0
+                                }
+
+                                property string uri_: Uri
+                                property string bestName_: BestName
+                                property string avatar_: Avatar ? Avatar : ""
+                                property string sinkId_: SinkId ? SinkId : ""
+                                property bool isLocal_: IsLocal
+                                property bool active_: Active
+                                property bool videoMuted_: VideoMuted
+                                property bool isContact_: IsContact
+                                property bool isModerator_: IsModerator
+                                property bool audioLocalMuted_: AudioLocalMuted
+                                property bool audioModeratorMuted_: AudioModeratorMuted
+                                property bool isHandRaised_: HandRaised
+                            }
+                        }
+                    }
                 }
 
                 RoundButton {
@@ -164,93 +250,6 @@ Item {
                     }
                 }
             }
-
-            Rectangle {
-                z:0
-                anchors.fill: parent
-                color: "transparent"
-
-                // GENERIC
-                Flow {
-                    id: commonParticipantsFlow
-                    anchors.left: parent.left
-                    anchors.right: parent.right
-                    anchors.top: Math.ceil((parent.height - commonParticipants.height) / 2)
-                    anchors.leftMargin: {
-                        if (!inLine)
-                            return 0
-                        var showed = Math.min(genericParticipantsRect.showable, columns)
-                        return Math.max(0, (parent.width - componentWidth * showed) / 2)
-                    }
-
-                    spacing: 3
-                    property int columns: {
-                        if (inLine)
-                            return commonParticipants.count
-                        var ratio = Math.floor(root.width / root.height)
-                        var sqrt = Math.max(1, Math.ceil(Math.sqrt(commonParticipants.count)))
-                        var wantedCol = Math.max(1, Math.round(sqrt * ratio))
-                        return Math.min(commonParticipants.count, wantedCol)
-                    }
-                    property int rows: Math.max(1, Math.ceil(commonParticipants.count/columns))
-                    property int componentWidth: {
-                        if (inLine)
-                            return height
-                        var totalSpacing = commonParticipantsFlow.spacing * commonParticipantsFlow.columns
-                        return Math.floor((genericParticipantsRect.width - totalSpacing)/ commonParticipantsFlow.columns)
-                    }
-
-                    Repeater {
-                        id: commonParticipants
-
-                        model: GenericParticipantsFilterModel
-                        delegate: Loader {
-                            sourceComponent: callVideoMedia
-                            active: root.visible
-                            asynchronous: true
-                            visible: {
-                                if (status !== Loader.Ready)
-                                    return false
-                                if (inLine)
-                                    return index >= genericParticipantsRect.currentPos
-                                            && index < genericParticipantsRect.currentPos + genericParticipantsRect.showable
-                                return true
-                            }
-                            width: commonParticipantsFlow.componentWidth + leftMargin_
-                            height: {
-                                if (inLine || commonParticipantsFlow.rows === 1)
-                                    return genericParticipantsRect.height
-                                var totalSpacing = commonParticipantsFlow.spacing * commonParticipantsFlow.rows
-                                return Math.floor((genericParticipantsRect.height - totalSpacing)/ commonParticipantsFlow.rows)
-                            }
-
-                            property int leftMargin_: {
-                                if (inLine || commonParticipantsFlow.rows === 1)
-                                    return 0
-                                if (index === commonParticipants.count - commonParticipantsFlow.columns + 1) {
-                                    var compW = commonParticipantsFlow.componentWidth + commonParticipantsFlow.spacing
-                                    var lastLineW = (commonParticipants.count % commonParticipantsFlow.columns) * compW
-                                    return (genericParticipantsRect.width - lastLineW) / 2
-                                }
-                                return 0
-                            }
-
-                            property string uri_: Uri
-                            property string bestName_: BestName
-                            property string avatar_: Avatar ? Avatar : ""
-                            property string sinkId_: SinkId ? SinkId : ""
-                            property bool isLocal_: IsLocal
-                            property bool active_: Active
-                            property bool videoMuted_: VideoMuted
-                            property bool isContact_: IsContact
-                            property bool isModerator_: IsModerator
-                            property bool audioLocalMuted_: AudioLocalMuted
-                            property bool audioModeratorMuted_: AudioModeratorMuted
-                            property bool isHandRaised_: HandRaised
-                        }
-                    }
-                }
-            }
         }
 
         // ACTIVE
diff --git a/src/mainview/components/SwarmDetailsPanel.qml b/src/mainview/components/SwarmDetailsPanel.qml
index d32b1dfc3..5ea44f1bc 100644
--- a/src/mainview/components/SwarmDetailsPanel.qml
+++ b/src/mainview/components/SwarmDetailsPanel.qml
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 by Savoir-faire Linux
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
  * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -67,7 +67,7 @@ Rectangle {
 
                 text: CurrentConversation.title
                 placeholderText: JamiStrings.editTitle
-                placeholderTextColor: UtilsAdapter.luma(backgroundColor) ? JamiTheme.placeholderTextColorWhite : JamiTheme.placeholderTextColor
+                placeholderTextColor: UtilsAdapter.luma(root.color) ? JamiTheme.placeholderTextColorWhite : JamiTheme.placeholderTextColor
                 tooltipText: JamiStrings.editTitle
                 backgroundColor: root.color
                 color: UtilsAdapter.luma(backgroundColor) ?
@@ -93,7 +93,7 @@ Rectangle {
 
                 text: CurrentConversation.description
                 placeholderText: JamiStrings.editDescription
-                placeholderTextColor: UtilsAdapter.luma(backgroundColor) ? JamiTheme.placeholderTextColorWhite : JamiTheme.placeholderTextColor
+                placeholderTextColor: UtilsAdapter.luma(root.color) ? JamiTheme.placeholderTextColorWhite : JamiTheme.placeholderTextColor
                 tooltipText: JamiStrings.editDescription
                 backgroundColor: root.color
                 color: UtilsAdapter.luma(backgroundColor) ?
diff --git a/src/mainview/components/SwarmParticipantContextMenu.qml b/src/mainview/components/SwarmParticipantContextMenu.qml
index d162b7371..dff489e8b 100644
--- a/src/mainview/components/SwarmParticipantContextMenu.qml
+++ b/src/mainview/components/SwarmParticipantContextMenu.qml
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 by Savoir-faire Linux
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
  * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/src/utils.cpp b/src/utils.cpp
index 3720d54ac..88465ed30 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -435,6 +435,8 @@ Utils::tempConversationAvatar(const QSize& size)
 QImage
 Utils::imageFromBase64String(const QString& str, bool circleCrop)
 {
+    if (str.isEmpty())
+        return {};
     return imageFromBase64Data(Utils::base64StringToByteArray(str), circleCrop);
 }
 
diff --git a/src/utilsadapter.cpp b/src/utilsadapter.cpp
index 0eaaacb47..356e92bd9 100644
--- a/src/utilsadapter.cpp
+++ b/src/utilsadapter.cpp
@@ -511,10 +511,12 @@ void
 UtilsAdapter::setSwarmCreationImageFromImage(const QImage& image, const QString& imageId)
 {
     // Compress the image before saving
-    auto img = Utils::scaleAndFrame(image, QSize(256, 256));
     QByteArray ba;
     QBuffer bu(&ba);
-    img.save(&bu, "PNG");
+    if (!image.isNull()) {
+        auto img = Utils::scaleAndFrame(image, QSize(256, 256));
+        img.save(&bu, "PNG");
+    }
     // Save the image
     if (imageId == "temp") {
         QFile file(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
diff --git a/src/wizardview/components/ProfilePage.qml b/src/wizardview/components/ProfilePage.qml
index fa6c61658..cba86402d 100644
--- a/src/wizardview/components/ProfilePage.qml
+++ b/src/wizardview/components/ProfilePage.qml
@@ -32,13 +32,12 @@ Rectangle {
     id: root
 
     // trigger a default avatar prior to account generation
-    property string createdAccountId: "dummy"
+    property string createdAccountId
     property int preferredHeight: profilePageColumnLayout.implicitHeight
 
     signal showThisPage
 
     function initializeOnShowUp() {
-        createdAccountId = "dummy"
         clearAllTextFields()
         saveProfileBtn.spinnerTriggered = true
     }
-- 
GitLab