Skip to content

Commit

Permalink
Call notifications now appear even when the tray is closed, and show …
Browse files Browse the repository at this point in the history
…the avatar of the caller if possible
  • Loading branch information
claucambra committed Apr 20, 2022
1 parent b77d7af commit 3576e51
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 50 deletions.
38 changes: 38 additions & 0 deletions src/gui/systray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickWindow>
#include <QQuickView>
#include <QVariantMap>
#include <QScreen>
#include <QMenu>
#include <QGuiApplication>
Expand Down Expand Up @@ -159,6 +161,42 @@ void Systray::create()
}
}

void Systray::createCallDialog(const Activity &callNotification)
{
if (_trayEngine && !_callsAlreadyNotified.contains(callNotification._id)) {
const QVariantMap talkNotificationData{
{"conversationToken", callNotification._talkNotificationData.conversationToken},
{"messageId", callNotification._talkNotificationData.messageId},
{"messageSent", callNotification._talkNotificationData.messageSent},
{"userAvatar", callNotification._talkNotificationData.userAvatar},
};

QVariantList links;
for(const auto &link : callNotification._links) {
links.append(QVariantMap{
{"imageSource", link._imageSource},
{"imageSourceHovered", link._imageSourceHovered},
{"label", link._label},
{"link", link._link},
{"primary", link._primary},
{"verb", link._verb},
});
}

const QVariantMap initialProperties{
{"talkNotificationData", talkNotificationData},
{"links", links},
{"subject", callNotification._subject},
{"link", callNotification._link},
};

const auto callDialog = new QQmlComponent(_trayEngine, QStringLiteral("qrc:/qml/src/gui/tray/CallNotificationDialog.qml"));
callDialog->createWithInitialProperties(initialProperties);

_callsAlreadyNotified.append(callNotification._id);
}
}

void Systray::slotNewUserSelected()
{
if (_trayEngine) {
Expand Down
3 changes: 3 additions & 0 deletions src/gui/systray.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class Systray
bool isOpen();
QString windowTitle() const;
bool useNormalWindow() const;
void createCallDialog(const Activity &callNotification);

Q_INVOKABLE void pauseResumeSync();
Q_INVOKABLE bool syncIsPaused();
Expand Down Expand Up @@ -120,6 +121,8 @@ private slots:
QPointer<QQmlApplicationEngine> _trayEngine;

AccessManagerFactory _accessManagerFactory;

QVector<qlonglong> _callsAlreadyNotified;
};

} // namespace OCC
Expand Down
13 changes: 0 additions & 13 deletions src/gui/tray/ActivityItem.qml
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,5 @@ MouseArea {

onTriggerAction: activityModel.slotTriggerAction(model.index, actionIndex)
}

Loader {
id: callNotificationLoader

function refresh() {
item.show();
}

active: isCallActivity
sourceComponent: CallNotificationDialog { }

onLoaded: refresh()
}
}
}
72 changes: 52 additions & 20 deletions src/gui/tray/CallNotificationDialog.qml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import com.nextcloud.desktopclient 1.0
import QtQuick.Layouts 1.2
import QtMultimedia 5.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15

Window {
id: root
color: "transparent"
flags: Qt.FramelessWindowHint
flags: Qt.Dialog | Qt.FramelessWindowHint

readonly property int windowMargins: 50
readonly property int windowWidth: 240
Expand All @@ -19,7 +20,11 @@ Window {
readonly property string talkIcon: svgImage.arg("wizard-talk")
readonly property string deleteIcon: svgImage.arg("delete")

readonly property variant links: model.links
// We set talkNotificationData, subject, and links properties in C++
property var talkNotificationData: ({})
property string subject: ""
property var links: []
property string link: ""

function closeNotification() {
ringSound.stop();
Expand All @@ -29,8 +34,14 @@ Window {
width: root.windowWidth
height: root.windowHeight

x: Screen.desktopAvailableWidth - root.windowWidth - root.windowMargins
y: Screen.desktopAvailableHeight - root.windowHeight - root.windowMargins
Component.onCompleted: {
Systray.forceWindowInit(root);
Systray.positionWindow(root);

root.show();
root.raise();
root.requestActivate();
}

Audio {
id: ringSound
Expand All @@ -50,28 +61,49 @@ Window {
ColumnLayout {
anchors.centerIn: parent
spacing: 10
Rectangle {
color: "blue"
Layout.fillHeight: true
Layout.fillWidth: true
}

Image {
id: callerAvatar
cache: false
Item {
width: Style.accountAvatarSize
height: Style.accountAvatarSize
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter

source: root.talkIcon + Style.ncBlue
sourceSize.width: Style.accountAvatarSize
sourceSize.height: Style.accountAvatarSize
Image {
id: callerAvatar
anchors.fill: parent
cache: true

property bool usingUserAvatar: root.talkNotificationData.userAvatar !== ""
source: usingUserAvatar ? root.talkNotificationData.userAvatar : root.talkIcon + Style.ncBlue
sourceSize.width: Style.accountAvatarSize
sourceSize.height: Style.accountAvatarSize

visible: !usingUserAvatar

Accessible.role: Accessible.Indicator
Accessible.name: qsTr("Talk notification caller avatar")
Accessible.role: Accessible.Indicator
Accessible.name: qsTr("Talk notification caller avatar")
}

Rectangle {
id: mask
color: "white"
radius: width * 0.5
anchors.fill: callerAvatar
visible: false
width: callerAvatar.paintedWidth
height: callerAvatar.paintedHeight
}

OpacityMask {
anchors.fill: callerAvatar
source: callerAvatar
maskSource: mask
visible: callerAvatar.usingUserAvatar
}
}

Text {
id: message
text: model.subject
text: root.subject
color: Style.ncTextColor
font.pixelSize: Style.topLinePixelSize
elide: Text.ElideRight
Expand All @@ -84,7 +116,7 @@ Window {

Repeater {
id: linksRepeater
model: links
model: root.links

CustomButton {
id: answerCall
Expand All @@ -106,7 +138,7 @@ Window {
Layout.preferredHeight: Style.callNotificationPrimaryButtonMinHeight

onClicked: {
activityModel.slotTriggerDefaultAction(model.index);
Qt.openUrlExternally(root.link);
root.closeNotification();
}

Expand Down
2 changes: 1 addition & 1 deletion src/gui/tray/activitydata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ OCC::Activity Activity::fromActivityJson(const QJsonObject json, const AccountPt
for (auto i = parameters.begin(); i != parameters.end(); ++i) {
const auto parameterJsonObject = i.value().toObject();

activity._subjectRichParameters[i.key()] = Activity::RichSubjectParameter {
activity._subjectRichParameters[i.key()] = RichSubjectParameter {
parameterJsonObject.value(QStringLiteral("type")).toString(),
parameterJsonObject.value(QStringLiteral("id")).toString(),
parameterJsonObject.value(QStringLiteral("name")).toString(),
Expand Down
81 changes: 67 additions & 14 deletions src/gui/tray/activitydata.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,40 @@ class PreviewData
QString _filename;
};

class RichSubjectParameter
{
Q_GADGET

Q_PROPERTY(QString type MEMBER type)
Q_PROPERTY(QString id MEMBER id)
Q_PROPERTY(QString name MEMBER name)
Q_PROPERTY(QString path MEMBER path)
Q_PROPERTY(QUrl link MEMBER link)

public:
QString type; // Required
QString id; // Required
QString name; // Required
QString path; // Required (for files only)
QUrl link; // Optional (files only)
};

class TalkNotificationData
{
Q_GADGET

Q_PROPERTY(QString conversationToken MEMBER conversationToken)
Q_PROPERTY(QString messageId MEMBER messageId)
Q_PROPERTY(QString messageSent MEMBER messageSent)
Q_PROPERTY(QString userAvatar MEMBER userAvatar)

public:
QString conversationToken;
QString messageId;
QString messageSent;
QString userAvatar;
};

/* ==================================================================== */
/**
* @brief Activity Structure
Expand All @@ -89,6 +123,33 @@ class PreviewData

class Activity
{
Q_GADGET

Q_PROPERTY(Type type MEMBER _type)
Q_PROPERTY(qlonglong id MEMBER _id)
Q_PROPERTY(QString fileAction MEMBER _fileAction)
Q_PROPERTY(int objectId MEMBER _objectId)
Q_PROPERTY(TalkNotificationData talkNotificationData READ talkNotificationData CONSTANT)
Q_PROPERTY(QString objectType MEMBER _objectType)
Q_PROPERTY(QString objectName MEMBER _objectName)
Q_PROPERTY(QString subject MEMBER _subject)
Q_PROPERTY(QString subjectRich MEMBER _subjectRich)
Q_PROPERTY(QString subjectDisplay MEMBER _subjectDisplay)
Q_PROPERTY(QString message MEMBER _message)
Q_PROPERTY(QString folder MEMBER _folder)
Q_PROPERTY(QString file MEMBER _file)
Q_PROPERTY(QString renamedFile MEMBER _renamedFile)
Q_PROPERTY(QUrl link MEMBER _link)
Q_PROPERTY(QDateTime dateTime MEMBER _dateTime)
Q_PROPERTY(qint64 expireAtMsecs MEMBER _expireAtMsecs)
Q_PROPERTY(QString accName MEMBER _accName)
Q_PROPERTY(QString darkIcon MEMBER _darkIcon)
Q_PROPERTY(QString lightIcon MEMBER _lightIcon)
Q_PROPERTY(bool isCurrentUserFileActivity MEMBER _isCurrentUserFileActivity)
Q_PROPERTY(QVector<PreviewData> previews READ previews CONSTANT)
Q_PROPERTY(int status MEMBER _status)
Q_PROPERTY(QVector<ActivityLink> links READ links CONSTANT)

public:
using Identifier = QPair<qlonglong, QString>;

Expand All @@ -98,23 +159,10 @@ class Activity
SyncResultType,
SyncFileItemType
};
Q_ENUM(Type);

static Activity fromActivityJson(const QJsonObject json, const AccountPtr account);

struct RichSubjectParameter {
QString type; // Required
QString id; // Required
QString name; // Required
QString path; // Required (for files only)
QUrl link; // Optional (files only)
};

struct TalkNotificationData {
QString conversationToken;
QString messageId;
QString messageSent;
};

Type _type;
qlonglong _id;
QString _fileAction;
Expand Down Expand Up @@ -151,6 +199,11 @@ class Activity


Identifier ident() const;

private:
TalkNotificationData talkNotificationData() { return _talkNotificationData; };
QVector<PreviewData> previews() { return _previews; };
QVector<ActivityLink> links() { return _links; };
};

bool operator==(const Activity &rhs, const Activity &lhs);
Expand Down
3 changes: 3 additions & 0 deletions src/gui/tray/activitylistmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ QHash<int, QByteArray> ActivityListModel::roleNames() const
roles[TalkNotificationConversationTokenRole] = "conversationToken";
roles[TalkNotificationMessageIdRole] = "messageId";
roles[TalkNotificationMessageSentRole] = "messageSent";
roles[TalkNotificationUserAvatarRole] = "userAvatar";

return roles;
}
Expand Down Expand Up @@ -332,6 +333,8 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
return a._talkNotificationData.messageId;
case TalkNotificationMessageSentRole:
return replyMessageSent(a);
case TalkNotificationUserAvatarRole:
return a._talkNotificationData.userAvatar;
default:
return QVariant();
}
Expand Down
1 change: 1 addition & 0 deletions src/gui/tray/activitylistmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class ActivityListModel : public QAbstractListModel
TalkNotificationConversationTokenRole,
TalkNotificationMessageIdRole,
TalkNotificationMessageSentRole,
TalkNotificationUserAvatarRole,
};
Q_ENUM(DataRole)

Expand Down
Loading

0 comments on commit 3576e51

Please sign in to comment.