1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-08-03 22:35:45 +02:00

video-split: follow up patch

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

GitLab: #476
Change-Id: Ib3270b5d37d63aa99a576d48574b62801df37258
This commit is contained in:
Sébastien Blin 2022-03-28 09:54:32 -04:00
parent 573f62d2c7
commit 3debb09740
20 changed files with 150 additions and 124 deletions

View file

@ -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()};
{
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();
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++;
}
}

View file

@ -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_;

View file

@ -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

View file

@ -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>
*

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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 ?

View file

@ -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)
}
}

View file

@ -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 ?

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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
}
}
}

View file

@ -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

View file

@ -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) ?

View file

@ -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

View file

@ -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);
}

View file

@ -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)

View file

@ -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
}