mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-08-04 14:55:43 +02:00
call: add call status indicator when adding new participants into a conference
Gitlab: #410 Change-Id: Iff3b06b123363478794fd7e419db3d2d0ae10bb7
This commit is contained in:
parent
7059a8cdab
commit
77aae84786
22 changed files with 614 additions and 158 deletions
8
images/icons/cross_black_24dp.svg
Normal file
8
images/icons/cross_black_24dp.svg
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||||
|
<path d="M13.3,12.4l2.1-2.1c0.3-0.3,0.3-0.8,0-1.1c-0.3-0.3-0.8-0.3-1.1,0l-2.1,2.1l-2.1-2.1C9.8,8.9,9.3,8.9,9,9.2
|
||||||
|
C8.9,9.3,8.8,9.5,8.8,9.7c0,0.2,0.1,0.4,0.2,0.6l2.1,2.1L9,14.5c-0.2,0.1-0.2,0.3-0.2,0.5c0,0.2,0.1,0.4,0.2,0.6
|
||||||
|
c0.3,0.3,0.8,0.3,1.1,0l2.1-2.1l2.1,2.1c0.1,0.1,0.3,0.2,0.5,0.2c0.2,0,0.4-0.1,0.5-0.2c0.3-0.3,0.3-0.8,0-1.1L13.3,12.4z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 697 B |
2
qml.qrc
2
qml.qrc
|
@ -141,5 +141,7 @@
|
||||||
<file>src/mainview/components/CallActionBar.qml</file>
|
<file>src/mainview/components/CallActionBar.qml</file>
|
||||||
<file>src/commoncomponents/HalfPill.qml</file>
|
<file>src/commoncomponents/HalfPill.qml</file>
|
||||||
<file>src/commoncomponents/MaterialToolTip.qml</file>
|
<file>src/commoncomponents/MaterialToolTip.qml</file>
|
||||||
|
<file>src/mainview/components/ParticipantCallInStatusDelegate.qml</file>
|
||||||
|
<file>src/mainview/components/ParticipantCallInStatusView.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<file>images/icons/baseline-refresh-24px.svg</file>
|
<file>images/icons/baseline-refresh-24px.svg</file>
|
||||||
<file>images/jami_rolling_spinner.gif</file>
|
<file>images/jami_rolling_spinner.gif</file>
|
||||||
<file>images/icons/baseline-close-24px.svg</file>
|
<file>images/icons/baseline-close-24px.svg</file>
|
||||||
|
<file>images/icons/cross_black_24dp.svg</file>
|
||||||
<file>images/icons/baseline-done-24px.svg</file>
|
<file>images/icons/baseline-done-24px.svg</file>
|
||||||
<file>images/icons/baseline-error_outline-24px.svg</file>
|
<file>images/icons/baseline-error_outline-24px.svg</file>
|
||||||
<file>projectcredits.html</file>
|
<file>projectcredits.html</file>
|
||||||
|
|
|
@ -643,29 +643,9 @@ CallAdapter::updateCallOverlay(const lrc::api::conversation::Info& convInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CallAdapter::hangupCall(const QString& uri)
|
CallAdapter::hangUpCall(const QString& callId)
|
||||||
{
|
{
|
||||||
const auto& convInfo = lrcInstance_->getConversationFromPeerUri(uri, accountId_);
|
lrcInstance_->getCurrentCallModel()->hangUp(callId);
|
||||||
if (!convInfo.uid.isEmpty()) {
|
|
||||||
auto callModel = lrcInstance_->getAccountInfo(accountId_).callModel.get();
|
|
||||||
if (callModel->hasCall(convInfo.callId)) {
|
|
||||||
/*
|
|
||||||
* Store the last remaining participant of the conference,
|
|
||||||
* so we can switch the smartlist index after termination.
|
|
||||||
*/
|
|
||||||
if (!convInfo.confId.isEmpty()) {
|
|
||||||
auto callList = lrcInstance_->getConferenceSubcalls(convInfo.confId);
|
|
||||||
if (callList.size() == 2) {
|
|
||||||
for (const auto& cId : callList) {
|
|
||||||
if (cId != convInfo.callId) {
|
|
||||||
lrcInstance_->pushlastConference(convInfo.confId, cId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callModel->hangUp(convInfo.callId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -56,7 +56,7 @@ public:
|
||||||
Q_INVOKABLE void sipInputPanelPlayDTMF(const QString& key);
|
Q_INVOKABLE void sipInputPanelPlayDTMF(const QString& key);
|
||||||
|
|
||||||
// For Call Overlay
|
// For Call Overlay
|
||||||
Q_INVOKABLE void hangupCall(const QString& uri);
|
Q_INVOKABLE void hangUpCall(const QString& callId);
|
||||||
Q_INVOKABLE void maximizeParticipant(const QString& uri);
|
Q_INVOKABLE void maximizeParticipant(const QString& uri);
|
||||||
Q_INVOKABLE void minimizeParticipant(const QString& uri);
|
Q_INVOKABLE void minimizeParticipant(const QString& uri);
|
||||||
Q_INVOKABLE void hangUpThisCall();
|
Q_INVOKABLE void hangUpThisCall();
|
||||||
|
|
|
@ -112,6 +112,127 @@ IndexRangeFilterProxyModel::setRange(int min, int max)
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PendingConferenceesListModel::PendingConferenceesListModel(LRCInstance* instance, QObject* parent)
|
||||||
|
: QAbstractListModel(parent)
|
||||||
|
, lrcInstance_(instance)
|
||||||
|
{
|
||||||
|
connectSignals();
|
||||||
|
connect(lrcInstance_, &LRCInstance::currentAccountIdChanged, [this]() { connectSignals(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PendingConferenceesListModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
return lrcInstance_->getCurrentCallModel()->getPendingConferencees().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant
|
||||||
|
PendingConferenceesListModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
using namespace PendingConferences;
|
||||||
|
|
||||||
|
// WARNING: not swarm ready
|
||||||
|
QString pendingConferenceeCallId;
|
||||||
|
QString pendingConferenceeContactUri;
|
||||||
|
ContactModel* contactModel {nullptr};
|
||||||
|
lrc::api::call::Status callStatus;
|
||||||
|
try {
|
||||||
|
auto callModel = lrcInstance_->getCurrentCallModel();
|
||||||
|
auto currentPendingConferenceeInfo = callModel->getPendingConferencees().at(index.row());
|
||||||
|
pendingConferenceeCallId = currentPendingConferenceeInfo.callId;
|
||||||
|
const auto call = callModel->getCall(pendingConferenceeCallId);
|
||||||
|
|
||||||
|
callStatus = call.status;
|
||||||
|
pendingConferenceeContactUri = currentPendingConferenceeInfo.uri;
|
||||||
|
contactModel = lrcInstance_->getCurrentContactModel();
|
||||||
|
} catch (...) {
|
||||||
|
return QVariant(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we are using image provider right now, image url representation should be unique to
|
||||||
|
// be able to use the image cache, account avatar will only be updated once PictureUid changed
|
||||||
|
switch (role) {
|
||||||
|
case Role::PrimaryName:
|
||||||
|
return QVariant(contactModel->bestNameForContact(pendingConferenceeContactUri));
|
||||||
|
case Role::CallStatus:
|
||||||
|
return QVariant(lrc::api::call::to_string(callStatus));
|
||||||
|
case Role::ContactUri:
|
||||||
|
return QVariant(pendingConferenceeContactUri);
|
||||||
|
case Role::PendingConferenceeCallId:
|
||||||
|
return QVariant(pendingConferenceeCallId);
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray>
|
||||||
|
PendingConferenceesListModel::roleNames() const
|
||||||
|
{
|
||||||
|
using namespace PendingConferences;
|
||||||
|
QHash<int, QByteArray> roles;
|
||||||
|
#define X(role) roles[role] = #role;
|
||||||
|
PC_ROLES
|
||||||
|
#undef X
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PendingConferenceesListModel::connectSignals()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
|
||||||
|
disconnect(callsStatusChanged_);
|
||||||
|
disconnect(beginInsertPendingConferencesRows_);
|
||||||
|
disconnect(endInsertPendingConferencesRows_);
|
||||||
|
disconnect(beginRemovePendingConferencesRows_);
|
||||||
|
disconnect(endRemovePendingConferencesRows_);
|
||||||
|
|
||||||
|
callsStatusChanged_ = connect(lrcInstance_->getCurrentCallModel(),
|
||||||
|
&NewCallModel::callStatusChanged,
|
||||||
|
this,
|
||||||
|
[this]() {
|
||||||
|
dataChanged(index(0, 0),
|
||||||
|
index(rowCount() - 1),
|
||||||
|
{PendingConferences::Role::CallStatus});
|
||||||
|
});
|
||||||
|
|
||||||
|
beginInsertPendingConferencesRows_ = connect(
|
||||||
|
lrcInstance_->getCurrentCallModel(),
|
||||||
|
&NewCallModel::beginInsertPendingConferenceesRows,
|
||||||
|
this,
|
||||||
|
[this](int position, int rows) {
|
||||||
|
beginInsertRows(QModelIndex(), position, position + (rows - 1));
|
||||||
|
},
|
||||||
|
Qt::DirectConnection);
|
||||||
|
|
||||||
|
endInsertPendingConferencesRows_ = connect(
|
||||||
|
lrcInstance_->getCurrentCallModel(),
|
||||||
|
&NewCallModel::endInsertPendingConferenceesRows,
|
||||||
|
this,
|
||||||
|
[this]() { endInsertRows(); },
|
||||||
|
Qt::DirectConnection);
|
||||||
|
|
||||||
|
beginRemovePendingConferencesRows_ = connect(
|
||||||
|
lrcInstance_->getCurrentCallModel(),
|
||||||
|
&NewCallModel::beginRemovePendingConferenceesRows,
|
||||||
|
this,
|
||||||
|
[this](int position, int rows) {
|
||||||
|
beginRemoveRows(QModelIndex(), position, position + (rows - 1));
|
||||||
|
},
|
||||||
|
Qt::DirectConnection);
|
||||||
|
|
||||||
|
endRemovePendingConferencesRows_ = connect(
|
||||||
|
lrcInstance_->getCurrentCallModel(),
|
||||||
|
&NewCallModel::endRemovePendingConferenceesRows,
|
||||||
|
this,
|
||||||
|
[this]() { endRemoveRows(); },
|
||||||
|
|
||||||
|
Qt::DirectConnection);
|
||||||
|
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
CallOverlayModel::CallOverlayModel(LRCInstance* instance, QObject* parent)
|
CallOverlayModel::CallOverlayModel(LRCInstance* instance, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, lrcInstance_(instance)
|
, lrcInstance_(instance)
|
||||||
|
@ -120,6 +241,7 @@ CallOverlayModel::CallOverlayModel(LRCInstance* instance, QObject* parent)
|
||||||
, overflowModel_(new IndexRangeFilterProxyModel(secondaryModel_))
|
, overflowModel_(new IndexRangeFilterProxyModel(secondaryModel_))
|
||||||
, overflowVisibleModel_(new IndexRangeFilterProxyModel(secondaryModel_))
|
, overflowVisibleModel_(new IndexRangeFilterProxyModel(secondaryModel_))
|
||||||
, overflowHiddenModel_(new IndexRangeFilterProxyModel(secondaryModel_))
|
, overflowHiddenModel_(new IndexRangeFilterProxyModel(secondaryModel_))
|
||||||
|
, pendingConferenceesModel_(new PendingConferenceesListModel(instance, this))
|
||||||
{
|
{
|
||||||
connect(this,
|
connect(this,
|
||||||
&CallOverlayModel::overflowIndexChanged,
|
&CallOverlayModel::overflowIndexChanged,
|
||||||
|
@ -177,6 +299,12 @@ CallOverlayModel::overflowHiddenModel()
|
||||||
return QVariant::fromValue(overflowHiddenModel_);
|
return QVariant::fromValue(overflowHiddenModel_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant
|
||||||
|
CallOverlayModel::pendingConferenceesModel()
|
||||||
|
{
|
||||||
|
return QVariant::fromValue(pendingConferenceesModel_);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CallOverlayModel::clearControls()
|
CallOverlayModel::clearControls()
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,12 @@
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
|
|
||||||
|
#define PC_ROLES \
|
||||||
|
X(PrimaryName) \
|
||||||
|
X(PendingConferenceeCallId) \
|
||||||
|
X(CallStatus) \
|
||||||
|
X(ContactUri)
|
||||||
|
|
||||||
namespace CallControl {
|
namespace CallControl {
|
||||||
Q_NAMESPACE
|
Q_NAMESPACE
|
||||||
enum Role { ItemAction = Qt::UserRole + 1, BadgeCount };
|
enum Role { ItemAction = Qt::UserRole + 1, BadgeCount };
|
||||||
|
@ -39,6 +45,17 @@ struct Item
|
||||||
};
|
};
|
||||||
} // namespace CallControl
|
} // namespace CallControl
|
||||||
|
|
||||||
|
namespace PendingConferences {
|
||||||
|
Q_NAMESPACE
|
||||||
|
enum Role {
|
||||||
|
DummyRole = Qt::UserRole + 1,
|
||||||
|
#define X(role) role,
|
||||||
|
PC_ROLES
|
||||||
|
#undef X
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(Role)
|
||||||
|
} // namespace PendingConferences
|
||||||
|
|
||||||
class CallControlListModel : public QAbstractListModel
|
class CallControlListModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -73,6 +90,28 @@ private:
|
||||||
int max_ {-1};
|
int max_ {-1};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PendingConferenceesListModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
PendingConferenceesListModel(LRCInstance* instance, QObject* parent = nullptr);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
void connectSignals();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LRCInstance* lrcInstance_ {nullptr};
|
||||||
|
|
||||||
|
QMetaObject::Connection callsStatusChanged_;
|
||||||
|
QMetaObject::Connection beginInsertPendingConferencesRows_;
|
||||||
|
QMetaObject::Connection endInsertPendingConferencesRows_;
|
||||||
|
QMetaObject::Connection beginRemovePendingConferencesRows_;
|
||||||
|
QMetaObject::Connection endRemovePendingConferencesRows_;
|
||||||
|
};
|
||||||
|
|
||||||
class CallOverlayModel : public QObject
|
class CallOverlayModel : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -91,6 +130,7 @@ public:
|
||||||
Q_INVOKABLE QVariant overflowModel();
|
Q_INVOKABLE QVariant overflowModel();
|
||||||
Q_INVOKABLE QVariant overflowVisibleModel();
|
Q_INVOKABLE QVariant overflowVisibleModel();
|
||||||
Q_INVOKABLE QVariant overflowHiddenModel();
|
Q_INVOKABLE QVariant overflowHiddenModel();
|
||||||
|
Q_INVOKABLE QVariant pendingConferenceesModel();
|
||||||
|
|
||||||
Q_INVOKABLE void registerFilter(QQuickWindow* object, QQuickItem* item);
|
Q_INVOKABLE void registerFilter(QQuickWindow* object, QQuickItem* item);
|
||||||
Q_INVOKABLE void unregisterFilter(QQuickWindow* object, QQuickItem* item);
|
Q_INVOKABLE void unregisterFilter(QQuickWindow* object, QQuickItem* item);
|
||||||
|
@ -110,6 +150,7 @@ private:
|
||||||
IndexRangeFilterProxyModel* overflowModel_;
|
IndexRangeFilterProxyModel* overflowModel_;
|
||||||
IndexRangeFilterProxyModel* overflowVisibleModel_;
|
IndexRangeFilterProxyModel* overflowVisibleModel_;
|
||||||
IndexRangeFilterProxyModel* overflowHiddenModel_;
|
IndexRangeFilterProxyModel* overflowHiddenModel_;
|
||||||
|
PendingConferenceesListModel* pendingConferenceesModel_;
|
||||||
|
|
||||||
QList<QQuickItem*> watchedItems_;
|
QList<QQuickItem*> watchedItems_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,10 +23,10 @@ import net.jami.Adapters 1.0
|
||||||
import net.jami.Constants 1.0
|
import net.jami.Constants 1.0
|
||||||
import net.jami.Models 1.0
|
import net.jami.Models 1.0
|
||||||
|
|
||||||
Item {
|
SpinningAnimation {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
enum Mode {
|
enum AvatarMode {
|
||||||
FromAccount = 0,
|
FromAccount = 0,
|
||||||
FromFile,
|
FromFile,
|
||||||
FromContactUri,
|
FromContactUri,
|
||||||
|
@ -40,22 +40,22 @@ Item {
|
||||||
property alias sourceSize: rootImage.sourceSize
|
property alias sourceSize: rootImage.sourceSize
|
||||||
property int transitionDuration: 150
|
property int transitionDuration: 150
|
||||||
property bool saveToConfig: false
|
property bool saveToConfig: false
|
||||||
property int mode: AvatarImage.Mode.FromAccount
|
property int avatarMode: AvatarImage.AvatarMode.FromAccount
|
||||||
property string imageProviderIdPrefix: {
|
property string imageProviderIdPrefix: {
|
||||||
switch(mode) {
|
switch (avatarMode) {
|
||||||
case AvatarImage.Mode.FromAccount:
|
case AvatarImage.AvatarMode.FromAccount:
|
||||||
return "account_"
|
return "account_"
|
||||||
case AvatarImage.Mode.FromFile:
|
case AvatarImage.AvatarMode.FromFile:
|
||||||
return "file_"
|
return "file_"
|
||||||
case AvatarImage.Mode.FromContactUri:
|
case AvatarImage.AvatarMode.FromContactUri:
|
||||||
return "contact_"
|
return "contact_"
|
||||||
case AvatarImage.Mode.FromConvUid:
|
case AvatarImage.AvatarMode.FromConvUid:
|
||||||
return "conversation_"
|
return "conversation_"
|
||||||
case AvatarImage.Mode.FromTemporaryName:
|
case AvatarImage.AvatarMode.FromTemporaryName:
|
||||||
return "fallback_"
|
return "fallback_"
|
||||||
case AvatarImage.Mode.FromBase64:
|
case AvatarImage.AvatarMode.FromBase64:
|
||||||
return "base64_"
|
return "base64_"
|
||||||
case AvatarImage.Mode.Default:
|
case AvatarImage.AvatarMode.Default:
|
||||||
return "default_"
|
return "default_"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
|
@ -63,24 +63,23 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Full request url example: forceUpdateUrl_xxxxxxx_account_xxxxxxxx
|
// Full request url example: forceUpdateUrl_xxxxxxx_account_xxxxxxxx
|
||||||
property string imageProviderUrl: "image://avatarImage/" + forceUpdateUrl + "_" +
|
property string imageProviderUrl: "image://avatarImage/" + forceUpdateUrl
|
||||||
imageProviderIdPrefix
|
+ "_" + imageProviderIdPrefix
|
||||||
property string imageId: ""
|
property string imageId: ""
|
||||||
property string forceUpdateUrl: Date.now()
|
property string forceUpdateUrl: Date.now()
|
||||||
property alias presenceStatus: presenceIndicator.status
|
property alias presenceStatus: presenceIndicator.status
|
||||||
property bool showPresenceIndicator: true
|
property bool showPresenceIndicator: true
|
||||||
property int unreadMessagesCount: 0
|
property int unreadMessagesCount: 0
|
||||||
property bool enableAnimation: true
|
property bool enableFadeAnimation: true
|
||||||
property bool showSpinningAnimation: false
|
|
||||||
|
|
||||||
signal imageIsReady
|
signal imageIsReady
|
||||||
|
|
||||||
function saveAvatarToConfig() {
|
function saveAvatarToConfig() {
|
||||||
switch(mode) {
|
switch (avatarMode) {
|
||||||
case AvatarImage.Mode.FromFile:
|
case AvatarImage.AvatarMode.FromFile:
|
||||||
AccountAdapter.setCurrAccAvatar(true, imageId)
|
AccountAdapter.setCurrAccAvatar(true, imageId)
|
||||||
break
|
break
|
||||||
case AvatarImage.Mode.FromBase64:
|
case AvatarImage.AvatarMode.FromBase64:
|
||||||
AccountAdapter.setCurrAccAvatar(false, imageId)
|
AccountAdapter.setCurrAccAvatar(false, imageId)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
|
@ -102,29 +101,38 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function reloadImageSource() {
|
function reloadImageSource() {
|
||||||
var tempEnableAnimation = enableAnimation
|
var tempEnableAnimation = enableFadeAnimation
|
||||||
var tempImageSource = rootImage.source
|
var tempImageSource = rootImage.source
|
||||||
|
|
||||||
enableAnimation = false
|
enableFadeAnimation = false
|
||||||
rootImage.source = ""
|
rootImage.source = ""
|
||||||
|
|
||||||
enableAnimation = tempEnableAnimation
|
enableFadeAnimation = tempEnableAnimation
|
||||||
rootImage.source = tempImageSource
|
rootImage.source = tempImageSource
|
||||||
}
|
}
|
||||||
|
|
||||||
function rootImageOverlayReadyCallback() {
|
function rootImageOverlayReadyCallback() {
|
||||||
if (rootImageOverlay.status === Image.Ready &&
|
if (rootImageOverlay.status === Image.Ready
|
||||||
(rootImageOverlay.state === "avatarImgFadeIn")) {
|
&& (rootImageOverlay.state === "avatarImgFadeIn")) {
|
||||||
rootImageOverlay.statusChanged.disconnect(rootImageOverlayReadyCallback)
|
rootImageOverlay.statusChanged.disconnect(
|
||||||
|
rootImageOverlayReadyCallback)
|
||||||
|
|
||||||
rootImageOverlay.state = ''
|
rootImageOverlay.state = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: imageGroup
|
||||||
|
|
||||||
|
anchors.centerIn: root
|
||||||
|
|
||||||
|
width: root.width - spinningAnimationWidth
|
||||||
|
height: root.height - spinningAnimationWidth
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: rootImage
|
id: rootImage
|
||||||
|
|
||||||
anchors.fill: root
|
anchors.fill: imageGroup
|
||||||
|
|
||||||
smooth: true
|
smooth: true
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
|
@ -137,7 +145,7 @@ Item {
|
||||||
|
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
if (status === Image.Ready) {
|
if (status === Image.Ready) {
|
||||||
if (enableAnimation) {
|
if (enableFadeAnimation) {
|
||||||
rootImageOverlay.state = "avatarImgFadeIn"
|
rootImageOverlay.state = "avatarImgFadeIn"
|
||||||
} else {
|
} else {
|
||||||
rootImageOverlay.source = rootImage.source
|
rootImageOverlay.source = rootImage.source
|
||||||
|
@ -178,16 +186,18 @@ Item {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
properties: "opacity"
|
properties: "opacity"
|
||||||
easing.type: Easing.InOutQuad
|
easing.type: Easing.InOutQuad
|
||||||
duration: enableAnimation ? 400 : 0
|
duration: enableFadeAnimation ? 400 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
onRunningChanged: {
|
onRunningChanged: {
|
||||||
if ((rootImageOverlay.state === "avatarImgFadeIn") && (!running)) {
|
if ((rootImageOverlay.state === "avatarImgFadeIn")
|
||||||
|
&& (!running)) {
|
||||||
if (rootImageOverlay.source === rootImage.source) {
|
if (rootImageOverlay.source === rootImage.source) {
|
||||||
rootImageOverlay.state = ''
|
rootImageOverlay.state = ''
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rootImageOverlay.statusChanged.connect(rootImageOverlayReadyCallback)
|
rootImageOverlay.statusChanged.connect(
|
||||||
|
rootImageOverlayReadyCallback)
|
||||||
rootImageOverlay.source = rootImage.source
|
rootImageOverlay.source = rootImage.source
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,33 +208,22 @@ Item {
|
||||||
PresenceIndicator {
|
PresenceIndicator {
|
||||||
id: presenceIndicator
|
id: presenceIndicator
|
||||||
|
|
||||||
anchors.right: root.right
|
anchors.right: imageGroup.right
|
||||||
anchors.rightMargin: -1
|
anchors.rightMargin: -1
|
||||||
anchors.bottom: root.bottom
|
anchors.bottom: imageGroup.bottom
|
||||||
anchors.bottomMargin: -1
|
anchors.bottomMargin: -1
|
||||||
|
|
||||||
size: root.width * 0.26
|
size: imageGroup.width * 0.26
|
||||||
|
|
||||||
visible: showPresenceIndicator
|
visible: showPresenceIndicator
|
||||||
}
|
}
|
||||||
|
|
||||||
SpinningAnimation {
|
|
||||||
id: spinningAnimation
|
|
||||||
|
|
||||||
anchors.horizontalCenter: root.horizontalCenter
|
|
||||||
anchors.verticalCenter: root.verticalCenter
|
|
||||||
|
|
||||||
visible: showSpinningAnimation
|
|
||||||
width: Math.ceil(root.width * 1.05)
|
|
||||||
height: Math.ceil(root.height * 1.05)
|
|
||||||
z: -1
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: ScreenInfo
|
target: ScreenInfo
|
||||||
|
|
||||||
function onDevicePixelRatioChanged(){
|
function onDevicePixelRatioChanged() {
|
||||||
reloadImageSource()
|
reloadImageSource()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ ColumnLayout {
|
||||||
photoState = PhotoboothView.PhotoState.Default
|
photoState = PhotoboothView.PhotoState.Default
|
||||||
avatarSet = false
|
avatarSet = false
|
||||||
if (useDefaultAvatar)
|
if (useDefaultAvatar)
|
||||||
setAvatarImage(AvatarImage.Mode.Default, "")
|
setAvatarImage(AvatarImage.AvatarMode.Default, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
function startBooth() {
|
function startBooth() {
|
||||||
|
@ -65,16 +65,16 @@ ColumnLayout {
|
||||||
} catch(erro){console.log("Exception: " + erro.message)}
|
} catch(erro){console.log("Exception: " + erro.message)}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAvatarImage(mode = AvatarImage.Mode.FromAccount,
|
function setAvatarImage(mode = AvatarImage.AvatarMode.FromAccount,
|
||||||
imageId = LRCInstance.currentAccountId){
|
imageId = LRCInstance.currentAccountId){
|
||||||
if (mode !== AvatarImage.Mode.FromBase64)
|
if (mode !== AvatarImage.AvatarMode.FromBase64)
|
||||||
avatarImg.enableAnimation = true
|
avatarImg.enableFadeAnimation = true
|
||||||
else
|
else
|
||||||
avatarImg.enableAnimation = false
|
avatarImg.enableFadeAnimation = false
|
||||||
|
|
||||||
avatarImg.mode = mode
|
avatarImg.avatarMode = mode
|
||||||
|
|
||||||
if (mode === AvatarImage.Mode.Default) {
|
if (mode === AvatarImage.AvatarMode.Default) {
|
||||||
avatarImg.updateImage(imageId)
|
avatarImg.updateImage(imageId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ ColumnLayout {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setAvatarImage(AvatarImage.Mode.FromFile,
|
setAvatarImage(AvatarImage.AvatarMode.FromFile,
|
||||||
UtilsAdapter.getAbsPath(fileName))
|
UtilsAdapter.getAbsPath(fileName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
onImageIsReady: {
|
onImageIsReady: {
|
||||||
if (mode === AvatarImage.Mode.FromBase64)
|
if (avatarMode === AvatarImage.AvatarMode.FromBase64)
|
||||||
photoState = PhotoboothView.PhotoState.Taken
|
photoState = PhotoboothView.PhotoState.Taken
|
||||||
|
|
||||||
if (photoState === PhotoboothView.PhotoState.Taken) {
|
if (photoState === PhotoboothView.PhotoState.Taken) {
|
||||||
|
@ -268,7 +268,7 @@ ColumnLayout {
|
||||||
startBooth()
|
startBooth()
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
setAvatarImage(AvatarImage.Mode.FromBase64,
|
setAvatarImage(AvatarImage.AvatarMode.FromBase64,
|
||||||
previewWidget.takePhoto(boothWidth))
|
previewWidget.takePhoto(boothWidth))
|
||||||
|
|
||||||
avatarSet = true
|
avatarSet = true
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 by Savoir-faire Linux
|
* Copyright (C) 2021 by Savoir-faire Linux
|
||||||
* Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
|
* Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
|
||||||
|
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,8 +26,23 @@ import QtGraphicalEffects 1.12
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
enum SpinningAnimationMode {
|
||||||
|
DISABLED = 0,
|
||||||
|
NORMAL,
|
||||||
|
SYMMETRY
|
||||||
|
}
|
||||||
|
|
||||||
|
property int spinningAnimationMode: SpinningAnimation.SpinningAnimationMode.DISABLED
|
||||||
|
property int spinningAnimationWidth: 5
|
||||||
|
property real outerCutRadius: root.height / 2
|
||||||
|
property int spinningAnimationDuration: 1000
|
||||||
|
|
||||||
ConicalGradient {
|
ConicalGradient {
|
||||||
|
id: conicalGradientOne
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
visible: spinningAnimationMode !== SpinningAnimation.SpinningAnimationMode.DISABLED
|
||||||
angle: 0.0
|
angle: 0.0
|
||||||
gradient: Gradient {
|
gradient: Gradient {
|
||||||
GradientStop { position: 0.5; color: "transparent" }
|
GradientStop { position: 0.5; color: "transparent" }
|
||||||
|
@ -35,17 +51,74 @@ Item {
|
||||||
|
|
||||||
RotationAnimation on angle {
|
RotationAnimation on angle {
|
||||||
loops: Animation.Infinite
|
loops: Animation.Infinite
|
||||||
duration: 1000
|
duration: spinningAnimationDuration
|
||||||
from: 0
|
from: 0
|
||||||
to: 360
|
to: 360
|
||||||
}
|
}
|
||||||
}
|
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
|
layer.effect: OpacityMask {
|
||||||
|
invert: true
|
||||||
|
maskSource: Item {
|
||||||
|
width: conicalGradientOne.width
|
||||||
|
height: conicalGradientOne.height
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: spinningAnimationWidth
|
||||||
|
radius: outerCutRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConicalGradient {
|
||||||
|
id: conicalGradientTwo
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
visible: spinningAnimationMode === SpinningAnimation.SpinningAnimationMode.SYMMETRY
|
||||||
|
angle: 180.0
|
||||||
|
gradient: Gradient {
|
||||||
|
GradientStop {
|
||||||
|
position: 0.75
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
|
GradientStop {
|
||||||
|
position: 1.0
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RotationAnimation on angle {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
duration: spinningAnimationDuration
|
||||||
|
from: 180.0
|
||||||
|
to: 540.0
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: OpacityMask {
|
||||||
|
invert: true
|
||||||
|
maskSource: Item {
|
||||||
|
width: conicalGradientTwo.width
|
||||||
|
height: conicalGradientTwo.height
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: spinningAnimationWidth
|
||||||
|
radius: outerCutRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.enabled: spinningAnimationMode !== SpinningAnimation.SpinningAnimationMode.DISABLED
|
||||||
layer.effect: OpacityMask {
|
layer.effect: OpacityMask {
|
||||||
maskSource: Rectangle {
|
maskSource: Rectangle {
|
||||||
width: root.height
|
width: root.width
|
||||||
height: root.height
|
height: root.height
|
||||||
radius: root.height / 2
|
radius: outerCutRadius
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -129,6 +129,9 @@ Item {
|
||||||
// Plugin Preferences View
|
// Plugin Preferences View
|
||||||
property color comboBoxBackgroundColor: darkTheme ? editBackgroundColor : selectedColor
|
property color comboBoxBackgroundColor: darkTheme ? editBackgroundColor : selectedColor
|
||||||
|
|
||||||
|
// ParticipantCallInStatusView
|
||||||
|
property color participantCallInStatusTextColor: whiteColor
|
||||||
|
|
||||||
// Chatview
|
// Chatview
|
||||||
property color jamiLightBlue: darkTheme ? "#003b4e" : Qt.rgba(59, 193, 211, 0.3)
|
property color jamiLightBlue: darkTheme ? "#003b4e" : Qt.rgba(59, 193, 211, 0.3)
|
||||||
property color jamiDarkBlue: darkTheme ? "#28b1ed" : "#003b4e"
|
property color jamiDarkBlue: darkTheme ? "#28b1ed" : "#003b4e"
|
||||||
|
@ -191,6 +194,16 @@ Item {
|
||||||
property real smartListAvatarSize: 52
|
property real smartListAvatarSize: 52
|
||||||
property real avatarSizeInCall: 130
|
property real avatarSizeInCall: 130
|
||||||
property real callButtonPreferredSize: 50
|
property real callButtonPreferredSize: 50
|
||||||
|
property int participantCallInStatusViewWidth: 225
|
||||||
|
property int participantCallInStatusViewHeight: 300
|
||||||
|
property int participantCallInStatusDelegateHeight: 105
|
||||||
|
property int participantCallInStatusDelegateRadius: 5
|
||||||
|
property real participantCallInStatusOpacity: 0.77
|
||||||
|
property int participantCallInAvatarSize: 75
|
||||||
|
property int participantCallInNameFontSize: 11
|
||||||
|
property int participantCallInStatusFontSize: 9
|
||||||
|
property int participantCallInStatusTextWidthLimit: 100
|
||||||
|
property int participantCallInStatusTextWidth: 68
|
||||||
|
|
||||||
property real maximumWidthSettingsView: 600
|
property real maximumWidthSettingsView: 600
|
||||||
property real settingsHeaderpreferredHeight: 64
|
property real settingsHeaderpreferredHeight: 64
|
||||||
|
|
|
@ -39,7 +39,7 @@ ItemDelegate {
|
||||||
width: 40
|
width: 40
|
||||||
height: 40
|
height: 40
|
||||||
|
|
||||||
mode: AvatarImage.Mode.FromContactUri
|
avatarMode: AvatarImage.AvatarMode.FromContactUri
|
||||||
imageId: URI
|
imageId: URI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ Rectangle {
|
||||||
|
|
||||||
property bool isIncoming: false
|
property bool isIncoming: false
|
||||||
property bool isAudioOnly: false
|
property bool isAudioOnly: false
|
||||||
property var accountConvPair: ["",""]
|
property var accountConvPair: ["", ""]
|
||||||
property int callStatus: 0
|
property int callStatus: 0
|
||||||
property string bestName: ""
|
property string bestName: ""
|
||||||
|
|
||||||
|
@ -76,12 +76,12 @@ Rectangle {
|
||||||
id: contactImg
|
id: contactImg
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
Layout.preferredWidth: JamiTheme.avatarSizeInCall
|
Layout.preferredWidth: JamiTheme.avatarSizeInCall + spinningAnimationWidth
|
||||||
Layout.preferredHeight: JamiTheme.avatarSizeInCall
|
Layout.preferredHeight: JamiTheme.avatarSizeInCall + spinningAnimationWidth
|
||||||
|
|
||||||
mode: AvatarImage.Mode.FromConvUid
|
avatarMode: AvatarImage.AvatarMode.FromConvUid
|
||||||
showPresenceIndicator: false
|
showPresenceIndicator: false
|
||||||
showSpinningAnimation: true
|
spinningAnimationMode: SpinningAnimation.SpinningAnimationMode.NORMAL
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
|
|
@ -44,7 +44,8 @@ Item {
|
||||||
|
|
||||||
property bool frozen: callActionBar.overflowOpen ||
|
property bool frozen: callActionBar.overflowOpen ||
|
||||||
callActionBar.hovered ||
|
callActionBar.hovered ||
|
||||||
callActionBar.subMenuOpen
|
callActionBar.subMenuOpen ||
|
||||||
|
participantCallInStatusView.visible
|
||||||
|
|
||||||
opacity: 0
|
opacity: 0
|
||||||
|
|
||||||
|
@ -184,6 +185,15 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParticipantCallInStatusView {
|
||||||
|
id: participantCallInStatusView
|
||||||
|
|
||||||
|
anchors.right: root.right
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
anchors.bottom: __callActionBar.top
|
||||||
|
anchors.bottomMargin: 20
|
||||||
|
}
|
||||||
|
|
||||||
CallActionBar {
|
CallActionBar {
|
||||||
id: __callActionBar
|
id: __callActionBar
|
||||||
|
|
||||||
|
|
|
@ -348,7 +348,7 @@ Rectangle {
|
||||||
Layout.preferredWidth: JamiTheme.avatarSizeInCall
|
Layout.preferredWidth: JamiTheme.avatarSizeInCall
|
||||||
Layout.preferredHeight: JamiTheme.avatarSizeInCall
|
Layout.preferredHeight: JamiTheme.avatarSizeInCall
|
||||||
|
|
||||||
mode: AvatarImage.Mode.FromConvUid
|
avatarMode: AvatarImage.AvatarMode.FromConvUid
|
||||||
showPresenceIndicator: false
|
showPresenceIndicator: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
141
src/mainview/components/ParticipantCallInStatusDelegate.qml
Normal file
141
src/mainview/components/ParticipantCallInStatusDelegate.qml
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Savoir-faire Linux
|
||||||
|
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
import net.jami.Adapters 1.0
|
||||||
|
import net.jami.Models 1.0
|
||||||
|
import net.jami.Constants 1.0
|
||||||
|
|
||||||
|
import "../../commoncomponents"
|
||||||
|
|
||||||
|
SpinningAnimation {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
width: contentRect.width + spinningAnimationWidth
|
||||||
|
height: JamiTheme.participantCallInStatusDelegateHeight
|
||||||
|
|
||||||
|
spinningAnimationMode: SpinningAnimation.SpinningAnimationMode.SYMMETRY
|
||||||
|
outerCutRadius: JamiTheme.participantCallInStatusDelegateRadius
|
||||||
|
spinningAnimationDuration: 5000
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: contentRect
|
||||||
|
|
||||||
|
anchors.centerIn: root
|
||||||
|
|
||||||
|
width: JamiTheme.participantCallInStatusViewWidth + callStatus.Layout.preferredWidth
|
||||||
|
- JamiTheme.participantCallInStatusTextWidth - spinningAnimationWidth
|
||||||
|
height: JamiTheme.participantCallInStatusDelegateHeight - spinningAnimationWidth
|
||||||
|
|
||||||
|
color: JamiTheme.darkGreyColor
|
||||||
|
opacity: JamiTheme.participantCallInStatusOpacity
|
||||||
|
radius: JamiTheme.participantCallInStatusDelegateRadius
|
||||||
|
|
||||||
|
AvatarImage {
|
||||||
|
id: avatar
|
||||||
|
|
||||||
|
anchors.left: contentRect.left
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.verticalCenter: contentRect.verticalCenter
|
||||||
|
|
||||||
|
width: JamiTheme.participantCallInAvatarSize
|
||||||
|
height: JamiTheme.participantCallInAvatarSize
|
||||||
|
|
||||||
|
showPresenceIndicator: false
|
||||||
|
avatarMode: AvatarImage.AvatarMode.FromContactUri
|
||||||
|
imageId: ContactUri
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: infoColumnLayout
|
||||||
|
|
||||||
|
anchors.left: avatar.right
|
||||||
|
anchors.leftMargin: 5
|
||||||
|
anchors.verticalCenter: contentRect.verticalCenter
|
||||||
|
|
||||||
|
implicitHeight: 50
|
||||||
|
implicitWidth: JamiTheme.participantCallInStatusTextWidth
|
||||||
|
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: name
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
Layout.preferredWidth: JamiTheme.participantCallInStatusTextWidth
|
||||||
|
|
||||||
|
font.weight: Font.ExtraBold
|
||||||
|
font.pointSize: JamiTheme.participantCallInNameFontSize
|
||||||
|
color: JamiTheme.participantCallInStatusTextColor
|
||||||
|
text: PrimaryName
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: callStatus
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
|
||||||
|
font.weight: Font.Normal
|
||||||
|
font.pointSize: JamiTheme.participantCallInStatusFontSize
|
||||||
|
color: JamiTheme.participantCallInStatusTextColor
|
||||||
|
text: CallStatus + "…"
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
onWidthChanged: {
|
||||||
|
if (width > JamiTheme.participantCallInStatusTextWidth
|
||||||
|
&& width < JamiTheme.participantCallInStatusTextWidthLimit)
|
||||||
|
callStatus.Layout.preferredWidth = width
|
||||||
|
else if (width >= JamiTheme.participantCallInStatusTextWidthLimit)
|
||||||
|
callStatus.Layout.preferredWidth
|
||||||
|
= JamiTheme.participantCallInStatusTextWidthLimit
|
||||||
|
else
|
||||||
|
callStatus.Layout.preferredWidth
|
||||||
|
= JamiTheme.participantCallInStatusTextWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PushButton {
|
||||||
|
id: callCancelButton
|
||||||
|
|
||||||
|
anchors.right: contentRect.right
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
anchors.verticalCenter: contentRect.verticalCenter
|
||||||
|
|
||||||
|
width: 40
|
||||||
|
height: 40
|
||||||
|
// To control the size of the svg
|
||||||
|
preferredSize: 50
|
||||||
|
|
||||||
|
pressedColor: JamiTheme.refuseRed
|
||||||
|
hoveredColor: JamiTheme.refuseRed
|
||||||
|
normalColor: JamiTheme.refuseRedTransparent
|
||||||
|
|
||||||
|
source: "qrc:/images/icons/cross_black_24dp.svg"
|
||||||
|
imageColor: JamiTheme.whiteColor
|
||||||
|
|
||||||
|
toolTipText: JamiStrings.optionCancel
|
||||||
|
|
||||||
|
onClicked: CallAdapter.hangUpCall(PendingConferenceeCallId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
src/mainview/components/ParticipantCallInStatusView.qml
Normal file
60
src/mainview/components/ParticipantCallInStatusView.qml
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Savoir-faire Linux
|
||||||
|
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
import net.jami.Models 1.0
|
||||||
|
import net.jami.Adapters 1.0
|
||||||
|
import net.jami.Constants 1.0
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
width: currentItem ? currentItem.width + currentItem.spinningAnimationWidth
|
||||||
|
: JamiTheme.participantCallInStatusViewWidth
|
||||||
|
height: JamiTheme.participantCallInStatusDelegateHeight
|
||||||
|
|
||||||
|
model: CallOverlayModel.pendingConferenceesModel()
|
||||||
|
delegate: ParticipantCallInStatusDelegate {}
|
||||||
|
|
||||||
|
visible: currentItem ? true : false
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: model
|
||||||
|
|
||||||
|
function onRowsInserted() {
|
||||||
|
var preferredHeight = JamiTheme.participantCallInStatusDelegateHeight * model.rowCount()
|
||||||
|
root.height = JamiTheme.participantCallInStatusViewHeight
|
||||||
|
< preferredHeight ? JamiTheme.participantCallInStatusViewHeight
|
||||||
|
: preferredHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRowsRemoved() {
|
||||||
|
var preferredHeight = JamiTheme.participantCallInStatusDelegateHeight * model.rowCount()
|
||||||
|
root.height = JamiTheme.participantCallInStatusViewHeight
|
||||||
|
< preferredHeight ? JamiTheme.participantCallInStatusViewHeight
|
||||||
|
: preferredHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
maximumFlickVelocity: 1024
|
||||||
|
ScrollIndicator.vertical: ScrollIndicator {}
|
||||||
|
}
|
|
@ -58,16 +58,16 @@ Item {
|
||||||
contactImage.visible = false
|
contactImage.visible = false
|
||||||
else {
|
else {
|
||||||
if (avatar) {
|
if (avatar) {
|
||||||
contactImage.mode = AvatarImage.Mode.FromBase64
|
contactImage.avatarMode = AvatarImage.AvatarMode.FromBase64
|
||||||
contactImage.updateImage(avatar)
|
contactImage.updateImage(avatar)
|
||||||
} else if (local) {
|
} else if (local) {
|
||||||
contactImage.mode = AvatarImage.Mode.FromAccount
|
contactImage.avatarMode = AvatarImage.AvatarMode.FromAccount
|
||||||
contactImage.updateImage(LRCInstance.currentAccountId)
|
contactImage.updateImage(LRCInstance.currentAccountId)
|
||||||
} else if (isContact) {
|
} else if (isContact) {
|
||||||
contactImage.mode = AvatarImage.Mode.FromContactUri
|
contactImage.avatarMode = AvatarImage.AvatarMode.FromContactUri
|
||||||
contactImage.updateImage(uri)
|
contactImage.updateImage(uri)
|
||||||
} else {
|
} else {
|
||||||
contactImage.mode = AvatarImage.Mode.FromTemporaryName
|
contactImage.avatarMode = AvatarImage.AvatarMode.FromTemporaryName
|
||||||
contactImage.updateImage(uri)
|
contactImage.updateImage(uri)
|
||||||
}
|
}
|
||||||
contactImage.visible = true
|
contactImage.visible = true
|
||||||
|
@ -195,7 +195,7 @@ Item {
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
imageId: ""
|
imageId: ""
|
||||||
visible: false
|
visible: false
|
||||||
mode: AvatarImage.Mode.Default
|
avatarMode: AvatarImage.AvatarMode.Default
|
||||||
showPresenceIndicator: false
|
showPresenceIndicator: false
|
||||||
|
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
|
|
|
@ -68,7 +68,7 @@ ItemDelegate {
|
||||||
Layout.preferredWidth: JamiTheme.smartListAvatarSize
|
Layout.preferredWidth: JamiTheme.smartListAvatarSize
|
||||||
Layout.preferredHeight: JamiTheme.smartListAvatarSize
|
Layout.preferredHeight: JamiTheme.smartListAvatarSize
|
||||||
|
|
||||||
mode: AvatarImage.Mode.FromContactUri
|
avatarMode: AvatarImage.AvatarMode.FromContactUri
|
||||||
showPresenceIndicator: Presence === undefined ? false : Presence
|
showPresenceIndicator: Presence === undefined ? false : Presence
|
||||||
transitionDuration: 0
|
transitionDuration: 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ BaseDialog {
|
||||||
sourceSize.width: preferredImgSize
|
sourceSize.width: preferredImgSize
|
||||||
sourceSize.height: preferredImgSize
|
sourceSize.height: preferredImgSize
|
||||||
|
|
||||||
mode: AvatarImage.Mode.FromConvUid
|
avatarMode: AvatarImage.AvatarMode.FromConvUid
|
||||||
showPresenceIndicator: false
|
showPresenceIndicator: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ ItemDelegate {
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
mode: AvatarImage.Mode.FromContactUri
|
avatarMode: AvatarImage.AvatarMode.FromContactUri
|
||||||
showPresenceIndicator: false
|
showPresenceIndicator: false
|
||||||
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
|
|
@ -54,7 +54,7 @@ Rectangle {
|
||||||
color: JamiTheme.backgroundColor
|
color: JamiTheme.backgroundColor
|
||||||
|
|
||||||
onCreatedAccountIdChanged: {
|
onCreatedAccountIdChanged: {
|
||||||
setAvatarWidget.setAvatarImage(AvatarImage.Mode.FromAccount,
|
setAvatarWidget.setAvatarImage(AvatarImage.AvatarMode.FromAccount,
|
||||||
createdAccountId)
|
createdAccountId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,14 +126,14 @@ Rectangle {
|
||||||
onTextEdited: {
|
onTextEdited: {
|
||||||
if (!(setAvatarWidget.avatarSet)) {
|
if (!(setAvatarWidget.avatarSet)) {
|
||||||
if (text.length === 0) {
|
if (text.length === 0) {
|
||||||
setAvatarWidget.setAvatarImage(AvatarImage.Mode.FromAccount,
|
setAvatarWidget.setAvatarImage(AvatarImage.AvatarMode.FromAccount,
|
||||||
createdAccountId)
|
createdAccountId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text.length == 1 && text.charAt(0) !== lastInitialCharacter) {
|
if (text.length == 1 && text.charAt(0) !== lastInitialCharacter) {
|
||||||
lastInitialCharacter = text.charAt(0)
|
lastInitialCharacter = text.charAt(0)
|
||||||
setAvatarWidget.setAvatarImage(AvatarImage.Mode.FromTemporaryName,
|
setAvatarWidget.setAvatarImage(AvatarImage.AvatarMode.FromTemporaryName,
|
||||||
text)
|
text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue