Commit 9d056093 authored by Ronan Abhamon's avatar Ronan Abhamon

feat(src/components/notifier/Notifier): reworking, handle virtual desktops

parent d114d858
......@@ -320,7 +320,6 @@
<file>ui/modules/Linphone/Styles/Notifications/NotificationReceivedCallStyle.qml</file>
<file>ui/modules/Linphone/Styles/Notifications/NotificationReceivedFileMessageStyle.qml</file>
<file>ui/modules/Linphone/Styles/Notifications/NotificationReceivedMessageStyle.qml</file>
<file>ui/modules/Linphone/Styles/Notifications/NotificationStyle.qml</file>
<file>ui/modules/Linphone/Styles/qmldir</file>
<file>ui/modules/Linphone/Styles/SmartSearchBar/SmartSearchBarStyle.qml</file>
<file>ui/modules/Linphone/Styles/TelKeypad/TelKeypadStyle.qml</file>
......
......@@ -20,35 +20,53 @@
* Author: Ronan Abhamon
*/
#include <QQmlComponent>
#include <QQuickWindow>
#include <QScreen>
#include <QtDebug>
#include <QTimer>
#include "../../app/App.hpp"
#include "../../Utils.hpp"
#include "../core/CoreManager.hpp"
#include "Notifier.hpp"
#include <QQmlComponent>
#include <QQuickWindow>
#include <QtDebug>
#include <QTimer>
// -----------------------------------------------------------------------------
// Notifications QML properties/methods.
// -----------------------------------------------------------------------------
#define NOTIFICATION_SHOW_METHOD_NAME "show"
#define NOTIFICATION_PROPERTY_DATA "notificationData"
#define NOTIFICATION_PROPERTY_HEIGHT "notificationHeight"
#define NOTIFICATION_PROPERTY_OFFSET "notificationOffset"
#define NOTIFICATION_PROPERTY_X "popupX"
#define NOTIFICATION_PROPERTY_Y "popupY"
#define NOTIFICATION_PROPERTY_WINDOW "__internalWindow"
#define NOTIFICATION_PROPERTY_TIMER "__timer"
// -----------------------------------------------------------------------------
// Paths.
// -----------------------------------------------------------------------------
#define QML_NOTIFICATION_PATH_RECEIVED_MESSAGE "qrc:/ui/modules/Linphone/Notifications/NotificationReceivedMessage.qml"
#define QML_NOTIFICATION_PATH_RECEIVED_FILE_MESSAGE "qrc:/ui/modules/Linphone/Notifications/NotificationReceivedFileMessage.qml"
#define QML_NOTIFICATION_PATH_RECEIVED_CALL "qrc:/ui/modules/Linphone/Notifications/NotificationReceivedCall.qml"
// -----------------------------------------------------------------------------
// Timeouts.
// -----------------------------------------------------------------------------
#define NOTIFICATION_TIMEOUT_RECEIVED_MESSAGE 10000
#define NOTIFICATION_TIMEOUT_RECEIVED_FILE_MESSAGE 10000
#define NOTIFICATION_TIMEOUT_RECEIVED_CALL 30000
// -----------------------------------------------------------------------------
// Arbitrary hardcoded values.
// -----------------------------------------------------------------------------
#define NOTIFICATION_SPACING 10
#define N_MAX_NOTIFICATIONS 5
#define MAX_TIMEOUT 30000
......@@ -57,29 +75,25 @@ using namespace std;
// =============================================================================
inline int getNotificationSize (const QObject &object, const char *property) {
inline int getIntegerFromNotification (const QObject &object, const char *property) {
QVariant variant = object.property(property);
bool soFarSoGood;
int size = variant.toInt(&soFarSoGood);
if (!soFarSoGood || size < 0) {
qWarning() << "Unable to get notification size.";
return -1;
int value = variant.toInt(&soFarSoGood);
if (!soFarSoGood) {
qWarning() << QStringLiteral("Unable to get int from: `%1`.").arg(property);
abort();
}
return size;
return value;
}
template<class T>
bool setProperty (QObject &object, const char *property, const T &value) {
QVariant qvariant(value);
if (!object.setProperty(property, qvariant)) {
void setProperty (QObject &object, const char *property, const T &value) {
if (!object.setProperty(property, QVariant(value))) {
qWarning() << QStringLiteral("Unable to set property: `%1`.").arg(property);
return false;
abort();
}
return true;
}
// -----------------------------------------------------------------------------
......@@ -117,29 +131,46 @@ QObject *Notifier::createNotification (Notifier::NotificationType type) {
// Check existing instances.
if (mInstancesNumber == N_MAX_NOTIFICATIONS) {
qWarning() << "Unable to create another notification";
qWarning() << QStringLiteral("Unable to create another notification.");
mMutex.unlock();
return nullptr;
}
// Create instance and set attributes.
QObject *object = mComponents[type]->create();
int offset = getNotificationSize(*object, NOTIFICATION_PROPERTY_HEIGHT);
QObject *instance = mComponents[type]->create();
qInfo() << QStringLiteral("Create notification:") << instance;
if (offset == -1 || !::setProperty(*object, NOTIFICATION_PROPERTY_OFFSET, mOffset)) {
delete object;
mMutex.unlock();
return nullptr;
}
mOffset = (offset + mOffset) + NOTIFICATION_SPACING;
mInstancesNumber++;
{
QQuickWindow *window = instance->findChild<QQuickWindow *>(NOTIFICATION_PROPERTY_WINDOW);
Q_ASSERT(window != nullptr);
QScreen *screen = window->screen();
Q_ASSERT(screen != nullptr);
QRect geometry = screen->availableGeometry();
// Set X/Y. (Not Pokémon games.)
int windowHeight = window->height();
int offset = geometry.y() + geometry.height() - windowHeight;
::setProperty(*instance, NOTIFICATION_PROPERTY_X, geometry.x() + geometry.width() - window->width());
::setProperty(*instance, NOTIFICATION_PROPERTY_Y, offset - (mOffset % offset));
// Update offset.
mOffset = (windowHeight + mOffset) + NOTIFICATION_SPACING;
if (mOffset - offset + geometry.y() >= 0)
mOffset = 0;
}
mMutex.unlock();
return object;
return instance;
}
// -----------------------------------------------------------------------------
void Notifier::showNotification (QObject *notification, int timeout) {
// Display notification.
QMetaObject::invokeMethod(notification, NOTIFICATION_SHOW_METHOD_NAME, Qt::DirectConnection);
......@@ -175,7 +206,7 @@ void Notifier::deleteNotification (QVariant notification) {
return;
}
qDebug() << "Delete notification.";
qInfo() << QStringLiteral("Delete notification:") << instance;
instance->setProperty("__valid", true);
instance->property(NOTIFICATION_PROPERTY_TIMER).value<QTimer *>()->stop();
......@@ -191,7 +222,7 @@ void Notifier::deleteNotification (QVariant notification) {
instance->deleteLater();
}
// -----------------------------------------------------------------------------
// =============================================================================
void Notifier::notifyReceivedMessage (const shared_ptr<linphone::ChatMessage> &message) {
QObject *notification = createNotification(Notifier::MessageReceived);
......
......@@ -47,6 +47,9 @@ Item {
Window {
id: popup
// Used for internal purposes only. Like Notifications.
objectName: '__internalWindow'
flags: wrapper.flags
opacity: 0
height: _content[0] != null ? _content[0].height : 0
......
import QtQuick 2.7
// Warning: This import is necessary to use the attached property `Screen`.
// See: https://doc-snapshots.qt.io/qt5-5.7/qml-qtquick-window-screen.html
import QtQuick.Window 2.2
import Common 1.0
import Linphone.Styles 1.0
import Utils 1.0
// =============================================================================
DesktopPopup {
id: notification
// ---------------------------------------------------------------------------
property alias notificationHeight: notification.popupHeight
property int notificationOffset: 0
property var notificationData: ({})
readonly property var window: _window
property var _window
// ---------------------------------------------------------------------------
signal deleteNotification (var notification)
function _close (cb) {
......@@ -34,34 +19,5 @@ DesktopPopup {
deleteNotification(notification)
}
// ---------------------------------------------------------------------------
flags: Qt.Window | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
Component.onCompleted: {
var window = _window = data[0]
Utils.assert(
Utils.qmlTypeof(window, 'QQuickWindowQmlImpl'), true,
'Unable to found `Window` object in `DesktopPopup`.'
)
window.x = Qt.binding(function () {
var screen = window.Screen
return screen != null
? screen.width - window.width - NotificationStyle.margin
: 0
})
window.y = Qt.binding(function () {
var screen = window.Screen
if (screen == null) {
return 0
}
var height = screen.desktopAvailableHeight - window.height
return height - (notificationOffset % height)
})
}
flags: Qt.Tool | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
}
......@@ -15,12 +15,20 @@ TestCase {
compare(Utils.isObject(notification.notificationData), true)
}
function test_notificationHeightProperty () {
compare(Utils.isInteger(notification.notificationHeight), true)
function test_notificationPopupX () {
compare(Utils.isInteger(notification.popupX), true)
}
function test_notificationOffsetProperty () {
compare(Utils.isInteger(notification.notificationOffset), true)
function test_notificationPopupY () {
compare(Utils.isInteger(notification.popupY), true)
}
function test_notificationPopupHeight () {
compare(Utils.isInteger(notification.popupHeight), true)
}
function test_notificationPopupWidth () {
compare(Utils.isInteger(notification.popupWidth), true)
}
function test_notificationShowMethod () {
......@@ -28,6 +36,9 @@ TestCase {
}
function test_childWindow () {
compare(Utils.qmlTypeof(notification.data[0], 'QQuickWindowQmlImpl'), true)
var window = notification.data[0]
compare(Utils.qmlTypeof(window, 'QQuickWindowQmlImpl'), true)
compare(window.objectName === '__internalWindow', true)
}
}
pragma Singleton
import QtQuick 2.7
// =============================================================================
QtObject {
property int margin: 0
}
......@@ -24,7 +24,6 @@ singleton MessagesCounterStyle 1.0 Contact/MessagesCounterStyle.
singleton SipAddressesMenuStyle 1.0 Menus/SipAddressesMenuStyle.qml
singleton NotificationStyle 1.0 Notifications/NotificationStyle.qml
singleton NotificationReceivedCallStyle 1.0 Notifications/NotificationReceivedCallStyle.qml
singleton NotificationReceivedMessageStyle 1.0 Notifications/NotificationReceivedMessageStyle.qml
singleton NotificationReceivedFileMessageStyle 1.0 Notifications/NotificationReceivedFileMessageStyle.qml
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment