toast notifications width and margins are now configurable

This commit is contained in:
Martin Rotter 2023-11-09 15:05:33 +01:00
parent 5e8e8a555d
commit 700b932cd8
5 changed files with 87 additions and 61 deletions

View file

@ -3,10 +3,10 @@
#include "gui/notifications/toastnotificationsmanager.h" #include "gui/notifications/toastnotificationsmanager.h"
#include "3rd-party/boolinq/boolinq.h" #include "3rd-party/boolinq/boolinq.h"
#include "gui/notifications/basetoastnotification.h"
#include "gui/notifications/articlelistnotification.h" #include "gui/notifications/articlelistnotification.h"
#include "gui/notifications/basetoastnotification.h"
#include "gui/notifications/toastnotification.h" #include "gui/notifications/toastnotification.h"
#include "miscellaneous/settings.h"
#include <QRect> #include <QRect>
#include <QScreen> #include <QScreen>
@ -29,11 +29,14 @@ QString ToastNotificationsManager::textForPosition(ToastNotificationsManager::No
} }
} }
ToastNotificationsManager::ToastNotificationsManager(NotificationPosition position, int screen, QObject* parent) ToastNotificationsManager::ToastNotificationsManager(QObject* parent)
: QObject(parent), m_position(position), m_screen(screen), m_articleListNotification(nullptr) {} : QObject(parent), m_position(ToastNotificationsManager::NotificationPosition::TopRight), m_screen(0), m_margins(0),
m_articleListNotification(nullptr) {
resetNotifications(false);
}
ToastNotificationsManager::~ToastNotificationsManager() { ToastNotificationsManager::~ToastNotificationsManager() {
clear(); clear(true);
} }
QList<BaseToastNotification*> ToastNotificationsManager::activeNotifications() const { QList<BaseToastNotification*> ToastNotificationsManager::activeNotifications() const {
@ -56,16 +59,59 @@ void ToastNotificationsManager::setPosition(NotificationPosition position) {
m_position = position; m_position = position;
} }
void ToastNotificationsManager::resetNotifications() {} void ToastNotificationsManager::resetNotifications(bool reload_existing_notifications) {
m_position = qApp->settings()
->value(GROUP(GUI), SETTING(GUI::ToastNotificationsPosition))
.value<ToastNotificationsManager::NotificationPosition>();
m_screen = qApp->settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsScreen)).toInt();
m_margins = qApp->settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsMargin)).toInt();
void ToastNotificationsManager::clear() { auto notif_width = qApp->settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsWidth)).toInt();
if (reload_existing_notifications) {
auto notif = m_activeNotifications;
clear(false);
while (!notif.isEmpty()) {
BaseToastNotification* one_notif = notif.takeLast();
one_notif->setFixedWidth(notif_width);
processNotification(one_notif);
}
}
}
void ToastNotificationsManager::clear(bool delete_from_memory) {
for (BaseToastNotification* notif : m_activeNotifications) { for (BaseToastNotification* notif : m_activeNotifications) {
closeNotification(notif, true); closeNotification(notif, delete_from_memory);
} }
m_activeNotifications.clear(); m_activeNotifications.clear();
} }
void ToastNotificationsManager::processNotification(BaseToastNotification* notif) {
notif->show();
auto* screen = moveToProperScreen(notif);
auto notif_new_pos = cornerForNewNotification(screen->availableGeometry());
// Make sure notification is finally resized.
notif->adjustSize();
qApp->processEvents();
// Move notification, at this point we already need to know its precise size.
moveNotificationToCorner(notif, notif_new_pos);
// Remove out-of-bounds old notifications and shift existing
// ones to make space for new notifications.
removeOutOfBoundsNotifications(notif->height());
makeSpaceForNotification(notif->height());
m_activeNotifications.prepend(notif);
}
void ToastNotificationsManager::showNotification(Notification::Event event, void ToastNotificationsManager::showNotification(Notification::Event event,
const GuiMessage& msg, const GuiMessage& msg,
const GuiAction& action) { const GuiAction& action) {
@ -89,26 +135,7 @@ void ToastNotificationsManager::showNotification(Notification::Event event,
hookNotification(notif); hookNotification(notif);
} }
// Insert new notification into free space. processNotification(notif);
notif->show();
auto* screen = moveToProperScreen(notif);
auto notif_new_pos = cornerForNewNotification(screen->availableGeometry());
// Make sure notification is finally resized.
notif->adjustSize();
qApp->processEvents();
// Move notification, at this point we already need to know its precise size.
moveNotificationToCorner(notif, notif_new_pos);
// Remove out-of-bounds old notifications and shift existing
// ones to make space for new notifications.
removeOutOfBoundsNotifications(notif->height());
makeSpaceForNotification(notif->height());
m_activeNotifications.prepend(notif);
} }
void ToastNotificationsManager::closeNotification(BaseToastNotification* notif, bool delete_from_memory) { void ToastNotificationsManager::closeNotification(BaseToastNotification* notif, bool delete_from_memory) {
@ -146,17 +173,17 @@ QScreen* ToastNotificationsManager::activeScreen() const {
QPoint ToastNotificationsManager::cornerForNewNotification(QRect screen_rect) { QPoint ToastNotificationsManager::cornerForNewNotification(QRect screen_rect) {
switch (m_position) { switch (m_position) {
case ToastNotificationsManager::TopLeft: case ToastNotificationsManager::TopLeft:
return screen_rect.topLeft() + QPoint(NOTIFICATIONS_MARGIN, NOTIFICATIONS_MARGIN); return screen_rect.topLeft() + QPoint(m_margins, m_margins);
case ToastNotificationsManager::TopRight: case ToastNotificationsManager::TopRight:
return screen_rect.topRight() - QPoint(NOTIFICATIONS_MARGIN, -NOTIFICATIONS_MARGIN); return screen_rect.topRight() - QPoint(m_margins, -m_margins);
case ToastNotificationsManager::BottomLeft: case ToastNotificationsManager::BottomLeft:
return screen_rect.bottomLeft() - QPoint(-NOTIFICATIONS_MARGIN, NOTIFICATIONS_MARGIN); return screen_rect.bottomLeft() - QPoint(-m_margins, m_margins);
case ToastNotificationsManager::BottomRight: case ToastNotificationsManager::BottomRight:
default: default:
return screen_rect.bottomRight() - QPoint(NOTIFICATIONS_MARGIN, NOTIFICATIONS_MARGIN); return screen_rect.bottomRight() - QPoint(m_margins, m_margins);
} }
} }
@ -222,7 +249,7 @@ void ToastNotificationsManager::makeSpaceForNotification(int height_to_make_spac
} }
// Move it all down. // Move it all down.
notif->move(notif->pos().x(), shift_down(notif->pos().y(), (height_to_make_space + NOTIFICATIONS_MARGIN))); notif->move(notif->pos().x(), shift_down(notif->pos().y(), (height_to_make_space + m_margins)));
break; break;
} }
@ -242,7 +269,7 @@ void ToastNotificationsManager::makeSpaceForNotification(int height_to_make_spac
} }
// Move it all up. // Move it all up.
notif->move(notif->pos().x(), shift_up(notif->pos().y(), height_to_make_space + NOTIFICATIONS_MARGIN)); notif->move(notif->pos().x(), shift_up(notif->pos().y(), height_to_make_space + m_margins));
break; break;
} }
} }
@ -254,8 +281,8 @@ void ToastNotificationsManager::removeOutOfBoundsNotifications(int height_to_res
int available_height = screen->availableSize().height(); int available_height = screen->availableSize().height();
while (boolinq::from(m_activeNotifications).sum([](BaseToastNotification* notif) { while (boolinq::from(m_activeNotifications).sum([this](BaseToastNotification* notif) {
return notif->height() + NOTIFICATIONS_MARGIN; return notif->height() + m_margins;
}) + height_to_reserve > }) + height_to_reserve >
available_height) { available_height) {
if (!m_activeNotifications.isEmpty()) { if (!m_activeNotifications.isEmpty()) {

View file

@ -27,9 +27,7 @@ class ToastNotificationsManager : public QObject {
static QString textForPosition(ToastNotificationsManager::NotificationPosition pos); static QString textForPosition(ToastNotificationsManager::NotificationPosition pos);
explicit ToastNotificationsManager(ToastNotificationsManager::NotificationPosition position, explicit ToastNotificationsManager(QObject* parent = nullptr);
int screen,
QObject* parent = nullptr);
virtual ~ToastNotificationsManager(); virtual ~ToastNotificationsManager();
QList<BaseToastNotification*> activeNotifications() const; QList<BaseToastNotification*> activeNotifications() const;
@ -42,11 +40,11 @@ class ToastNotificationsManager : public QObject {
NotificationPosition position() const; NotificationPosition position() const;
void setPosition(NotificationPosition position); void setPosition(NotificationPosition position);
void resetNotifications(); void resetNotifications(bool reload_existing_notifications);
public slots: public slots:
void clear(); void clear(bool delete_from_memory);
void showNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action); void showNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action = {});
private slots: private slots:
void closeNotification(BaseToastNotification* notif, bool delete_from_memory); void closeNotification(BaseToastNotification* notif, bool delete_from_memory);
@ -60,6 +58,7 @@ class ToastNotificationsManager : public QObject {
QScreen* moveToProperScreen(BaseToastNotification* notif); QScreen* moveToProperScreen(BaseToastNotification* notif);
QPoint cornerForNewNotification(QRect screen_rect); QPoint cornerForNewNotification(QRect screen_rect);
void processNotification(BaseToastNotification* notif);
void initializeArticleListNotification(); void initializeArticleListNotification();
void hookNotification(BaseToastNotification* notif); void hookNotification(BaseToastNotification* notif);
void moveNotificationToCorner(BaseToastNotification* notif, QPoint corner); void moveNotificationToCorner(BaseToastNotification* notif, QPoint corner);
@ -69,6 +68,7 @@ class ToastNotificationsManager : public QObject {
private: private:
NotificationPosition m_position; NotificationPosition m_position;
int m_screen; int m_screen;
int m_margins;
// List of all displayed notifications, newest notifications are in the beginning of the list // List of all displayed notifications, newest notifications are in the beginning of the list
// and oldest at the end. // and oldest at the end.

View file

@ -28,8 +28,6 @@ SettingsNotifications::SettingsNotifications(Settings* settings, QWidget* parent
connect(m_ui.m_rbNativeNotifications, &QRadioButton::toggled, this, &SettingsNotifications::requireRestart); connect(m_ui.m_rbNativeNotifications, &QRadioButton::toggled, this, &SettingsNotifications::requireRestart);
connect(m_ui.m_sbScreen, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings); connect(m_ui.m_sbScreen, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings);
connect(m_ui.m_sbScreen, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::requireRestart);
connect(m_ui.m_sbMargin, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings); connect(m_ui.m_sbMargin, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings);
connect(m_ui.m_sbWidth, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings); connect(m_ui.m_sbWidth, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings);
@ -39,10 +37,6 @@ SettingsNotifications::SettingsNotifications(Settings* settings, QWidget* parent
QOverload<int>::of(&QComboBox::currentIndexChanged), QOverload<int>::of(&QComboBox::currentIndexChanged),
this, this,
&SettingsNotifications::dirtifySettings); &SettingsNotifications::dirtifySettings);
connect(m_ui.m_cbCustomNotificationsPosition,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this,
&SettingsNotifications::requireRestart);
} }
void SettingsNotifications::loadSettings() { void SettingsNotifications::loadSettings() {
@ -97,7 +91,13 @@ void SettingsNotifications::saveSettings() {
m_ui.m_cbCustomNotificationsPosition->currentData() m_ui.m_cbCustomNotificationsPosition->currentData()
.value<ToastNotificationsManager::NotificationPosition>()); .value<ToastNotificationsManager::NotificationPosition>());
// qApp->m_toastNotifications qApp->toastNotifications()->resetNotifications(true);
qApp->toastNotifications()->showNotification(Notification::Event::GeneralEvent,
GuiMessage(tr("How do I look?"),
tr("Just testing new notifications settings. "
"That's all."),
QSystemTrayIcon::MessageIcon::Warning));
onEndSaveSettings(); onEndSaveSettings();
} }

View file

@ -112,13 +112,8 @@ Application::Application(const QString& id, int& argc, char** argv, const QStrin
m_database = new DatabaseFactory(this); m_database = new DatabaseFactory(this);
m_downloadManager = nullptr; m_downloadManager = nullptr;
m_notifications = new NotificationFactory(this); m_notifications = new NotificationFactory(this);
m_toastNotifications = m_toastNotifications = settings()->value(GROUP(GUI), SETTING(GUI::UseToastNotifications)).toBool()
settings()->value(GROUP(GUI), SETTING(GUI::UseToastNotifications)).toBool() ? new ToastNotificationsManager(this)
? new ToastNotificationsManager(settings()
->value(GROUP(GUI), SETTING(GUI::ToastNotificationsPosition))
.value<ToastNotificationsManager::NotificationPosition>(),
settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsScreen)).toInt(),
this)
: nullptr; : nullptr;
m_shouldRestart = false; m_shouldRestart = false;
@ -428,6 +423,10 @@ void Application::displayLogMessageInDialog(const QString& message) {
} }
} }
ToastNotificationsManager* Application::toastNotifications() const {
return m_toastNotifications;
}
QThreadPool* Application::workHorsePool() const { QThreadPool* Application::workHorsePool() const {
return m_workHorsePool; return m_workHorsePool;
} }

View file

@ -132,6 +132,8 @@ class RSSGUARD_DLLSPEC Application : public SingleApplication {
SystemTrayIcon* trayIcon(); SystemTrayIcon* trayIcon();
NotificationFactory* notifications() const; NotificationFactory* notifications() const;
NodeJs* nodejs() const; NodeJs* nodejs() const;
QThreadPool* workHorsePool() const;
ToastNotificationsManager* toastNotifications() const;
QIcon desktopAwareIcon() const; QIcon desktopAwareIcon() const;
@ -151,6 +153,8 @@ class RSSGUARD_DLLSPEC Application : public SingleApplication {
QString cacheFolder(); QString cacheFolder();
int customAdblockPort() const;
QString replaceDataUserDataFolderPlaceholder(QString text) const; QString replaceDataUserDataFolderPlaceholder(QString text) const;
QStringList replaceDataUserDataFolderPlaceholder(QStringList texts) const; QStringList replaceDataUserDataFolderPlaceholder(QStringList texts) const;
@ -190,10 +194,6 @@ class RSSGUARD_DLLSPEC Application : public SingleApplication {
// Custom debug/console log handler. // Custom debug/console log handler.
static void performLogging(QtMsgType type, const QMessageLogContext& context, const QString& msg); static void performLogging(QtMsgType type, const QMessageLogContext& context, const QString& msg);
int customAdblockPort() const;
QThreadPool* workHorsePool() const;
public slots: public slots:
// Restarts the application. // Restarts the application.
void restart(); void restart();