diff --git a/src/librssguard/CMakeLists.txt b/src/librssguard/CMakeLists.txt index d9cd30db0..c2dccee1b 100644 --- a/src/librssguard/CMakeLists.txt +++ b/src/librssguard/CMakeLists.txt @@ -99,6 +99,8 @@ set(SOURCES gui/notifications/notificationseditor.h gui/notifications/singlenotificationeditor.cpp gui/notifications/singlenotificationeditor.h + gui/notifications/articlelistnotification.cpp + gui/notifications/articlelistnotification.h gui/reusable/baselineedit.cpp gui/reusable/baselineedit.h gui/reusable/basetreeview.cpp @@ -440,9 +442,10 @@ set(UI_FILES gui/dialogs/formupdate.ui gui/notifications/notificationseditor.ui gui/notifications/singlenotificationeditor.ui + gui/notifications/articlelistnotification.ui + gui/notifications/toastnotification.ui gui/reusable/networkproxydetails.ui gui/itemdetails.ui - gui/notifications/toastnotification.ui gui/richtexteditor/mrichtextedit.ui gui/newspaperpreviewer.ui gui/reusable/searchtextwidget.ui diff --git a/src/librssguard/gui/dialogs/formmain.cpp b/src/librssguard/gui/dialogs/formmain.cpp index b2563a855..7a4d49d0d 100644 --- a/src/librssguard/gui/dialogs/formmain.cpp +++ b/src/librssguard/gui/dialogs/formmain.cpp @@ -1090,20 +1090,7 @@ void FormMain::showAddAccountDialog() { } void FormMain::reportABug() { - qApp - ->showGuiMessage(Notification::Event::GeneralEvent, - GuiMessage(QDateTime::currentDateTime().toString(), - "Quisque ullamcorper ut purus nec tempus. Vivamus eros dolor, sagittis ultrices augue " - "ut, posuere fringilla lorem. Donec posuere, enim sit amet fermentum dignissim, tellus " - "lectus laoreet lectus, vestibulum laoreet felis tortor eget nunc. Curabitur sagittis " - "quam in scelerisque placerat. Vivamus vel porta tortor. Vivamus nec volutpat sem", - QSystemTrayIcon::MessageIcon::Information), - GuiMessageDestination(), - GuiAction("test", []() { - qDebugNN << "aa"; - })); - - // qApp->web()->openUrlInExternalBrowser(QSL(APP_URL_ISSUES_NEW)); + qApp->web()->openUrlInExternalBrowser(QSL(APP_URL_ISSUES_NEW)); } void FormMain::donate() { diff --git a/src/librssguard/gui/notifications/articlelistnotification.cpp b/src/librssguard/gui/notifications/articlelistnotification.cpp new file mode 100644 index 000000000..5eb62d926 --- /dev/null +++ b/src/librssguard/gui/notifications/articlelistnotification.cpp @@ -0,0 +1,10 @@ +// For license of this file, see /LICENSE.md. + +#include "gui/notifications/articlelistnotification.h" + +ArticleListNotification::ArticleListNotification(QWidget* parent) : BaseToastNotification(parent) { + m_ui.setupUi(this); + + setupCloseButton(m_ui.m_btnClose); + setupTimedClosing(); +} diff --git a/src/librssguard/gui/notifications/articlelistnotification.h b/src/librssguard/gui/notifications/articlelistnotification.h new file mode 100644 index 000000000..8aaea8095 --- /dev/null +++ b/src/librssguard/gui/notifications/articlelistnotification.h @@ -0,0 +1,20 @@ +// For license of this file, see /LICENSE.md. + +#ifndef ARTICLELISTNOTIFICATION_H +#define ARTICLELISTNOTIFICATION_H + +#include "gui/notifications/basetoastnotification.h" + +#include "ui_articlelistnotification.h" + +class ArticleListNotification : public BaseToastNotification { + Q_OBJECT + + public: + explicit ArticleListNotification(QWidget* parent = nullptr); + + private: + Ui::ArticleListNotification m_ui; +}; + +#endif // ARTICLELISTNOTIFICATION_H diff --git a/src/librssguard/gui/notifications/basetoastnotification.cpp b/src/librssguard/gui/notifications/basetoastnotification.cpp index 07fc295a3..c396c6e56 100644 --- a/src/librssguard/gui/notifications/basetoastnotification.cpp +++ b/src/librssguard/gui/notifications/basetoastnotification.cpp @@ -26,7 +26,7 @@ BaseToastNotification::BaseToastNotification(QWidget* parent) : QDialog(parent) #endif Qt::WindowType::FramelessWindowHint | Qt::WindowType::WindowStaysOnTopHint | Qt::WindowType::WindowSystemMenuHint); - setStyleSheet(QSL("BaseToastNotification { border: 1px solid black; }")); + setStyleSheet(QSL("BaseToastNotification { border: 1px solid %1; }").arg(palette().windowText().color().name())); installEventFilter(this); } diff --git a/src/librssguard/gui/notifications/basetoastnotification.h b/src/librssguard/gui/notifications/basetoastnotification.h index 34704c917..654e937ea 100644 --- a/src/librssguard/gui/notifications/basetoastnotification.h +++ b/src/librssguard/gui/notifications/basetoastnotification.h @@ -14,9 +14,6 @@ class BaseToastNotification : public QDialog { explicit BaseToastNotification(QWidget* parent = nullptr); virtual ~BaseToastNotification(); - // If true, then notification is always moved as close to top as possible. - virtual bool alwaysOnTop() const = 0; - public slots: virtual void reject(); diff --git a/src/librssguard/gui/notifications/toastnotification.cpp b/src/librssguard/gui/notifications/toastnotification.cpp index bb2dd3d11..8918bb749 100644 --- a/src/librssguard/gui/notifications/toastnotification.cpp +++ b/src/librssguard/gui/notifications/toastnotification.cpp @@ -21,7 +21,7 @@ ToastNotification::ToastNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action, QWidget* parent) - : BaseToastNotification(parent) { + : BaseToastNotification() { m_ui.setupUi(this); setupHeading(); @@ -31,10 +31,6 @@ ToastNotification::ToastNotification(Notification::Event event, loadNotification(event, msg, action); } -bool ToastNotification::alwaysOnTop() const { - return false; -} - void ToastNotification::loadNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action) { m_ui.m_lblTitle->setText(msg.m_title); m_ui.m_lblBody->setText(msg.m_message); diff --git a/src/librssguard/gui/notifications/toastnotification.h b/src/librssguard/gui/notifications/toastnotification.h index b14f8bbd0..c919fe023 100644 --- a/src/librssguard/gui/notifications/toastnotification.h +++ b/src/librssguard/gui/notifications/toastnotification.h @@ -18,8 +18,6 @@ class ToastNotification : public BaseToastNotification { const GuiAction& action, QWidget* parent = nullptr); - virtual bool alwaysOnTop() const; - private: void setupHeading(); void loadNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action); diff --git a/src/librssguard/gui/notifications/toastnotificationsmanager.cpp b/src/librssguard/gui/notifications/toastnotificationsmanager.cpp index cb6235d61..73547ad85 100644 --- a/src/librssguard/gui/notifications/toastnotificationsmanager.cpp +++ b/src/librssguard/gui/notifications/toastnotificationsmanager.cpp @@ -4,14 +4,16 @@ #include "3rd-party/boolinq/boolinq.h" #include "gui/notifications/basetoastnotification.h" + +#include "gui/notifications/articlelistnotification.h" #include "gui/notifications/toastnotification.h" #include #include #include -ToastNotificationsManager::ToastNotificationsManager(QObject* parent) - : QObject(parent), m_position(NotificationPosition::BottomRight), m_screen(-1) {} +ToastNotificationsManager::ToastNotificationsManager(NotificationPosition position, int screen, QObject* parent) + : QObject(parent), m_position(position), m_screen(screen), m_articleListNotification(nullptr) {} ToastNotificationsManager::~ToastNotificationsManager() { clear(); @@ -39,7 +41,7 @@ void ToastNotificationsManager::setPosition(NotificationPosition position) { void ToastNotificationsManager::clear() { for (BaseToastNotification* notif : m_activeNotifications) { - closeNotification(notif); + closeNotification(notif, true); } m_activeNotifications.clear(); @@ -74,12 +76,48 @@ void ToastNotificationsManager::showNotification(Notification::Event event, m_activeNotifications.prepend(notif); } -void ToastNotificationsManager::showNotification(const QList& new_messages) {} +void ToastNotificationsManager::showNotification(const QList& new_messages) { + if (m_articleListNotification == nullptr) { + m_articleListNotification = new ArticleListNotification(); + hookNotification(m_articleListNotification); + } -void ToastNotificationsManager::closeNotification(BaseToastNotification* notif) { + if (!m_activeNotifications.isEmpty() && m_activeNotifications.first() != m_articleListNotification) { + // Article notification is somewhere in list, clear first to move it to first positon. + closeNotification(m_articleListNotification, false); + } + + auto* screen = moveToProperScreen(m_articleListNotification); + + // Insert new notification into free space. + m_articleListNotification->show(); + + auto notif_new_pos = cornerForNewNotification(screen->availableGeometry()); + + // Make sure notification is finally resized. + m_articleListNotification->adjustSize(); + qApp->processEvents(); + + // Move notification, at this point we already need to know its precise size. + moveNotificationToCorner(m_articleListNotification, notif_new_pos); + + // Remove out-of-bounds old notifications and shift existing + // ones to make space for new notifications. + removeOutOfBoundsNotifications(m_articleListNotification->height()); + makeSpaceForNotification(m_articleListNotification->height()); + + m_activeNotifications.prepend(m_articleListNotification); +} + +void ToastNotificationsManager::closeNotification(BaseToastNotification* notif, bool delete_from_memory) { auto notif_idx = m_activeNotifications.indexOf(notif); - notif->deleteLater(); + if (delete_from_memory) { + notif->deleteLater(); + } + else { + notif->hide(); + } m_activeNotifications.removeAll(notif); @@ -121,7 +159,9 @@ QPoint ToastNotificationsManager::cornerForNewNotification(QRect screen_rect) { } void ToastNotificationsManager::hookNotification(BaseToastNotification* notif) { - connect(notif, &BaseToastNotification::closeRequested, this, &ToastNotificationsManager::closeNotification); + connect(notif, &BaseToastNotification::closeRequested, this, [this](BaseToastNotification* notif) { + closeNotification(notif, false); + }); } void ToastNotificationsManager::moveNotificationToCorner(BaseToastNotification* notif, QPoint corner) { diff --git a/src/librssguard/gui/notifications/toastnotificationsmanager.h b/src/librssguard/gui/notifications/toastnotificationsmanager.h index 9b8bedb8e..1a28ca677 100644 --- a/src/librssguard/gui/notifications/toastnotificationsmanager.h +++ b/src/librssguard/gui/notifications/toastnotificationsmanager.h @@ -9,6 +9,7 @@ class BaseToastNotification; class ToastNotification; +class ArticleListNotification; class QScreen; class ToastNotificationsManager : public QObject { @@ -22,7 +23,9 @@ class ToastNotificationsManager : public QObject { BottomRight = 3 }; - explicit ToastNotificationsManager(QObject* parent = nullptr); + explicit ToastNotificationsManager(ToastNotificationsManager::NotificationPosition position, + int screen, + QObject* parent = nullptr); virtual ~ToastNotificationsManager(); QList activeNotifications() const; @@ -41,7 +44,7 @@ class ToastNotificationsManager : public QObject { void showNotification(const QList& new_messages); private slots: - void closeNotification(BaseToastNotification* notif); + void closeNotification(BaseToastNotification* notif, bool delete_from_memory); private: QScreen* activeScreen() const; @@ -60,6 +63,8 @@ class ToastNotificationsManager : public QObject { // List of all displayed notifications, newest notifications are in the beginning of the list // and oldest at the end. QList m_activeNotifications; + + ArticleListNotification* m_articleListNotification; }; #endif // TOASTNOTIFICATIONSMANAGER_H diff --git a/src/librssguard/gui/settings/settingsnotifications.cpp b/src/librssguard/gui/settings/settingsnotifications.cpp index e18ebe0ef..672062450 100644 --- a/src/librssguard/gui/settings/settingsnotifications.cpp +++ b/src/librssguard/gui/settings/settingsnotifications.cpp @@ -18,6 +18,21 @@ SettingsNotifications::SettingsNotifications(Settings* settings, QWidget* parent connect(m_ui.m_checkEnableNotifications, &QCheckBox::toggled, this, &SettingsNotifications::dirtifySettings); connect(m_ui.m_editor, &NotificationsEditor::someNotificationChanged, this, &SettingsNotifications::dirtifySettings); + + connect(m_ui.m_rbCustomNotifications, &QRadioButton::toggled, this, &SettingsNotifications::dirtifySettings); + connect(m_ui.m_rbCustomNotifications, &QRadioButton::toggled, this, &SettingsNotifications::requireRestart); + + connect(m_ui.m_rbNativeNotifications, &QRadioButton::toggled, this, &SettingsNotifications::dirtifySettings); + connect(m_ui.m_rbNativeNotifications, &QRadioButton::toggled, this, &SettingsNotifications::requireRestart); + + connect(m_ui.m_cbCustomNotificationsPosition, + &QComboBox::currentIndexChanged, + this, + &SettingsNotifications::dirtifySettings); + connect(m_ui.m_cbCustomNotificationsPosition, + &QComboBox::currentIndexChanged, + this, + &SettingsNotifications::requireRestart); } void SettingsNotifications::loadSettings() { diff --git a/src/librssguard/gui/settings/settingsnotifications.ui b/src/librssguard/gui/settings/settingsnotifications.ui index a67f9ac10..917ffadf7 100644 --- a/src/librssguard/gui/settings/settingsnotifications.ui +++ b/src/librssguard/gui/settings/settingsnotifications.ui @@ -37,7 +37,7 @@ - Notifications type + Balloon notifications type @@ -45,6 +45,9 @@ Native notifications (tray icon must be enabled) + + true + diff --git a/src/librssguard/miscellaneous/application.cpp b/src/librssguard/miscellaneous/application.cpp index 330f94215..0e669ca8c 100644 --- a/src/librssguard/miscellaneous/application.cpp +++ b/src/librssguard/miscellaneous/application.cpp @@ -110,7 +110,12 @@ Application::Application(const QString& id, int& argc, char** argv, const QStrin m_database = new DatabaseFactory(this); m_downloadManager = nullptr; m_notifications = new NotificationFactory(this); - m_toastNotifications = new ToastNotificationsManager(this); + m_toastNotifications = + new ToastNotificationsManager(settings() + ->value(GROUP(GUI), SETTING(GUI::ToastNotificationsPosition)) + .value(), + settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsScreen)).toInt(), + this); m_shouldRestart = false; #if defined(Q_OS_WIN) diff --git a/src/librssguard/miscellaneous/feedreader.cpp b/src/librssguard/miscellaneous/feedreader.cpp index 4e1fd627e..c9ccbef19 100644 --- a/src/librssguard/miscellaneous/feedreader.cpp +++ b/src/librssguard/miscellaneous/feedreader.cpp @@ -255,6 +255,19 @@ void FeedReader::removeMessageFilterToFeedAssignment(Feed* feed, MessageFilter* } void FeedReader::updateAllFeeds() { + qApp + ->showGuiMessage(Notification::Event::GeneralEvent, + GuiMessage(QDateTime::currentDateTime().toString(), + "Quisque ullamcorper ut purus nec tempus. Vivamus eros dolor, sagittis ultrices augue " + "ut, posuere fringilla lorem. Donec posuere, enim sit amet fermentum dignissim, tellus " + "lectus laoreet lectus, vestibulum laoreet felis tortor eget nunc. Curabitur sagittis " + "quam in scelerisque placerat. Vivamus vel porta tortor. Vivamus nec volutpat sem", + QSystemTrayIcon::MessageIcon::Information), + GuiMessageDestination(), + GuiAction("test", []() { + qDebugNN << "aa"; + })); + updateFeeds(m_feedsModel->rootItem()->getSubTreeFeeds()); } diff --git a/src/librssguard/miscellaneous/settings.cpp b/src/librssguard/miscellaneous/settings.cpp index f9f7d5996..a2d4fb76f 100644 --- a/src/librssguard/miscellaneous/settings.cpp +++ b/src/librssguard/miscellaneous/settings.cpp @@ -292,6 +292,9 @@ DKEY GUI::ToastNotificationsPosition = "toast_notifications_position"; DVALUE(ToastNotificationsManager::NotificationPosition) GUI::ToastNotificationsPositionDef = ToastNotificationsManager::NotificationPosition::BottomRight; +DKEY GUI::ToastNotificationsScreen = "toast_notifications_screen"; +DVALUE(int) GUI::ToastNotificationsScreenDef = -1; + DKEY GUI::HideMainWindowWhenMinimized = "hide_when_minimized"; DVALUE(bool) GUI::HideMainWindowWhenMinimizedDef = false; diff --git a/src/librssguard/miscellaneous/settings.h b/src/librssguard/miscellaneous/settings.h index 986957273..e048d367f 100644 --- a/src/librssguard/miscellaneous/settings.h +++ b/src/librssguard/miscellaneous/settings.h @@ -225,6 +225,9 @@ namespace GUI { KEY ToastNotificationsPosition; VALUE(ToastNotificationsManager::NotificationPosition) ToastNotificationsPositionDef; + KEY ToastNotificationsScreen; + VALUE(int) ToastNotificationsScreenDef; + KEY MessageViewState; VALUE(QString) MessageViewStateDef;