1 /**************************************************************************
2 * Otter Browser: Web browser controlled by the user, not vice-versa.
3 * Copyright (C) 2013 - 2018 Michal Dutkiewicz aka Emdek <michal@emdek.pl>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 **************************************************************************/
19 
20 #include "NotificationsManager.h"
21 #include "Application.h"
22 #include "SessionsManager.h"
23 #include "../ui/MainWindow.h"
24 
25 #include <QtCore/QFile>
26 #include <QtCore/QMetaEnum>
27 #include <QtCore/QSettings>
28 #include <QtMultimedia/QSoundEffect>
29 
30 namespace Otter
31 {
32 
33 NotificationsManager* NotificationsManager::m_instance(nullptr);
34 QMap<int, QString> NotificationsManager::m_identifiers;
35 QVector<NotificationsManager::EventDefinition> NotificationsManager::m_definitions;
36 int NotificationsManager::m_eventIdentifierEnumerator(0);
37 
Notification(const QString & message,NotificationLevel level,int event,QObject * parent)38 Notification::Notification(const QString &message, NotificationLevel level, int event, QObject *parent) : QObject(parent),
39 	m_message(message),
40 	m_creationTime(QDateTime::currentDateTime()),
41 	m_level(level),
42 	m_event(event)
43 {
44 }
45 
markAsClicked()46 void Notification::markAsClicked()
47 {
48 	emit clicked();
49 
50 	deleteLater();
51 }
52 
markAsIgnored()53 void Notification::markAsIgnored()
54 {
55 	emit ignored();
56 
57 	deleteLater();
58 }
59 
setData(const QVariant & data)60 void Notification::setData(const QVariant &data)
61 {
62 	m_data = data;
63 }
64 
getMessage() const65 QString Notification::getMessage() const
66 {
67 	return m_message;
68 }
69 
getCreationTime() const70 QDateTime Notification::getCreationTime() const
71 {
72 	return m_creationTime;
73 }
74 
getData() const75 QVariant Notification::getData() const
76 {
77 	return m_data;
78 }
79 
getLevel() const80 Notification::NotificationLevel Notification::getLevel() const
81 {
82 	return m_level;
83 }
84 
NotificationsManager(QObject * parent)85 NotificationsManager::NotificationsManager(QObject *parent) : QObject(parent)
86 {
87 	registerEvent(QT_TRANSLATE_NOOP("notifications", "Feed Updated"), QT_TRANSLATE_NOOP("notifications", "Feed update was completed"));
88 	registerEvent(QT_TRANSLATE_NOOP("notifications", "Download Completed"), QT_TRANSLATE_NOOP("notifications", "File download was completed"));
89 	registerEvent(QT_TRANSLATE_NOOP("notifications", "Update Available"), QT_TRANSLATE_NOOP("notifications", "Update is available to be downloaded"));
90 }
91 
createInstance()92 void NotificationsManager::createInstance()
93 {
94 	if (!m_instance)
95 	{
96 		m_instance = new NotificationsManager(QCoreApplication::instance());
97 		m_eventIdentifierEnumerator = NotificationsManager::staticMetaObject.indexOfEnumerator(QLatin1String("EventIdentifier").data());
98 	}
99 }
100 
createNotification(int event,const QString & message,Notification::NotificationLevel level,QObject * parent)101 Notification* NotificationsManager::createNotification(int event, const QString &message, Notification::NotificationLevel level, QObject *parent)
102 {
103 	Notification *notification(new Notification(message, level, event, Application::getInstance()));
104 	const EventDefinition definition(getEventDefinition(event));
105 
106 	if (!definition.playSound.isEmpty())
107 	{
108 		QSoundEffect *effect(new QSoundEffect(m_instance));
109 		effect->setSource(QUrl::fromLocalFile(definition.playSound));
110 		effect->setLoopCount(1);
111 		effect->setVolume(0.5);
112 
113 		if (effect->status() == QSoundEffect::Error)
114 		{
115 			effect->deleteLater();
116 		}
117 		else
118 		{
119 			connect(effect, &QSoundEffect::playingChanged, m_instance, [=]()
120 			{
121 				if (!effect->isPlaying())
122 				{
123 					effect->deleteLater();
124 				}
125 			});
126 
127 			effect->play();
128 		}
129 	}
130 
131 	if (definition.showAlert)
132 	{
133 		Application::getInstance()->alert(MainWindow::findMainWindow(parent));
134 	}
135 
136 	if (definition.showNotification)
137 	{
138 		Application::showNotification(notification);
139 	}
140 
141 	return notification;
142 }
143 
getEventName(int identifier)144 QString NotificationsManager::getEventName(int identifier)
145 {
146 	if (m_identifiers.contains(identifier))
147 	{
148 		return m_identifiers[identifier];
149 	}
150 
151 	QString name(NotificationsManager::staticMetaObject.enumerator(m_eventIdentifierEnumerator).valueToKey(identifier));
152 
153 	if (!name.isEmpty())
154 	{
155 		name.chop(5);
156 
157 		return name;
158 	}
159 
160 	return {};
161 }
162 
getEventDefinition(int identifier)163 NotificationsManager::EventDefinition NotificationsManager::getEventDefinition(int identifier)
164 {
165 	if (identifier < 0 || identifier >= m_definitions.count())
166 	{
167 		return {};
168 	}
169 
170 	const QSettings notificationsSettings(SessionsManager::getReadableDataPath(QLatin1String("notifications.ini")), QSettings::IniFormat);
171 	const QString eventName(getEventName(identifier));
172 	EventDefinition definition(m_definitions.at(identifier));
173 	definition.playSound = notificationsSettings.value(eventName + QLatin1String("/playSound"), {}).toString();
174 	definition.showAlert = notificationsSettings.value(eventName + QLatin1String("/showAlert"), false).toBool();
175 	definition.showNotification = notificationsSettings.value(eventName + QLatin1String("/showNotification"), false).toBool();
176 
177 	return definition;
178 }
179 
getEventDefinitions()180 QVector<NotificationsManager::EventDefinition> NotificationsManager::getEventDefinitions()
181 {
182 	QVector<EventDefinition> definitions;
183 	definitions.reserve(m_definitions.count());
184 
185 	for (int i = 0; i < m_definitions.count(); ++i)
186 	{
187 		definitions.append(getEventDefinition(i));
188 	}
189 
190 	return definitions;
191 }
192 
registerEvent(const QString & title,const QString & description)193 int NotificationsManager::registerEvent(const QString &title, const QString &description)
194 {
195 	const int identifier(m_definitions.count());
196 
197 	EventDefinition definition;
198 	definition.title = title;
199 	definition.description = description;
200 	definition.identifier = identifier;
201 
202 	m_definitions.append(definition);
203 
204 	return identifier;
205 }
206 
207 }
208