Commit 2b5cb6bc authored by Ronan Abhamon's avatar Ronan Abhamon

feat(src/components/notifier/Notifier): supports messages & calls notifications

parent 40ee4028
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 41 (35326) - http://www.bohemiancoding.com/sketch -->
<title>call_in_sign</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="call_in_sign">
<polygon fill="#FF5E00" points="0 0 40 0 0 40"></polygon>
<path d="M11.243716,8.71501414 L11.1871835,8.71501414 C8.47215269,8.71501414 5.21235367,10.3895588 4.11804501,12.8152126 L4.51732144,15.956733 L8.01512006,15.956733 L8.2626641,12.830113 L14.1683578,12.830113 L14.41529,15.956733 L17.9130886,15.956733 L18.3123651,12.8149535 C17.2174446,10.3886518 13.9583798,8.71501414 11.243716,8.71501414 Z" fill="#FFFFFF" transform="translate(11.215205, 12.335874) rotate(-135.000000) translate(-11.215205, -12.335874) "></path>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 41 (35326) - http://www.bohemiancoding.com/sketch -->
<title>call_in_sign</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="call_in_sign">
<polygon fill="#FF5E00" points="0 0 40 0 0 40"></polygon>
<path d="M11.243716,8.71501414 L11.1871835,8.71501414 C8.47215269,8.71501414 5.21235367,10.3895588 4.11804501,12.8152126 L4.51732144,15.956733 L8.01512006,15.956733 L8.2626641,12.830113 L14.1683578,12.830113 L14.41529,15.956733 L17.9130886,15.956733 L18.3123651,12.8149535 C17.2174446,10.3886518 13.9583798,8.71501414 11.243716,8.71501414 Z" fill="#FFFFFF" transform="translate(11.215205, 12.335874) rotate(-135.000000) translate(-11.215205, -12.335874) "></path>
</g>
</g>
</svg>
\ No newline at end of file
...@@ -78,6 +78,7 @@ ...@@ -78,6 +78,7 @@
<file>assets/images/edit_normal.svg</file> <file>assets/images/edit_normal.svg</file>
<file>assets/images/edit_pressed.svg</file> <file>assets/images/edit_pressed.svg</file>
<file>assets/images/ended_call.svg</file> <file>assets/images/ended_call.svg</file>
<file>assets/images/file_sign.svg</file>
<file>assets/images/filter.svg</file> <file>assets/images/filter.svg</file>
<file>assets/images/fullscreen_hovered.svg</file> <file>assets/images/fullscreen_hovered.svg</file>
<file>assets/images/fullscreen_normal.svg</file> <file>assets/images/fullscreen_normal.svg</file>
...@@ -101,6 +102,7 @@ ...@@ -101,6 +102,7 @@
<file>assets/images/led_red.svg</file> <file>assets/images/led_red.svg</file>
<file>assets/images/led_white.svg</file> <file>assets/images/led_white.svg</file>
<file>assets/images/linphone.png</file> <file>assets/images/linphone.png</file>
<file>assets/images/message_sign.svg</file>
<file>assets/images/micro_off_hovered.svg</file> <file>assets/images/micro_off_hovered.svg</file>
<file>assets/images/micro_off_normal.svg</file> <file>assets/images/micro_off_normal.svg</file>
<file>assets/images/micro_off_pressed.svg</file> <file>assets/images/micro_off_pressed.svg</file>
...@@ -228,9 +230,10 @@ ...@@ -228,9 +230,10 @@
<file>ui/modules/Linphone/Contact/ContactDescription.qml</file> <file>ui/modules/Linphone/Contact/ContactDescription.qml</file>
<file>ui/modules/Linphone/Contact/Contact.qml</file> <file>ui/modules/Linphone/Contact/Contact.qml</file>
<file>ui/modules/Linphone/Contact/MessagesCounter.qml</file> <file>ui/modules/Linphone/Contact/MessagesCounter.qml</file>
<file>ui/modules/Linphone/Notifications/CallNotification.qml</file>
<file>ui/modules/Linphone/Notifications/Notification.qml</file> <file>ui/modules/Linphone/Notifications/Notification.qml</file>
<file>ui/modules/Linphone/Notifications/ReceivedMessageNotification.qml</file> <file>ui/modules/Linphone/Notifications/NotificationReceivedCall.qml</file>
<file>ui/modules/Linphone/Notifications/NotificationReceivedFileMessage.qml</file>
<file>ui/modules/Linphone/Notifications/NotificationReceivedMessage.qml</file>
<file>ui/modules/Linphone/Presence/PresenceLevel.qml</file> <file>ui/modules/Linphone/Presence/PresenceLevel.qml</file>
<file>ui/modules/Linphone/Presence/PresenceString.qml</file> <file>ui/modules/Linphone/Presence/PresenceString.qml</file>
<file>ui/modules/Linphone/qmldir</file> <file>ui/modules/Linphone/qmldir</file>
...@@ -243,7 +246,10 @@ ...@@ -243,7 +246,10 @@
<file>ui/modules/Linphone/Styles/Contact/ContactDescriptionStyle.qml</file> <file>ui/modules/Linphone/Styles/Contact/ContactDescriptionStyle.qml</file>
<file>ui/modules/Linphone/Styles/Contact/ContactStyle.qml</file> <file>ui/modules/Linphone/Styles/Contact/ContactStyle.qml</file>
<file>ui/modules/Linphone/Styles/Contact/MessagesCounterStyle.qml</file> <file>ui/modules/Linphone/Styles/Contact/MessagesCounterStyle.qml</file>
<file>ui/modules/Linphone/Styles/NotificationStyle.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/NotificationReceivedMessageStyle.qml</file>
<file>ui/modules/Linphone/Styles/Notifications/NotificationStyle.qml</file>
<file>ui/modules/Linphone/Styles/Presence/PresenceStringStyle.qml</file> <file>ui/modules/Linphone/Styles/Presence/PresenceStringStyle.qml</file>
<file>ui/modules/Linphone/Styles/qmldir</file> <file>ui/modules/Linphone/Styles/qmldir</file>
<file>ui/modules/Linphone/Styles/SmartSearchBarStyle.qml</file> <file>ui/modules/Linphone/Styles/SmartSearchBarStyle.qml</file>
......
...@@ -92,10 +92,13 @@ QQuickWindow *App::getCallsWindow () const { ...@@ -92,10 +92,13 @@ QQuickWindow *App::getCallsWindow () const {
return window; return window;
} }
bool App::hasFocus () const { QQuickWindow *App::getMainWindow () const {
QQmlApplicationEngine &engine = const_cast<QQmlApplicationEngine &>(m_engine); QQmlApplicationEngine &engine = const_cast<QQmlApplicationEngine &>(m_engine);
const QQuickWindow *root = qobject_cast<QQuickWindow *>(engine.rootObjects().at(0)); return qobject_cast<QQuickWindow *>(engine.rootObjects().at(0));
return !!root->activeFocusItem(); }
bool App::hasFocus () const {
return getMainWindow()->isActive() || getCallsWindow()->isActive();
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -109,6 +112,9 @@ void App::initContentApp () { ...@@ -109,6 +112,9 @@ void App::initContentApp () {
registerTypes(); registerTypes();
addContextProperties(); addContextProperties();
// Enable notifications.
m_notifier = new Notifier();
CoreManager::getInstance()->enableHandlers(); CoreManager::getInstance()->enableHandlers();
// Load main view. // Load main view.
...@@ -167,7 +173,7 @@ void App::registerTypes () { ...@@ -167,7 +173,7 @@ void App::registerTypes () {
qmlRegisterSingletonType<CallsListModel>( qmlRegisterSingletonType<CallsListModel>(
"Linphone", 1, 0, "CallsListModel", "Linphone", 1, 0, "CallsListModel",
[](QQmlEngine *, QJSEngine *) -> QObject *{ [](QQmlEngine *, QJSEngine *) -> QObject *{
return new CallsListModel(); return CoreManager::getInstance()->getCallsListModel();
} }
); );
...@@ -219,13 +225,10 @@ void App::addContextProperties () { ...@@ -219,13 +225,10 @@ void App::addContextProperties () {
} }
context->setContextProperty("CallsWindow", component.create()); context->setContextProperty("CallsWindow", component.create());
m_notifier = new Notifier();
context->setContextProperty("Notifier", m_notifier);
} }
void App::setTrayIcon () { void App::setTrayIcon () {
QQuickWindow *root = qobject_cast<QQuickWindow *>(m_engine.rootObjects().at(0)); QQuickWindow *root = getMainWindow();
QMenu *menu = new QMenu(); QMenu *menu = new QMenu();
m_system_tray_icon = new QSystemTrayIcon(root); m_system_tray_icon = new QSystemTrayIcon(root);
......
...@@ -49,6 +49,7 @@ public: ...@@ -49,6 +49,7 @@ public:
} }
QQuickWindow *getCallsWindow () const; QQuickWindow *getCallsWindow () const;
QQuickWindow *getMainWindow () const;
bool hasFocus () const; bool hasFocus () const;
......
...@@ -226,18 +226,15 @@ float CallModel::getQuality () const { ...@@ -226,18 +226,15 @@ float CallModel::getQuality () const {
} }
bool CallModel::getMicroMuted () const { bool CallModel::getMicroMuted () const {
return m_micro_muted; return !CoreManager::getInstance()->getCore()->micEnabled();
} }
void CallModel::setMicroMuted (bool status) { void CallModel::setMicroMuted (bool status) {
if (m_micro_muted != status) { shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
m_micro_muted = status;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
if (m_micro_muted == core->micEnabled())
core->enableMic(!m_micro_muted);
emit microMutedChanged(m_micro_muted); if (status != core->micEnabled()) {
core->enableMic(!status);
emit microMutedChanged(status);
} }
} }
......
...@@ -109,7 +109,6 @@ private: ...@@ -109,7 +109,6 @@ private:
bool getRecording () const; bool getRecording () const;
bool m_micro_muted = false;
bool m_paused_by_remote = false; bool m_paused_by_remote = false;
bool m_paused_by_user = false; bool m_paused_by_user = false;
bool m_recording = false; bool m_recording = false;
......
...@@ -81,6 +81,16 @@ QVariant CallsListModel::data (const QModelIndex &index, int role) const { ...@@ -81,6 +81,16 @@ QVariant CallsListModel::data (const QModelIndex &index, int role) const {
return QVariant(); return QVariant();
} }
CallModel *CallsListModel::getCall (const shared_ptr<linphone::Call> &linphone_call) const {
auto it = find_if(
m_list.begin(), m_list.end(), [linphone_call](CallModel *call) {
return linphone_call == call->getLinphoneCall();
}
);
return it != m_list.end() ? *it : nullptr;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void CallsListModel::launchAudioCall (const QString &sip_uri) const { void CallsListModel::launchAudioCall (const QString &sip_uri) const {
......
...@@ -43,6 +43,8 @@ public: ...@@ -43,6 +43,8 @@ public:
QHash<int, QByteArray> roleNames () const override; QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
CallModel *getCall (const std::shared_ptr<linphone::Call> &linphone_call) const;
Q_INVOKABLE void launchAudioCall (const QString &sip_uri) const; Q_INVOKABLE void launchAudioCall (const QString &sip_uri) const;
Q_INVOKABLE void launchVideoCall (const QString &sip_uri) const; Q_INVOKABLE void launchVideoCall (const QString &sip_uri) const;
......
#include <QOpenGLFunctions> /*
* MSFunctions.cpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: February 9, 2017
* Author: Ronan Abhamon
*/
#include "MSFunctions.hpp"
// Do not include this header before `QOpenGLFunctions`!!! // Do not include this header before `QOpenGLFunctions`!!!
#include <mediastreamer2/msogl.h> #include <mediastreamer2/msogl.h>
#include "MSFunctions.hpp"
// ============================================================================= // =============================================================================
MSFunctions *MSFunctions::m_instance = nullptr; MSFunctions *MSFunctions::m_instance = nullptr;
......
/*
* MSFunctions.hpp
* Copyright (C) 2017 Belledonne Communications, Grenoble, France
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Created on: February 9, 2017
* Author: Ronan Abhamon
*/
#ifndef MS_FUNCTIONS_H_ #ifndef MS_FUNCTIONS_H_
#define MS_FUNCTIONS_H_ #define MS_FUNCTIONS_H_
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <QTimer> #include <QTimer>
#include <QUuid> #include <QUuid>
#include "../../app/App.hpp"
#include "../../app/Paths.hpp" #include "../../app/Paths.hpp"
#include "../../app/ThumbnailProvider.hpp" #include "../../app/ThumbnailProvider.hpp"
#include "../../utils.hpp" #include "../../utils.hpp"
...@@ -150,9 +151,11 @@ private: ...@@ -150,9 +151,11 @@ private:
if (it == m_chat_model->m_entries.end()) if (it == m_chat_model->m_entries.end())
return; return;
// File message downloaded.
if (state == linphone::ChatMessageStateFileTransferDone && !message->isOutgoing()) { if (state == linphone::ChatMessageStateFileTransferDone && !message->isOutgoing()) {
createThumbnail(message); createThumbnail(message);
fillThumbnailProperty((*it).first, message); fillThumbnailProperty((*it).first, message);
App::getInstance()->getNotifier()->notifyReceivedFileMessage(message);
} }
(*it).first["status"] = state; (*it).first["status"] = state;
......
...@@ -46,16 +46,19 @@ void CoreHandlers::onCallStateChanged ( ...@@ -46,16 +46,19 @@ void CoreHandlers::onCallStateChanged (
const string & const string &
) { ) {
emit callStateChanged(call, state); emit callStateChanged(call, state);
if (call->getState() == linphone::CallStateIncomingReceived)
App::getInstance()->getNotifier()->notifyReceivedCall(call);
} }
void CoreHandlers::onMessageReceived ( void CoreHandlers::onMessageReceived (
const shared_ptr<linphone::Core> &, const shared_ptr<linphone::Core> &,
const shared_ptr<linphone::ChatRoom> &room, const shared_ptr<linphone::ChatRoom> &,
const shared_ptr<linphone::ChatMessage> &message const shared_ptr<linphone::ChatMessage> &message
) { ) {
emit messageReceived(message); emit messageReceived(message);
const App *app = App::getInstance(); const App *app = App::getInstance();
if (!app->hasFocus()) if (!app->hasFocus())
app->getNotifier()->notifyReceivedMessage(10000, room, message); app->getNotifier()->notifyReceivedMessage(message);
} }
...@@ -49,6 +49,7 @@ void CoreManager::init () { ...@@ -49,6 +49,7 @@ void CoreManager::init () {
if (!m_instance) { if (!m_instance) {
m_instance = new CoreManager(); m_instance = new CoreManager();
m_instance->m_calls_list_model = new CallsListModel(m_instance);
m_instance->m_contacts_list_model = new ContactsListModel(m_instance); m_instance->m_contacts_list_model = new ContactsListModel(m_instance);
m_instance->m_sip_addresses_model = new SipAddressesModel(m_instance); m_instance->m_sip_addresses_model = new SipAddressesModel(m_instance);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#ifndef CORE_MANAGER_H_ #ifndef CORE_MANAGER_H_
#define CORE_MANAGER_H_ #define CORE_MANAGER_H_
#include "../calls/CallsListModel.hpp"
#include "../contacts/ContactsListModel.hpp" #include "../contacts/ContactsListModel.hpp"
#include "../sip-addresses/SipAddressesModel.hpp" #include "../sip-addresses/SipAddressesModel.hpp"
#include "CoreHandlers.hpp" #include "CoreHandlers.hpp"
...@@ -51,6 +52,10 @@ public: ...@@ -51,6 +52,10 @@ public:
// Singleton models. // Singleton models.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
CallsListModel *getCallsListModel () const {
return m_calls_list_model;
}
ContactsListModel *getContactsListModel () const { ContactsListModel *getContactsListModel () const {
return m_contacts_list_model; return m_contacts_list_model;
} }
...@@ -83,6 +88,7 @@ private: ...@@ -83,6 +88,7 @@ private:
std::shared_ptr<linphone::Core> m_core; std::shared_ptr<linphone::Core> m_core;
std::shared_ptr<CoreHandlers> m_handlers; std::shared_ptr<CoreHandlers> m_handlers;
CallsListModel *m_calls_list_model;
ContactsListModel *m_contacts_list_model; ContactsListModel *m_contacts_list_model;
SipAddressesModel *m_sip_addresses_model; SipAddressesModel *m_sip_addresses_model;
......
...@@ -20,23 +20,31 @@ ...@@ -20,23 +20,31 @@
* Author: Ronan Abhamon * Author: Ronan Abhamon
*/ */
#include "../../app/App.hpp"
#include "Notifier.hpp"
#include <QQmlComponent> #include <QQmlComponent>
#include <QQuickWindow> #include <QQuickWindow>
#include <QtDebug> #include <QtDebug>
#include <QTimer> #include <QTimer>
#include "../../app/App.hpp"
#include "../../utils.hpp"
#include "../core/CoreManager.hpp"
#include "Notifier.hpp"
// Notifications QML properties/methods. // Notifications QML properties/methods.
#define NOTIFICATION_SHOW_METHOD_NAME "show" #define NOTIFICATION_SHOW_METHOD_NAME "show"
#define NOTIFICATION_HEIGHT_PROPERTY "notificationHeight" #define NOTIFICATION_PROPERTY_DATA "notificationData"
#define NOTIFICATION_OFFSET_PROPERTY_NAME "notificationOffset" #define NOTIFICATION_PROPERTY_HEIGHT "notificationHeight"
#define NOTIFICATION_PROPERTY_OFFSET "notificationOffset"
#define QML_CALL_NOTIFICATION_PATH "qrc:/ui/modules/Linphone/Notifications/CallNotification.qml" #define QML_NOTIFICATION_PATH_RECEIVED_MESSAGE "qrc:/ui/modules/Linphone/Notifications/NotificationReceivedMessage.qml"
#define QML_MESSAGE_RECEIVED_NOTIFICATION_PATH "qrc:/ui/modules/Linphone/Notifications/ReceivedMessageNotification.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 NOTIFICATION_TIMEOUT_RECEIVED_MESSAGE 10000
#define NOTIFICATION_TIMEOUT_RECEIVED_FILE_MESSAGE 10000
#define NOTIFICATION_TIMEOUT_RECEIVED_CALL 10000
// Arbitrary hardcoded values. // Arbitrary hardcoded values.
#define NOTIFICATION_SPACING 10 #define NOTIFICATION_SPACING 10
...@@ -77,22 +85,22 @@ Notifier::Notifier (QObject *parent) : ...@@ -77,22 +85,22 @@ Notifier::Notifier (QObject *parent) :
QQmlEngine *engine = App::getInstance()->getEngine(); QQmlEngine *engine = App::getInstance()->getEngine();
// Build components. // Build components.
m_components[Notifier::Call] = new QQmlComponent(engine, QUrl(QML_CALL_NOTIFICATION_PATH)); m_components[Notifier::MessageReceived] = new QQmlComponent(engine, QUrl(QML_NOTIFICATION_PATH_RECEIVED_MESSAGE));
m_components[Notifier::MessageReceived] = new QQmlComponent(engine, QUrl(QML_MESSAGE_RECEIVED_NOTIFICATION_PATH)); m_components[Notifier::FileMessageReceived] = new QQmlComponent(engine, QUrl(QML_NOTIFICATION_PATH_RECEIVED_FILE_MESSAGE));
m_components[Notifier::CallReceived] = new QQmlComponent(engine, QUrl(QML_NOTIFICATION_PATH_RECEIVED_CALL));
// Check errors. // Check errors.
for (int i = 0; i < Notifier::MaxNbTypes; ++i) { for (int i = 0; i < Notifier::MaxNbTypes; ++i) {
QQmlComponent *component = m_components[i]; QQmlComponent *component = m_components[i];
if (component->isError()) { if (component->isError()) {
qWarning() << QStringLiteral("Errors found in `Notification` component %1:").arg(i) << qWarning() << QStringLiteral("Errors found in `Notification` component %1:").arg(i) << component->errors();
component->errors();
abort(); abort();
} }
} }
} }
Notifier::~Notifier () { Notifier::~Notifier () {
for (int i = 0; i < Notifier::MaxNbTypes; i++) for (int i = 0; i < Notifier::MaxNbTypes; ++i)
delete m_components[i]; delete m_components[i];
} }
...@@ -110,9 +118,9 @@ QObject *Notifier::createNotification (Notifier::NotificationType type) { ...@@ -110,9 +118,9 @@ QObject *Notifier::createNotification (Notifier::NotificationType type) {
// Create instance and set attributes. // Create instance and set attributes.
QObject *object = m_components[type]->create(); QObject *object = m_components[type]->create();
int offset = getNotificationSize(*object, NOTIFICATION_HEIGHT_PROPERTY); int offset = getNotificationSize(*object, NOTIFICATION_PROPERTY_HEIGHT);
if (offset == -1 || !::setProperty(*object, NOTIFICATION_OFFSET_PROPERTY_NAME, m_offset)) { if (offset == -1 || !::setProperty(*object, NOTIFICATION_PROPERTY_OFFSET, m_offset)) {
delete object; delete object;
m_mutex.unlock(); m_mutex.unlock();
return nullptr; return nullptr;
...@@ -149,7 +157,7 @@ void Notifier::showNotification (QObject *notification, int timeout) { ...@@ -149,7 +157,7 @@ void Notifier::showNotification (QObject *notification, int timeout) {
qInfo() << "Update notifications counter, hidden notification detected."; qInfo() << "Update notifications counter, hidden notification detected.";
if (visible) if (visible)
qFatal("A notification cannot be visible twice!"); qWarning("A notification cannot be visible twice!");
m_mutex.lock(); m_mutex.lock();
...@@ -172,20 +180,41 @@ void Notifier::showNotification (QObject *notification, int timeout) { ...@@ -172,20 +180,41 @@ void Notifier::showNotification (QObject *notification, int timeout) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void Notifier::notifyReceivedMessage ( void Notifier::notifyReceivedMessage (const shared_ptr<linphone::ChatMessage> &message) {
int timeout, QObject *notification = createNotification(Notifier::MessageReceived);
const shared_ptr<linphone::ChatRoom> &room, if (!notification)
const shared_ptr<linphone::ChatMessage> &message return;
) {
QObject *object = createNotification(Notifier::MessageReceived); QVariantMap map;
map["message"] = ::Utils::linphoneStringToQString(message->getText());
map["sipAddress"] = ::Utils::linphoneStringToQString(message->getFromAddress()->asStringUriOnly());
map["window"].setValue(App::getInstance()->getMainWindow());
if (object) ::setProperty(*notification, NOTIFICATION_PROPERTY_DATA, map);
showNotification(object, timeout); showNotification(notification, NOTIFICATION_TIMEOUT_RECEIVED_MESSAGE);
} }
void Notifier::showCallMessage (int timeout, const QString &) { void Notifier::notifyReceivedFileMessage (const shared_ptr<linphone::ChatMessage> &message) {
QObject *object = createNotification(Notifier::Call); QObject *notification = createNotification(Notifier::FileMessageReceived);
if (!notification)
return;
QVariantMap map;
map["fileUri"] = ::Utils::linphoneStringToQString(message->getFileTransferFilepath());
map["fileSize"] = static_cast<quint64>(message->getFileTransferInformation()->getSize());
::setProperty(*notification, NOTIFICATION_PROPERTY_DATA, map);
showNotification(notification, NOTIFICATION_TIMEOUT_RECEIVED_FILE_MESSAGE);
}
void Notifier::notifyReceivedCall (const shared_ptr<linphone::Call> &call) {
QObject *notification = createNotification(Notifier::CallReceived);
if (!notification)
return;
QVariantMap map;
map["call"].setValue(CoreManager::getInstance()->getCallsListModel()->getCall(call));
if (object) ::setProperty(*notification, NOTIFICATION_PROPERTY_DATA, map);
showNotification(object, timeout); showNotification(notification, NOTIFICATION_TIMEOUT_RECEIVED_CALL);
} }
...@@ -40,19 +40,15 @@ public: ...@@ -40,19 +40,15 @@ public:
~Notifier (); ~Notifier ();
enum NotificationType { enum NotificationType {
Call,
MessageReceived, MessageReceived,
FileMessageReceived,
CallReceived,
MaxNbTypes MaxNbTypes
}; };
void notifyReceivedMessage ( void notifyReceivedMessage (const std::shared_ptr<linphone::ChatMessage> &message);
int timeout, void notifyReceivedFileMessage (const std::shared_ptr<linphone::ChatMessage> &message);
const std::shared_ptr<linphone::ChatRoom> &room, void notifyReceivedCall (const std::shared_ptr<linphone::Call> &call);
const std::shared_ptr<linphone::ChatMessage> &message
);
// TODO
void showCallMessage (int timeout, const QString &);
private: private:
QObject *createNotification (NotificationType type); QObject *createNotification (NotificationType type);
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
int main (int argc, char *argv[]) { int main (int argc, char *argv[]) {
Logger::init(); Logger::init();
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true);
// Force shader version 2.0. // Force shader version 2.0.
QSurfaceFormat fmt; QSurfaceFormat fmt;
fmt.setVersion(2, 0); fmt.setVersion(2, 0);
......
...@@ -77,7 +77,10 @@ Item { ...@@ -77,7 +77,10 @@ Item {
to: 'opened' to: 'opened'
ScriptAction { ScriptAction {
script: popup.showNormal() script: {
popup.showNormal()
popup.requestActivate()
}
} }
NumberAnimation { NumberAnimation {
......
...@@ -23,8 +23,10 @@ Item { ...@@ -23,8 +23,10 @@ Item {
iconSize: MessagesCounterStyle.iconSize.message iconSize: MessagesCounterStyle.iconSize.message
Icon { Icon {
anchors.horizontalCenter: parent.right anchors {
anchors.verticalCenter: parent.bottom horizontalCenter: parent.right
verticalCenter: parent.bottom
}
icon: 'chat_amount' icon: 'chat_amount'
iconSize: MessagesCounterStyle.iconSize.amount iconSize: MessagesCounterStyle.iconSize.amount
......
import QtQuick 2.7
// =============================================================================
Notification {
Rectangle {
color: 'red'
width: 200
height: 100
}
}
...@@ -15,15 +15,19 @@ DesktopPopup { ...@@ -15,15 +15,19 @@ DesktopPopup {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
property int notificationOffset: 0
property alias notificationHeight: notification.popupHeight property alias notificationHeight: notification.popupHeight
property int notificationOffset: 0
property var notificationData: null
readonly property var window: _window
property var _window
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
flags: Qt.Popup flags: Qt.Popup
Component.onCompleted: { Component.onCompleted: {
var window = data[0] var window = _window = data[0]
Utils.assert( Utils.assert(
Utils.qmlTypeof(window, 'QQuickWindowQmlImpl'), true, Utils.qmlTypeof(window, 'QQuickWindowQmlImpl'), true,
...@@ -45,7 +49,7 @@ DesktopPopup { ...@@ -45,7 +49,7 @@ DesktopPopup {
} }
var height = screen.desktopAvailableHeight - window.height var height = screen.desktopAvailableHeight - window.height
return height - notificationOffset % height return height - (notificationOffset % height)
}) })
} }
} }
...@@ -11,6 +11,10 @@ TestCase { ...@@ -11,6 +11,10 @@ TestCase {
id: notification id: notification
} }
function test_notificationDataProperty () {
compare(Utils.isObject(notification.notificationData), true)
}
function test_notificationHeightProperty () { function test_notificationHeightProperty () {
compare(Utils.isInteger(notification.notificationHeight), true) compare(Utils.isInteger(notification.notificationHeight), true)
} }
......
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import Linphone.Styles 1.0
// =============================================================================
Notification {
id: notification
// ---------------------------------------------------------------------------
property var _call: notificationData && notificationData.call
property var _contact: _contactObserver.contact
property var _contactObserver: SipAddressesModel.getContactObserver(_call ? _call.sipAddress : '')
// ---------------------------------------------------------------------------
function _close (cb) {
notification.window.setVisible(false)
cb()
}
// ---------------------------------------------------------------------------
Rectangle {
color: NotificationReceivedCallStyle.color
height: NotificationReceivedCallStyle.height
width: NotificationReceivedCallStyle.width
Icon {
anchors {
left: parent.left
top: parent.top
}
icon: 'call_sign_incoming'
iconSize: NotificationReceivedCallStyle.iconSize
}
Loader {
active: notification._call
anchors {
fill: parent
leftMargin: NotificationReceivedCallStyle.leftMargin
rightMargin: NotificationReceivedCallStyle.rightMargin
bottomMargin: NotificationReceivedCallStyle.bottomMargin
}
sourceComponent: ColumnLayout {
spacing: NotificationReceivedCallStyle.spacing
Contact {
Layout.fillWidth: true
entry: ({
contact: notification._contact,
sipAddress: notification._contactObserver.sipAddress
})
}
// ---------------------------------------------------------------------
// Action buttons.
// ---------------------------------------------------------------------
Item {
Layout.fillHeight: true
Layout.fillWidth: true
ActionBar {
anchors.centerIn: parent
iconSize: NotificationReceivedCallStyle.actionArea.iconSize
ActionButton {
icon: 'video_call_accept'
onClicked: notification._close(notification._call.acceptWithVideo)
}
ActionButton {
icon: 'call_accept'
onClicked: notification._close(notification._call.accept)
}
}
ActionBar {
anchors {
right: parent.right
rightMargin: NotificationReceivedCallStyle.actionArea.rightButtonsGroupMargin
verticalCenter: parent.verticalCenter
}
iconSize: NotificationReceivedCallStyle.actionArea.iconSize
ActionButton {
icon: 'hangup'
onClicked: notification._close(notification._call.terminate)
}
}
}
}
}
}
}
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import Linphone.Styles 1.0
import Utils 1.0
// =============================================================================
Notification {
id: notification
// ---------------------------------------------------------------------------
property string _fileUri: notificationData ? notificationData.fileUri : ''
// ---------------------------------------------------------------------------
Rectangle {
color: NotificationReceivedFileMessageStyle.color
height: NotificationReceivedFileMessageStyle.height
width: NotificationReceivedFileMessageStyle.width
Icon {
anchors {
left: parent.left
top: parent.top
}
icon: 'file_sign'
iconSize: NotificationReceivedFileMessageStyle.iconSize
}
Loader {
active: notification._fileUri.length > 0
anchors {
fill: parent
leftMargin: NotificationReceivedFileMessageStyle.leftMargin
rightMargin: NotificationReceivedFileMessageStyle.rightMargin
}
sourceComponent: RowLayout {
anchors.fill: parent
spacing: NotificationReceivedFileMessageStyle.spacing
Text {
Layout.fillWidth: true
color: NotificationReceivedFileMessageStyle.fileName.color
elide: Text.ElideRight
font.pointSize: NotificationReceivedFileMessageStyle.fileName.fontSize
text: Utils.basename(notification._fileUri)
}
Text {
Layout.preferredWidth: NotificationReceivedFileMessageStyle.fileSize.width
color: NotificationReceivedFileMessageStyle.fileSize.color
elide: Text.ElideRight
font.pointSize: NotificationReceivedFileMessageStyle.fileSize.fontSize
horizontalAlignment: Text.AlignRight
text: Utils.formatSize(notification.notificationData.fileSize)
}
}
MouseArea {
anchors.fill: parent
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
onClicked: {
notification.window.setVisible(false)
Qt.openUrlExternally('file://' + Utils.dirname(notification._fileUri))
}
}
}
}
}
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import Linphone.Styles 1.0
// =============================================================================
Notification {
id: notification
// ---------------------------------------------------------------------------
property string _sipAddress: notificationData ? notificationData.sipAddress : ''
property var _contact: _contactObserver.contact
property var _contactObserver: SipAddressesModel.getContactObserver(_sipAddress)
// ---------------------------------------------------------------------------
Rectangle {
color: NotificationReceivedMessageStyle.color
height: NotificationReceivedMessageStyle.height
width: NotificationReceivedMessageStyle.width
Icon {
anchors {
left: parent.left
top: parent.top
}
icon: 'message_sign'
iconSize: NotificationReceivedMessageStyle.iconSize
}
Loader {
active: notification._sipAddress.length > 0
anchors {
fill: parent
leftMargin: NotificationReceivedMessageStyle.leftMargin
rightMargin: NotificationReceivedMessageStyle.rightMargin
bottomMargin: NotificationReceivedMessageStyle.bottomMargin
}
sourceComponent: ColumnLayout {
spacing: NotificationReceivedMessageStyle.spacing
Contact {
Layout.fillWidth: true
entry: ({
contact: notification._contact,
sipAddress: notification._sipAddress
})
}
Rectangle {
Layout.fillHeight: true
Layout.fillWidth: true
color: NotificationReceivedMessageStyle.messageContainer.color
radius: NotificationReceivedMessageStyle.messageContainer.radius
Text {
anchors {
fill: parent
margins: NotificationReceivedMessageStyle.messageContainer.margins
}
color: NotificationReceivedMessageStyle.messageContainer.text.color
elide: Text.ElideRight
font {
italic: true
pointSize: NotificationReceivedMessageStyle.messageContainer.text.fontSize
}
verticalAlignment: Text.AlignVCenter
text: notification.notificationData.message
wrapMode: Text.Wrap
}
}
}
}
MouseArea {
anchors.fill: parent
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
hoverEnabled: true
onClicked: {
notification.window.setVisible(false)
notification.notificationData.window.setView('Conversation', {
sipAddress: notification._sipAddress
})
}
}
}
}
import QtQuick 2.7
// =============================================================================
Notification {
Rectangle {
color: 'red'
width: 200
height: 100
}
}
pragma Singleton
import QtQuick 2.7
import Common 1.0
// =============================================================================
QtObject {
property color color: Colors.k
property int height: 120
property int iconSize: 40
property int spacing: 0
property int width: 300
property int bottomMargin: 15
property int leftMargin: 15
property int rightMargin: 15
property QtObject actionArea: QtObject {
property int iconSize: 40
property int rightButtonsGroupMargin: 15
}
}
pragma Singleton
import QtQuick 2.7
import Common 1.0
// =============================================================================
QtObject {
property color color: Colors.k
property int height: 55
property int iconSize: 40
property int leftMargin: 25
property int rightMargin: 15
property int spacing: 10
property int width: 300
property QtObject fileName: QtObject {
property color color: Colors.h
property int fontSize: 10
}
property QtObject fileSize: QtObject {
property color color: Colors.h
property int fontSize: 9
property int width: 100
}
}
pragma Singleton
import QtQuick 2.7
import Common 1.0
// =============================================================================
QtObject {
property color color: Colors.k
property int bottomMargin: 15
property int iconSize: 40
property int leftMargin: 15
property int rightMargin: 15
property int spacing: 0
property int width: 300
property int height: 120
property QtObject messageContainer: QtObject {
property color color: Colors.m
property int radius: 6
property int margins: 10
property QtObject text: QtObject {
property color color: Colors.l
property int fontSize: 9
}
}
}
...@@ -4,5 +4,5 @@ import QtQuick 2.7 ...@@ -4,5 +4,5 @@ import QtQuick 2.7
// ============================================================================= // =============================================================================
QtObject { QtObject {
property int margin: 10 property int margin: 0
} }
...@@ -4,22 +4,25 @@ module Linphone.Style ...@@ -4,22 +4,25 @@ module Linphone.Style
# Components styles ------------------------------------------------------------ # Components styles ------------------------------------------------------------
singleton AccountStatusStyle 1.0 Account/AccountStatusStyle.qml singleton AccountStatusStyle 1.0 Account/AccountStatusStyle.qml
singleton ChatStyle 1.0 ChatStyle.qml singleton ChatStyle 1.0 ChatStyle.qml
singleton CallsStyle 1.0 Calls/CallsStyle.qml singleton CallsStyle 1.0 Calls/CallsStyle.qml
singleton CallControlsStyle 1.0 Calls/CallControlsStyle.qml singleton CallControlsStyle 1.0 Calls/CallControlsStyle.qml
singleton AvatarStyle 1.0 Contact/AvatarStyle.qml singleton AvatarStyle 1.0 Contact/AvatarStyle.qml
singleton ContactDescriptionStyle 1.0 Contact/ContactDescriptionStyle.qml singleton ContactDescriptionStyle 1.0 Contact/ContactDescriptionStyle.qml
singleton ContactStyle 1.0 Contact/ContactStyle.qml singleton ContactStyle 1.0 Contact/ContactStyle.qml
singleton MessagesCounterStyle 1.0 Contact/MessagesCounterStyle.qml singleton MessagesCounterStyle 1.0 Contact/MessagesCounterStyle.qml
singleton NotificationStyle 1.0 NotificationStyle.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
singleton PresenceStringStyle 1.0 Presence/PresenceStringStyle.qml singleton PresenceStringStyle 1.0 Presence/PresenceStringStyle.qml
singleton SmartSearchBarStyle 1.0 SmartSearchBarStyle.qml singleton SmartSearchBarStyle 1.0 SmartSearchBarStyle.qml
singleton TimelineStyle 1.0 TimelineStyle.qml singleton TimelineStyle 1.0 TimelineStyle.qml
...@@ -261,6 +261,18 @@ function assert (condition, message) { ...@@ -261,6 +261,18 @@ function assert (condition, message) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
function basename (str) {
return str.slice(str.lastIndexOf('/') + 1)
}
// -----------------------------------------------------------------------------
function dirname (str) {
return str.slice(0, str.lastIndexOf('/') + 1)
}
// -----------------------------------------------------------------------------
function extractProperties (obj, pattern) { function extractProperties (obj, pattern) {
if (!pattern) { if (!pattern) {
return {} return {}
......
...@@ -46,10 +46,6 @@ ApplicationWindow { ...@@ -46,10 +46,6 @@ ApplicationWindow {
}) })
} }
function ensureCollapsed () {
collapse.setCollapsed(true)
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function _updateSelectedEntry (view, props) { function _updateSelectedEntry (view, props) {
...@@ -66,6 +62,10 @@ ApplicationWindow { ...@@ -66,6 +62,10 @@ ApplicationWindow {
} }
function _setView (view, props) { function _setView (view, props) {
window.showNormal()
window.requestActivate()
collapse.setCollapsed(true)
_updateSelectedEntry(view, props) _updateSelectedEntry(view, props)
_currentView = view _currentView = view
contentLoader.setSource(view + '.qml', props || {}) contentLoader.setSource(view + '.qml', props || {})
...@@ -153,28 +153,20 @@ ApplicationWindow { ...@@ -153,28 +153,20 @@ ApplicationWindow {
model: SmartSearchBarModel {} model: SmartSearchBarModel {}
onAddContact: { onAddContact: window.setView('ContactEdit', {
window.ensureCollapsed() sipAddress: sipAddress
window.setView('ContactEdit', { })
sipAddress: sipAddress
})
}
onLaunchCall: CallsListModel.launchAudioCall(sipAddress) onLaunchCall: CallsListModel.launchAudioCall(sipAddress)
onLaunchChat: { onLaunchChat: window.setView('Conversation', {
window.ensureCollapsed() sipAddress: sipAddress
window.setView('Conversation', { })
sipAddress: sipAddress
})
}
onLaunchVideoCall: CallsListModel.launchVideoCall(sipAddress) onLaunchVideoCall: CallsListModel.launchVideoCall(sipAddress)
onEntryClicked: { onEntryClicked: window.setView(entry.contact ? 'ContactEdit' : 'Conversation', {
window.ensureCollapsed() sipAddress: entry.sipAddress
window.setView(entry.contact ? 'ContactEdit' : 'Conversation', { })
sipAddress: entry.sipAddress
})
}
} }
} }
} }
......
cmake-builder @ 326a0976
Subproject commit a79e2826e056cc48b3b4d0eda4f38d82f124bb56 Subproject commit 326a0976c0b42927056d39d99a396a2d0a8fc3da
linphone @ 2c3f66ef
Subproject commit 87bc9f7ea55f8e449cf1d6b83fefacd2d9e596b0 Subproject commit 2c3f66ef6f160f4c23efc2dea9485ddae8194af1
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