summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonathan Feenstra <26406078+JonathanFeenstra@users.noreply.github.com>2026-05-15 09:23:09 +0200
committerGitHub <noreply@github.com>2026-05-15 02:23:09 -0500
commit55de581ee9829c5fcb5bae37504fad4e89cac721 (patch)
treed126ea862033f96da7381fc40322216af51adf66 /src
parent6748953d35516b948d83dd135cc970c805efeff0 (diff)
Add setting to show notifications when downloads complete or fail (#2338)
Diffstat (limited to 'src')
-rw-r--r--src/downloadmanager.cpp16
-rw-r--r--src/downloadmanager.h2
-rw-r--r--src/iuserinterface.h5
-rw-r--r--src/mainwindow.cpp7
-rw-r--r--src/mainwindow.h5
-rw-r--r--src/organizercore.cpp9
-rw-r--r--src/organizercore.h5
-rw-r--r--src/settings.cpp10
-rw-r--r--src/settings.h5
-rw-r--r--src/settingsdialog.ui17
-rw-r--r--src/settingsdialoggeneral.cpp4
-rw-r--r--src/systemtraymanager.cpp11
-rw-r--r--src/systemtraymanager.h6
13 files changed, 97 insertions, 5 deletions
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp
index 4e667e0f..2d9cdd45 100644
--- a/src/downloadmanager.cpp
+++ b/src/downloadmanager.cpp
@@ -42,6 +42,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QHttp2Configuration>
#include <QInputDialog>
#include <QMessageBox>
+#include <QSystemTrayIcon>
#include <QTextDocument>
#include <QTimer>
@@ -1403,7 +1404,11 @@ QString DownloadManager::getDisplayName(int index) const
}
DownloadInfo* info = m_ActiveDownloads.at(index);
+ return displayNameByInfo(info);
+}
+QString DownloadManager::displayNameByInfo(const DownloadInfo* info) const
+{
QTextDocument doc;
if (!info->m_FileInfo->name.isEmpty()) {
doc.setHtml(info->m_FileInfo->name);
@@ -1817,6 +1822,11 @@ void DownloadManager::nxmDescriptionAvailable(QString, int, QVariant userData,
info->m_FileInfo->modName = doc.toPlainText();
if (info->m_FileInfo->fileID != 0) {
setState(info, STATE_READY);
+ if (m_OrganizerCore->settings().interface().showDownloadNotifications()) {
+ m_OrganizerCore->showNotification(
+ tr("Download complete"),
+ tr("%1 is ready to be installed.").arg(displayNameByInfo(info)));
+ }
} else {
setState(info, STATE_FETCHINGFILEINFO);
}
@@ -2392,6 +2402,12 @@ void DownloadManager::finishDownload(DownloadID id)
emit showMessage(tr("Download failed: %1 (%2)")
.arg(reply->errorString())
.arg(reply->error()));
+ if (m_OrganizerCore->settings().interface().showDownloadNotifications()) {
+ m_OrganizerCore->showNotification(
+ tr("Download failed"),
+ tr("%1 failed to download.").arg(displayNameByInfo(info)),
+ QSystemTrayIcon::MessageIcon::Critical);
+ }
}
error = true;
setState(info, STATE_ERROR);
diff --git a/src/downloadmanager.h b/src/downloadmanager.h
index 9c8e391d..876978b2 100644
--- a/src/downloadmanager.h
+++ b/src/downloadmanager.h
@@ -759,6 +759,8 @@ private:
DownloadInfo* downloadInfoByID(DownloadID id);
+ QString displayNameByInfo(const DownloadInfo* info) const;
+
void removePending(QString gameName, int modID, int fileID);
/**
diff --git a/src/iuserinterface.h b/src/iuserinterface.h
index 7ddc545d..ae5ed880 100644
--- a/src/iuserinterface.h
+++ b/src/iuserinterface.h
@@ -4,6 +4,7 @@
#include "modinfodialogfwd.h"
#include <QMainWindow>
#include <QMenu>
+#include <QSystemTrayIcon>
#include <delayedfilewriter.h>
#include <ipluginmodpage.h>
#include <iplugintool.h>
@@ -27,6 +28,10 @@ public:
virtual MOBase::DelayedFileWriterBase& archivesWriter() = 0;
virtual QMainWindow* mainWindow() = 0;
+
+ virtual void showNotification(const QString& title, const QString& message,
+ QSystemTrayIcon::MessageIcon icon =
+ QSystemTrayIcon::MessageIcon::Information) = 0;
};
#endif // IUSERINTERFACE_H
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 0a4fba2e..6a662173 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -142,6 +142,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QShortcut>
#include <QSize>
#include <QSizePolicy>
+#include <QSystemTrayIcon>
#include <QTime>
#include <QTimer>
#include <QToolButton>
@@ -2266,6 +2267,12 @@ QMainWindow* MainWindow::mainWindow()
return this;
}
+void MainWindow::showNotification(const QString& title, const QString& message,
+ QSystemTrayIcon::MessageIcon icon)
+{
+ m_SystemTrayManager->showNotification(title, message, icon);
+}
+
void MainWindow::on_tabWidget_currentChanged(int index)
{
QWidget* currentWidget = ui->tabWidget->widget(index);
diff --git a/src/mainwindow.h b/src/mainwindow.h
index d3e1d480..cc7e3366 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -78,6 +78,7 @@ class DirectoryEntry;
#include <QProcess>
#include <QString>
#include <QStringList>
+#include <QSystemTrayIcon>
#include <QTime>
#include <QTimer>
#include <QVariant>
@@ -156,6 +157,10 @@ public:
return m_ArchiveListWriter;
}
+ void showNotification(const QString& title, const QString& message,
+ QSystemTrayIcon::MessageIcon icon =
+ QSystemTrayIcon::MessageIcon::Information) override;
+
public slots:
void refresherProgress(const DirectoryRefreshProgress* p);
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index 68ccd2ff..27ab9713 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -46,6 +46,7 @@
#include <QMessageBox>
#include <QNetworkInterface>
#include <QProcess>
+#include <QSystemTrayIcon>
#include <QTimer>
#include <QUrl>
#include <QWidget>
@@ -541,6 +542,14 @@ std::wstring OrganizerCore::getGlobalCoreDumpPath()
return {};
}
+void OrganizerCore::showNotification(const QString& message, const QString& title,
+ QSystemTrayIcon::MessageIcon icon)
+{
+ if (m_UserInterface) {
+ m_UserInterface->showNotification(message, title, icon);
+ }
+}
+
void OrganizerCore::setCurrentProfile(const QString& profileName)
{
if ((m_CurrentProfile != nullptr) && (profileName == m_CurrentProfile->name())) {
diff --git a/src/organizercore.h b/src/organizercore.h
index 80f340b6..d7810e1b 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -8,6 +8,7 @@
#include <QSettings>
#include <QString>
#include <QStringList>
+#include <QSystemTrayIcon>
#include <QThread>
#include <QVariant>
@@ -360,6 +361,10 @@ public:
static void setGlobalCoreDumpType(env::CoreDumpTypes type);
static std::wstring getGlobalCoreDumpPath();
+ void showNotification(
+ const QString& title, const QString& message,
+ QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon::Information);
+
public:
MOBase::IModRepositoryBridge* createNexusBridge() const;
QString profileName() const;
diff --git a/src/settings.cpp b/src/settings.cpp
index 849f64ec..a7c46458 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -2302,6 +2302,16 @@ void InterfaceSettings::setHideDownloadsAfterInstallation(bool b)
set(m_Settings, "Settings", "autohide_downloads", b);
}
+bool InterfaceSettings::showDownloadNotifications() const
+{
+ return get<bool>(m_Settings, "Settings", "download_notifications", false);
+}
+
+void InterfaceSettings::setShowDownloadNotifications(bool b)
+{
+ set(m_Settings, "Settings", "download_notifications", b);
+}
+
bool InterfaceSettings::hideAPICounter() const
{
return get<bool>(m_Settings, "Settings", "hide_api_counter", false);
diff --git a/src/settings.h b/src/settings.h
index 28eeb1fd..5b2c6ee7 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -654,6 +654,11 @@ public:
bool hideDownloadsAfterInstallation() const;
void setHideDownloadsAfterInstallation(bool b);
+ // whether to show notifications when downloads complete or fail
+ //
+ bool showDownloadNotifications() const;
+ void setShowDownloadNotifications(bool b);
+
// whether the API counter should be hidden
//
bool hideAPICounter() const;
diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui
index 9e335909..9a7ce3bc 100644
--- a/src/settingsdialog.ui
+++ b/src/settingsdialog.ui
@@ -166,6 +166,19 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="showDownloadNotificationsBox">
+ <property name="toolTip">
+ <string>Show notifications when downloads complete or fail.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Show notifications when downloads complete or fail.</string>
+ </property>
+ <property name="text">
+ <string>Show notifications for completed or failed downloads</string>
+ </property>
+ </widget>
+ </item>
<item alignment="Qt::AlignmentFlag::AlignLeft">
<widget class="QPushButton" name="associateModlButton">
<property name="maximumSize">
@@ -191,10 +204,10 @@
<item>
<widget class="QCheckBox" name="checkForUpdates">
<property name="toolTip">
- <string>Check for Mod Organizer updates on Github on startup.</string>
+ <string>Check for Mod Organizer updates on GitHub on startup.</string>
</property>
<property name="whatsThis">
- <string>Check for Mod Organizer updates on Github on startup.</string>
+ <string>Check for Mod Organizer updates on GitHub on startup.</string>
</property>
<property name="text">
<string>Check for updates</string>
diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp
index 374eb621..ab68b3f2 100644
--- a/src/settingsdialoggeneral.cpp
+++ b/src/settingsdialoggeneral.cpp
@@ -20,6 +20,8 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d)
ui->showMetaBox->setChecked(settings().interface().metaDownloads());
ui->hideDownloadInstallBox->setChecked(
settings().interface().hideDownloadsAfterInstallation());
+ ui->showDownloadNotificationsBox->setChecked(
+ settings().interface().showDownloadNotifications());
// connect MODL button
QObject::connect(ui->associateModlButton, &QPushButton::clicked, [&] {
@@ -69,6 +71,8 @@ void GeneralSettingsTab::update()
settings().interface().setMetaDownloads(ui->showMetaBox->isChecked());
settings().interface().setHideDownloadsAfterInstallation(
ui->hideDownloadInstallBox->isChecked());
+ settings().interface().setShowDownloadNotifications(
+ ui->showDownloadNotificationsBox->isChecked());
// updates
settings().setCheckForUpdates(ui->checkForUpdates->isChecked());
diff --git a/src/systemtraymanager.cpp b/src/systemtraymanager.cpp
index d885f1eb..afbd598d 100644
--- a/src/systemtraymanager.cpp
+++ b/src/systemtraymanager.cpp
@@ -24,6 +24,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QIcon>
#include <QMainWindow>
#include <QMenu>
+#include <QString>
#include <QSystemTrayIcon>
SystemTrayManager::SystemTrayManager(QMainWindow* parent, QDockWidget* logDock)
@@ -42,11 +43,11 @@ SystemTrayManager::SystemTrayManager(QMainWindow* parent, QDockWidget* logDock)
trayMenu->addAction(exitAction);
m_SystemTrayIcon->setContextMenu(trayMenu);
+ m_SystemTrayIcon->show();
}
void SystemTrayManager::minimizeToSystemTray()
{
- m_SystemTrayIcon->show();
m_Parent->hide();
if (m_LogDock->isFloating() && m_LogDock->isVisible()) {
@@ -56,8 +57,6 @@ void SystemTrayManager::minimizeToSystemTray()
void SystemTrayManager::restoreFromSystemTray()
{
- m_SystemTrayIcon->hide();
-
m_Parent->showNormal();
m_Parent->raise();
m_Parent->activateWindow();
@@ -67,6 +66,12 @@ void SystemTrayManager::restoreFromSystemTray()
}
}
+void SystemTrayManager::showNotification(const QString& title, const QString& message,
+ QSystemTrayIcon::MessageIcon icon)
+{
+ m_SystemTrayIcon->showMessage(title, message, icon);
+}
+
void SystemTrayManager::on_systemTrayIcon_activated(
QSystemTrayIcon::ActivationReason reason)
{
diff --git a/src/systemtraymanager.h b/src/systemtraymanager.h
index 43a3b0e4..e7e03c09 100644
--- a/src/systemtraymanager.h
+++ b/src/systemtraymanager.h
@@ -21,8 +21,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#define SYSTEMTRAYMANAGER_H
#include <QDockWidget>
+#include <QIcon>
#include <QMainWindow>
#include <QObject>
+#include <QString>
#include <QSystemTrayIcon>
class SystemTrayManager : public QObject
@@ -35,6 +37,10 @@ public:
void minimizeToSystemTray();
void restoreFromSystemTray();
+ void showNotification(
+ const QString& title, const QString& message,
+ QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon::Information);
+
private:
QMainWindow* m_Parent;
QDockWidget* m_LogDock;