diff --git a/src/gui/accountmanager.cpp b/src/gui/accountmanager.cpp index 76c94eb2a8..e78d760960 100644 --- a/src/gui/accountmanager.cpp +++ b/src/gui/accountmanager.cpp @@ -287,6 +287,7 @@ bool AccountManager::restoreFromLegacySettings() configFile.setPromptDeleteFiles(settings->value(ConfigFile::promptDeleteC, configFile.promptDeleteFiles()).toBool()); configFile.setShowCallNotifications(settings->value(ConfigFile::showCallNotificationsC, configFile.showCallNotifications()).toBool()); configFile.setShowChatNotifications(settings->value(ConfigFile::showChatNotificationsC, configFile.showChatNotifications()).toBool()); + configFile.setShowQuotaWarningNotifications(settings->value(ConfigFile::showQuotaWarningNotificationsC, configFile.showQuotaWarningNotifications()).toBool()); configFile.setShowInExplorerNavigationPane(settings->value(ConfigFile::showInExplorerNavigationPaneC, configFile.showInExplorerNavigationPane()).toBool()); ClientProxy().saveProxyConfigurationFromSettings(*settings); configFile.setUseUploadLimit(settings->value(ConfigFile::useUploadLimitC, configFile.useUploadLimit()).toInt()); diff --git a/src/gui/generalsettings.cpp b/src/gui/generalsettings.cpp index 10271ecc1e..a9b3c6c818 100644 --- a/src/gui/generalsettings.cpp +++ b/src/gui/generalsettings.cpp @@ -195,6 +195,9 @@ GeneralSettings::GeneralSettings(QWidget *parent) this, &GeneralSettings::slotToggleCallNotifications); _ui->callNotificationsCheckBox->setToolTip(tr("Show call notification dialogs.")); + connect(_ui->quotaWarningNotificationsCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::slotToggleQuotaWarningNotifications); + _ui->quotaWarningNotificationsCheckBox->setToolTip(tr("Show notification when quota usage exceeds 80%.")); + connect(_ui->showInExplorerNavigationPaneCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::slotShowInExplorerNavigationPane); // Rename 'Explorer' appropriately on non-Windows @@ -298,6 +301,8 @@ void GeneralSettings::loadMiscSettings() _ui->chatNotificationsCheckBox->setChecked(cfgFile.showChatNotifications()); _ui->callNotificationsCheckBox->setEnabled(cfgFile.optionalServerNotifications()); _ui->callNotificationsCheckBox->setChecked(cfgFile.showCallNotifications()); + _ui->quotaWarningNotificationsCheckBox->setEnabled(cfgFile.optionalServerNotifications()); + _ui->quotaWarningNotificationsCheckBox->setChecked(cfgFile.showQuotaWarningNotifications()); _ui->showInExplorerNavigationPaneCheckBox->setChecked(cfgFile.showInExplorerNavigationPane()); _ui->newExternalStorage->setChecked(cfgFile.confirmExternalStorage()); _ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons()); @@ -594,6 +599,12 @@ void GeneralSettings::slotToggleCallNotifications(bool enable) cfgFile.setShowCallNotifications(enable); } +void GeneralSettings::slotToggleQuotaWarningNotifications(bool enable) +{ + ConfigFile cfgFile; + cfgFile.setShowQuotaWarningNotifications(enable); +} + void GeneralSettings::slotShowInExplorerNavigationPane(bool checked) { ConfigFile cfgFile; diff --git a/src/gui/generalsettings.h b/src/gui/generalsettings.h index 2c52ff0080..b62a7b3c07 100644 --- a/src/gui/generalsettings.h +++ b/src/gui/generalsettings.h @@ -49,6 +49,7 @@ private slots: void slotToggleOptionalServerNotifications(bool); void slotToggleChatNotifications(bool); void slotToggleCallNotifications(bool); + void slotToggleQuotaWarningNotifications(bool); void slotShowInExplorerNavigationPane(bool); void slotIgnoreFilesEditor(); void slotCreateDebugArchive(); diff --git a/src/gui/generalsettings.ui b/src/gui/generalsettings.ui index 0a20f0b68c..b26f433ed2 100644 --- a/src/gui/generalsettings.ui +++ b/src/gui/generalsettings.ui @@ -58,6 +58,13 @@ + + + + Show &Quota Warning Notifications + + + diff --git a/src/gui/tray/usermodel.cpp b/src/gui/tray/usermodel.cpp index a2929b5339..f5a7946071 100644 --- a/src/gui/tray/usermodel.cpp +++ b/src/gui/tray/usermodel.cpp @@ -24,12 +24,14 @@ #include "tray/talkreply.h" #include "userstatusconnector.h" +#include #include #include #include #include #include #include +#include // time span in milliseconds which has to be between two // refreshes of the notifications @@ -83,6 +85,7 @@ User::User(AccountStatePtr &account, const bool &isCurrent, QObject *parent) connect(_account.data(), &AccountState::hasFetchedNavigationApps, this, &User::slotRebuildNavigationAppList); connect(_account->account().data(), &Account::accountChangedDisplayName, this, &User::nameChanged); + connect(_account->account().data(), &Account::rootFolderQuotaChanged, this, &User::slotQuotaChanged); connect(FolderMan::instance(), &FolderMan::folderListChanged, this, &User::hasLocalFolderChanged); @@ -1192,6 +1195,44 @@ void User::slotFetchGroupFolders() connect(groupFolderListJob, &SimpleNetworkJob::finishedSignal, this, &User::slotGroupFoldersFetched); } +void User::slotQuotaChanged(const int64_t &usedBytes, const int64_t &availableBytes) +{ + int64_t total = usedBytes + availableBytes; + if (total <= 0 || !ConfigFile().showQuotaWarningNotifications()) { + return; + } + + const auto percent = (double)usedBytes / (double)total * 100.0; + const auto percentInt = qMin(qRound(percent), 100); + qCDebug(lcActivity) << tr("Quota is updated; %1 percent of the total space is used.").arg(QString::number(percentInt)); + + int thresholdPassed = 0; + if (_lastQuotaPercent < 80 && percentInt >= 80) { + thresholdPassed = 80; + } + + if (_lastQuotaPercent < 90 && percentInt >= 90) { + thresholdPassed = 90; + } + + if (_lastQuotaPercent < 95 && percentInt >= 95) { + thresholdPassed = 95; + } + + if (thresholdPassed > 0) { + _activityModel->removeActivityFromActivityList(_lastQuotaActivity); + + _lastQuotaActivity._type = Activity::OpenSettingsNotificationType; + _lastQuotaActivity._dateTime = QDateTime::fromString(QDateTime::currentDateTime().toString(), Qt::ISODate); + _lastQuotaActivity._subject = tr("Quota Warning - %1 percent or more storage in use").arg(QString::number(thresholdPassed)); + _lastQuotaActivity._accName = account()->displayName(); + _lastQuotaActivity._id = qHash(QDateTime::currentMSecsSinceEpoch()); + showDesktopNotification(_lastQuotaActivity); + _activityModel->addNotificationToActivityList(_lastQuotaActivity); + } + _lastQuotaPercent = percentInt; +} + void User::slotGroupFoldersFetched(QNetworkReply *reply) { Q_ASSERT(reply); diff --git a/src/gui/tray/usermodel.h b/src/gui/tray/usermodel.h index e8ca2a153b..0f7fd54834 100644 --- a/src/gui/tray/usermodel.h +++ b/src/gui/tray/usermodel.h @@ -18,6 +18,7 @@ #include "activitydata.h" #include "activitylistmodel.h" #include "folderman.h" +#include "userinfo.h" #include "userstatusconnector.h" #include "userstatusselectormodel.h" #include @@ -161,6 +162,7 @@ private slots: void slotReceivedPushActivity(OCC::Account *account); void slotCheckExpiredActivities(); void slotGroupFoldersFetched(QNetworkReply *reply); + void slotQuotaChanged(const int64_t &usedBytes, const int64_t &availableBytes); void checkNotifiedNotifications(); void showDesktopNotification(const QString &title, const QString &message, const long notificationId); void showDesktopNotification(const OCC::Activity &activity); @@ -206,6 +208,10 @@ private: int _lastTalkNotificationsReceivedCount = 0; bool _isNotificationFetchRunning = false; + + // used for quota warnings + int _lastQuotaPercent = 0; + Activity _lastQuotaActivity; }; class UserModel : public QAbstractListModel diff --git a/src/libsync/account.h b/src/libsync/account.h index 5434904ec5..bbb198762d 100644 --- a/src/libsync/account.h +++ b/src/libsync/account.h @@ -470,6 +470,7 @@ signals: void encryptionCertificateFingerprintChanged(); void userCertificateNeedsMigrationChanged(); + void rootFolderQuotaChanged(const int64_t &usedBytes, const int64_t &availableBytes); protected Q_SLOTS: void slotCredentialsFetched(); void slotCredentialsAsked(); diff --git a/src/libsync/configfile.cpp b/src/libsync/configfile.cpp index d512fba3af..71ac126d46 100644 --- a/src/libsync/configfile.cpp +++ b/src/libsync/configfile.cpp @@ -216,6 +216,19 @@ void ConfigFile::setShowCallNotifications(bool show) settings.sync(); } +bool ConfigFile::showQuotaWarningNotifications() const +{ + const QSettings settings(configFile(), QSettings::IniFormat); + return settings.value(showQuotaWarningNotificationsC, true).toBool() && optionalServerNotifications(); +} + +void ConfigFile::setShowQuotaWarningNotifications(bool show) +{ + QSettings settings(configFile(), QSettings::IniFormat); + settings.setValue(showQuotaWarningNotificationsC, show); + settings.sync(); +} + bool ConfigFile::showInExplorerNavigationPane() const { const bool defaultValue = diff --git a/src/libsync/configfile.h b/src/libsync/configfile.h index c2b22f0c6e..92f960a5c5 100644 --- a/src/libsync/configfile.h +++ b/src/libsync/configfile.h @@ -165,6 +165,9 @@ public: [[nodiscard]] bool showCallNotifications() const; void setShowCallNotifications(bool show); + [[nodiscard]] bool showQuotaWarningNotifications() const; + void setShowQuotaWarningNotifications(bool show); + [[nodiscard]] bool showInExplorerNavigationPane() const; void setShowInExplorerNavigationPane(bool show); @@ -257,6 +260,7 @@ public: static constexpr char optionalServerNotificationsC[] = "optionalServerNotifications"; static constexpr char promptDeleteC[] = "promptDeleteAllFiles"; static constexpr char showCallNotificationsC[] = "showCallNotifications"; + static constexpr char showQuotaWarningNotificationsC[] = "showQuotaWarningNotifications"; static constexpr char showChatNotificationsC[] = "showChatNotifications"; static constexpr char showInExplorerNavigationPaneC[] = "showInExplorerNavigationPane"; diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index 1b314040d6..a5e53ce32b 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -2299,6 +2299,10 @@ void ProcessDirectoryJob::setFolderQuota(const FolderQuota &folderQuota) { _folderQuota.bytesUsed = folderQuota.bytesUsed; _folderQuota.bytesAvailable = folderQuota.bytesAvailable; + + if (_currentFolder._original.isEmpty()) { + emit updatedRootFolderQuota(_folderQuota.bytesUsed, _folderQuota.bytesAvailable); + } } void ProcessDirectoryJob::startAsyncLocalQuery() diff --git a/src/libsync/discovery.h b/src/libsync/discovery.h index 164de5662c..1dc2de2350 100644 --- a/src/libsync/discovery.h +++ b/src/libsync/discovery.h @@ -305,6 +305,7 @@ signals: void finished(); // The root etag of this directory was fetched void etag(const QByteArray &, const QDateTime &time); + void updatedRootFolderQuota(const int64_t &bytesUsed, const int64_t &bytesAvailable); private slots: void setFolderQuota(const FolderQuota &folderQuota); diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index 7b4b69f4f9..a9ca164038 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -760,6 +760,7 @@ void SyncEngine::startSync() _discoveryPhase->startJob(discoveryJob); connect(discoveryJob, &ProcessDirectoryJob::etag, this, &SyncEngine::slotRootEtagReceived); + connect(discoveryJob, &ProcessDirectoryJob::updatedRootFolderQuota, account().data(), &Account::rootFolderQuotaChanged); connect(_discoveryPhase.get(), &DiscoveryPhase::addErrorToGui, this, &SyncEngine::addErrorToGui); }