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 @@ ...@@ -320,7 +320,6 @@
<file>ui/modules/Linphone/Styles/Notifications/NotificationReceivedCallStyle.qml</file> <file>ui/modules/Linphone/Styles/Notifications/NotificationReceivedCallStyle.qml</file>
<file>ui/modules/Linphone/Styles/Notifications/NotificationReceivedFileMessageStyle.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/NotificationReceivedMessageStyle.qml</file>
<file>ui/modules/Linphone/Styles/Notifications/NotificationStyle.qml</file>
<file>ui/modules/Linphone/Styles/qmldir</file> <file>ui/modules/Linphone/Styles/qmldir</file>
<file>ui/modules/Linphone/Styles/SmartSearchBar/SmartSearchBarStyle.qml</file> <file>ui/modules/Linphone/Styles/SmartSearchBar/SmartSearchBarStyle.qml</file>
<file>ui/modules/Linphone/Styles/TelKeypad/TelKeypadStyle.qml</file> <file>ui/modules/Linphone/Styles/TelKeypad/TelKeypadStyle.qml</file>
......
...@@ -20,35 +20,53 @@ ...@@ -20,35 +20,53 @@
* Author: Ronan Abhamon * Author: Ronan Abhamon
*/ */
#include <QQmlComponent>
#include <QQuickWindow>
#include <QScreen>
#include <QtDebug>
#include <QTimer>
#include "../../app/App.hpp" #include "../../app/App.hpp"
#include "../../Utils.hpp" #include "../../Utils.hpp"
#include "../core/CoreManager.hpp" #include "../core/CoreManager.hpp"
#include "Notifier.hpp" #include "Notifier.hpp"
#include <QQmlComponent> // -----------------------------------------------------------------------------
#include <QQuickWindow>
#include <QtDebug>
#include <QTimer>
// Notifications QML properties/methods. // Notifications QML properties/methods.
// -----------------------------------------------------------------------------
#define NOTIFICATION_SHOW_METHOD_NAME "show" #define NOTIFICATION_SHOW_METHOD_NAME "show"
#define NOTIFICATION_PROPERTY_DATA "notificationData" #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" #define NOTIFICATION_PROPERTY_TIMER "__timer"
// -----------------------------------------------------------------------------
// Paths.
// -----------------------------------------------------------------------------
#define QML_NOTIFICATION_PATH_RECEIVED_MESSAGE "qrc:/ui/modules/Linphone/Notifications/NotificationReceivedMessage.qml" #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_FILE_MESSAGE "qrc:/ui/modules/Linphone/Notifications/NotificationReceivedFileMessage.qml"
#define QML_NOTIFICATION_PATH_RECEIVED_CALL "qrc:/ui/modules/Linphone/Notifications/NotificationReceivedCall.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_MESSAGE 10000
#define NOTIFICATION_TIMEOUT_RECEIVED_FILE_MESSAGE 10000 #define NOTIFICATION_TIMEOUT_RECEIVED_FILE_MESSAGE 10000
#define NOTIFICATION_TIMEOUT_RECEIVED_CALL 30000 #define NOTIFICATION_TIMEOUT_RECEIVED_CALL 30000
// -----------------------------------------------------------------------------
// Arbitrary hardcoded values. // Arbitrary hardcoded values.
// -----------------------------------------------------------------------------
#define NOTIFICATION_SPACING 10 #define NOTIFICATION_SPACING 10
#define N_MAX_NOTIFICATIONS 5 #define N_MAX_NOTIFICATIONS 5
#define MAX_TIMEOUT 30000 #define MAX_TIMEOUT 30000
...@@ -57,29 +75,25 @@ using namespace std; ...@@ -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); QVariant variant = object.property(property);
bool soFarSoGood; bool soFarSoGood;
int size = variant.toInt(&soFarSoGood); int value = variant.toInt(&soFarSoGood);
if (!soFarSoGood || size < 0) { if (!soFarSoGood) {
qWarning() << "Unable to get notification size."; qWarning() << QStringLiteral("Unable to get int from: `%1`.").arg(property);
return -1; abort();
} }
return size; return value;
} }
template<class T> template<class T>
bool setProperty (QObject &object, const char *property, const T &value) { void setProperty (QObject &object, const char *property, const T &value) {
QVariant qvariant(value); if (!object.setProperty(property, QVariant(value))) {
if (!object.setProperty(property, qvariant)) {
qWarning() << QStringLiteral("Unable to set property: `%1`.").arg(property); qWarning() << QStringLiteral("Unable to set property: `%1`.").arg(property);
return false; abort();
} }
return true;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -117,29 +131,46 @@ QObject *Notifier::createNotification (Notifier::NotificationType type) { ...@@ -117,29 +131,46 @@ QObject *Notifier::createNotification (Notifier::NotificationType type) {
// Check existing instances. // Check existing instances.
if (mInstancesNumber == N_MAX_NOTIFICATIONS) { if (mInstancesNumber == N_MAX_NOTIFICATIONS) {
qWarning() << "Unable to create another notification"; qWarning() << QStringLiteral("Unable to create another notification.");
mMutex.unlock(); mMutex.unlock();
return nullptr; return nullptr;
} }
// Create instance and set attributes. // Create instance and set attributes.
QObject *object = mComponents[type]->create(); QObject *instance = mComponents[type]->create();
int offset = getNotificationSize(*object, NOTIFICATION_PROPERTY_HEIGHT); 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++; 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(); mMutex.unlock();
return object; return instance;
} }
// -----------------------------------------------------------------------------
void Notifier::showNotification (QObject *notification, int timeout) { void Notifier::showNotification (QObject *notification, int timeout) {
// Display notification. // Display notification.
QMetaObject::invokeMethod(notification, NOTIFICATION_SHOW_METHOD_NAME, Qt::DirectConnection); QMetaObject::invokeMethod(notification, NOTIFICATION_SHOW_METHOD_NAME, Qt::DirectConnection);
...@@ -175,7 +206,7 @@ void Notifier::deleteNotification (QVariant notification) { ...@@ -175,7 +206,7 @@ void Notifier::deleteNotification (QVariant notification) {
return; return;
} }
qDebug() << "Delete notification."; qInfo() << QStringLiteral("Delete notification:") << instance;
instance->setProperty("__valid", true); instance->setProperty("__valid", true);
instance->property(NOTIFICATION_PROPERTY_TIMER).value<QTimer *>()->stop(); instance->property(NOTIFICATION_PROPERTY_TIMER).value<QTimer *>()->stop();
...@@ -191,7 +222,7 @@ void Notifier::deleteNotification (QVariant notification) { ...@@ -191,7 +222,7 @@ void Notifier::deleteNotification (QVariant notification) {
instance->deleteLater(); instance->deleteLater();
} }
// ----------------------------------------------------------------------------- // =============================================================================
void Notifier::notifyReceivedMessage (const shared_ptr<linphone::ChatMessage> &message) { void Notifier::notifyReceivedMessage (const shared_ptr<linphone::ChatMessage> &message) {
QObject *notification = createNotification(Notifier::MessageReceived); QObject *notification = createNotification(Notifier::MessageReceived);
......
...@@ -47,6 +47,9 @@ Item { ...@@ -47,6 +47,9 @@ Item {
Window { Window {
id: popup id: popup
// Used for internal purposes only. Like Notifications.
objectName: '__internalWindow'
flags: wrapper.flags flags: wrapper.flags
opacity: 0 opacity: 0
height: _content[0] != null ? _content[0].height : 0 height: _content[0] != null ? _content[0].height : 0
......
import QtQuick 2.7 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 Common 1.0
import Linphone.Styles 1.0
import Utils 1.0
// ============================================================================= // =============================================================================
DesktopPopup { DesktopPopup {
id: notification id: notification
// ---------------------------------------------------------------------------
property alias notificationHeight: notification.popupHeight
property int notificationOffset: 0
property var notificationData: ({}) property var notificationData: ({})
readonly property var window: _window
property var _window
// ---------------------------------------------------------------------------
signal deleteNotification (var notification) signal deleteNotification (var notification)
function _close (cb) { function _close (cb) {
...@@ -34,34 +19,5 @@ DesktopPopup { ...@@ -34,34 +19,5 @@ DesktopPopup {
deleteNotification(notification) deleteNotification(notification)
} }
// --------------------------------------------------------------------------- flags: Qt.Tool | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
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)
})
}
} }
...@@ -15,12 +15,20 @@ TestCase { ...@@ -15,12 +15,20 @@ TestCase {
compare(Utils.isObject(notification.notificationData), true) compare(Utils.isObject(notification.notificationData), true)
} }
function test_notificationHeightProperty () { function test_notificationPopupX () {
compare(Utils.isInteger(notification.notificationHeight), true) compare(Utils.isInteger(notification.popupX), true)
} }
function test_notificationOffsetProperty () { function test_notificationPopupY () {
compare(Utils.isInteger(notification.notificationOffset), true) 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 () { function test_notificationShowMethod () {
...@@ -28,6 +36,9 @@ TestCase { ...@@ -28,6 +36,9 @@ TestCase {
} }
function test_childWindow () { 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. ...@@ -24,7 +24,6 @@ singleton MessagesCounterStyle 1.0 Contact/MessagesCounterStyle.
singleton SipAddressesMenuStyle 1.0 Menus/SipAddressesMenuStyle.qml singleton SipAddressesMenuStyle 1.0 Menus/SipAddressesMenuStyle.qml
singleton NotificationStyle 1.0 Notifications/NotificationStyle.qml
singleton NotificationReceivedCallStyle 1.0 Notifications/NotificationReceivedCallStyle.qml singleton NotificationReceivedCallStyle 1.0 Notifications/NotificationReceivedCallStyle.qml
singleton NotificationReceivedMessageStyle 1.0 Notifications/NotificationReceivedMessageStyle.qml singleton NotificationReceivedMessageStyle 1.0 Notifications/NotificationReceivedMessageStyle.qml
singleton NotificationReceivedFileMessageStyle 1.0 Notifications/NotificationReceivedFileMessageStyle.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