From 91dc8b3b08c299e8a3754fe021ceedf1b807f35d Mon Sep 17 00:00:00 2001 From: Phillip Wheatley Date: Tue, 17 Mar 2020 01:49:11 +0000 Subject: [PATCH] Add configuration option to send desktop notification on buddy presence (#3886) --- cockatrice/src/dlg_settings.cpp | 30 +++++++++++++++++------- cockatrice/src/dlg_settings.h | 2 ++ cockatrice/src/settingscache.cpp | 7 ++++++ cockatrice/src/settingscache.h | 6 +++++ cockatrice/src/tab_room.cpp | 11 ++++++--- cockatrice/src/tab_room.h | 1 + cockatrice/src/tab_supervisor.cpp | 39 +++++++++++++++++++++++++++---- cockatrice/src/tab_supervisor.h | 2 ++ 8 files changed, 83 insertions(+), 15 deletions(-) diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp index ed9ed160..83c7c200 100644 --- a/cockatrice/src/dlg_settings.cpp +++ b/cockatrice/src/dlg_settings.cpp @@ -373,6 +373,11 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage() connect(&specNotificationsEnabledCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setSpectatorNotificationsEnabled(int))); + buddyConnectNotificationsEnabledCheckBox.setChecked(settingsCache->getBuddyConnectNotificationsEnabled()); + buddyConnectNotificationsEnabledCheckBox.setEnabled(settingsCache->getNotificationsEnabled()); + connect(&buddyConnectNotificationsEnabledCheckBox, SIGNAL(stateChanged(int)), settingsCache, + SLOT(setBuddyConnectNotificationsEnabled(int))); + doubleClickToPlayCheckBox.setChecked(settingsCache->getDoubleClickToPlay()); connect(&doubleClickToPlayCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setDoubleClickToPlay(int))); @@ -387,16 +392,22 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage() [](int state) { settingsCache->setUseTearOffMenus(state == Qt::Checked); }); auto *generalGrid = new QGridLayout; - generalGrid->addWidget(¬ificationsEnabledCheckBox, 0, 0); - generalGrid->addWidget(&specNotificationsEnabledCheckBox, 1, 0); - generalGrid->addWidget(&doubleClickToPlayCheckBox, 2, 0); - generalGrid->addWidget(&playToStackCheckBox, 3, 0); - generalGrid->addWidget(&annotateTokensCheckBox, 4, 0); - generalGrid->addWidget(&useTearOffMenusCheckBox, 5, 0); + generalGrid->addWidget(&doubleClickToPlayCheckBox, 0, 0); + generalGrid->addWidget(&playToStackCheckBox, 1, 0); + generalGrid->addWidget(&annotateTokensCheckBox, 2, 0); + generalGrid->addWidget(&useTearOffMenusCheckBox, 3, 0); generalGroupBox = new QGroupBox; generalGroupBox->setLayout(generalGrid); + auto *notificationsGrid = new QGridLayout; + notificationsGrid->addWidget(¬ificationsEnabledCheckBox, 0, 0); + notificationsGrid->addWidget(&specNotificationsEnabledCheckBox, 1, 0); + notificationsGrid->addWidget(&buddyConnectNotificationsEnabledCheckBox, 2, 0); + + notificationsGroupBox = new QGroupBox; + notificationsGroupBox->setLayout(notificationsGrid); + tapAnimationCheckBox.setChecked(settingsCache->getTapAnimation()); connect(&tapAnimationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setTapAnimation(int))); @@ -408,6 +419,7 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage() auto *mainLayout = new QVBoxLayout; mainLayout->addWidget(generalGroupBox); + mainLayout->addWidget(notificationsGroupBox); mainLayout->addWidget(animationGroupBox); setLayout(mainLayout); @@ -421,12 +433,14 @@ void UserInterfaceSettingsPage::setSpecNotificationEnabled(int i) void UserInterfaceSettingsPage::retranslateUi() { generalGroupBox->setTitle(tr("General interface settings")); - notificationsEnabledCheckBox.setText(tr("Enable notifications in taskbar")); - specNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar for game events while you are spectating")); doubleClickToPlayCheckBox.setText(tr("&Double-click cards to play them (instead of single-click)")); playToStackCheckBox.setText(tr("&Play all nonlands onto the stack (not the battlefield) by default")); annotateTokensCheckBox.setText(tr("Annotate card text on tokens")); useTearOffMenusCheckBox.setText(tr("Use tear-off menus, allowing right click menus to persist on screen")); + notificationsGroupBox->setTitle(tr("Notifications settings")); + notificationsEnabledCheckBox.setText(tr("Enable notifications in taskbar")); + specNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar for game events while you are spectating")); + buddyConnectNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar when users in your buddy list connect")); animationGroupBox->setTitle(tr("Animation settings")); tapAnimationCheckBox.setText(tr("&Tap/untap animation")); } diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h index 1bab0cb8..96549a64 100644 --- a/cockatrice/src/dlg_settings.h +++ b/cockatrice/src/dlg_settings.h @@ -108,12 +108,14 @@ private slots: private: QCheckBox notificationsEnabledCheckBox; QCheckBox specNotificationsEnabledCheckBox; + QCheckBox buddyConnectNotificationsEnabledCheckBox; QCheckBox doubleClickToPlayCheckBox; QCheckBox playToStackCheckBox; QCheckBox annotateTokensCheckBox; QCheckBox useTearOffMenusCheckBox; QCheckBox tapAnimationCheckBox; QGroupBox *generalGroupBox; + QGroupBox *notificationsGroupBox; QGroupBox *animationGroupBox; public: diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index 1ef51df4..1c7316c5 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -227,6 +227,7 @@ SettingsCache::SettingsCache() tokenDialogGeometry = settings->value("interface/token_dialog_geometry").toByteArray(); notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool(); spectatorNotificationsEnabled = settings->value("interface/specnotificationsenabled", false).toBool(); + buddyConnectNotificationsEnabled = settings->value("interface/buddyconnectnotificationsenabled", true).toBool(); doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool(); playToStack = settings->value("interface/playtostack", true).toBool(); startingHandSize = settings->value("interface/startinghandsize", 7).toInt(); @@ -438,6 +439,12 @@ void SettingsCache::setSpectatorNotificationsEnabled(int _spectatorNotifications settings->setValue("interface/specnotificationsenabled", spectatorNotificationsEnabled); } +void SettingsCache::setBuddyConnectNotificationsEnabled(int _buddyConnectNotificationsEnabled) +{ + buddyConnectNotificationsEnabled = static_cast(_buddyConnectNotificationsEnabled); + settings->setValue("interface/buddyconnectnotificationsenabled", buddyConnectNotificationsEnabled); +} + void SettingsCache::setDoubleClickToPlay(int _doubleClickToPlay) { doubleClickToPlay = static_cast(_doubleClickToPlay); diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h index 933e7ac0..6cbada53 100644 --- a/cockatrice/src/settingscache.h +++ b/cockatrice/src/settingscache.h @@ -77,6 +77,7 @@ private: bool picDownload; bool notificationsEnabled; bool spectatorNotificationsEnabled; + bool buddyConnectNotificationsEnabled; bool doubleClickToPlay; bool playToStack; int startingHandSize; @@ -202,6 +203,10 @@ public: { return spectatorNotificationsEnabled; } + bool getBuddyConnectNotificationsEnabled() const + { + return buddyConnectNotificationsEnabled; + } bool getNotifyAboutUpdates() const { return notifyAboutUpdates; @@ -476,6 +481,7 @@ public slots: void setPicDownload(int _picDownload); void setNotificationsEnabled(int _notificationsEnabled); void setSpectatorNotificationsEnabled(int _spectatorNotificationsEnabled); + void setBuddyConnectNotificationsEnabled(int _buddyConnectNotificationsEnabled); void setDoubleClickToPlay(int _doubleClickToPlay); void setPlayToStack(int _playToStack); void setStartingHandSize(int _startingHandSize); diff --git a/cockatrice/src/tab_room.cpp b/cockatrice/src/tab_room.cpp index 9931821c..016387a3 100644 --- a/cockatrice/src/tab_room.cpp +++ b/cockatrice/src/tab_room.cpp @@ -158,11 +158,16 @@ void TabRoom::focusTab() } void TabRoom::actShowMentionPopup(QString &sender) +{ + this->actShowPopup(sender + tr(" mentioned you.")); +} + +void TabRoom::actShowPopup(const QString &message) { if (trayIcon && (tabSupervisor->currentIndex() != tabSupervisor->indexOf(this) || - QApplication::activeWindow() == 0 || QApplication::focusWidget() == 0)) { - disconnect(trayIcon, SIGNAL(messageClicked()), 0, 0); - trayIcon->showMessage(sender + tr(" mentioned you."), tr("Click to view")); + QApplication::activeWindow() == nullptr || QApplication::focusWidget() == nullptr)) { + disconnect(trayIcon, SIGNAL(messageClicked()), nullptr, nullptr); + trayIcon->showMessage(message, tr("Click to view")); connect(trayIcon, SIGNAL(messageClicked()), chatView, SLOT(actMessageClicked())); } } diff --git a/cockatrice/src/tab_room.h b/cockatrice/src/tab_room.h index c5e41a1b..b1169b69 100644 --- a/cockatrice/src/tab_room.h +++ b/cockatrice/src/tab_room.h @@ -75,6 +75,7 @@ private slots: void addMentionTag(QString mentionTag); void focusTab(); void actShowMentionPopup(QString &sender); + void actShowPopup(const QString &message); void actCompleterChanged(); void processListGamesEvent(const Event_ListGames &event); diff --git a/cockatrice/src/tab_supervisor.cpp b/cockatrice/src/tab_supervisor.cpp index 446170c5..cd026402 100644 --- a/cockatrice/src/tab_supervisor.cpp +++ b/cockatrice/src/tab_supervisor.cpp @@ -1,5 +1,6 @@ #include "tab_supervisor.h" #include "abstractclient.h" +#include "main.h" #include "pixmapgenerator.h" #include "settingscache.h" #include "tab_admin.h" @@ -17,6 +18,7 @@ #include #include #include +#include #include "pb/event_game_joined.pb.h" #include "pb/event_notify_user.pb.h" @@ -441,7 +443,7 @@ void TabSupervisor::replayLeft(TabGame *tab) TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus) { if (receiverName == QString::fromStdString(userInfo->name())) - return 0; + return nullptr; ServerInfo_User otherUser; UserListTWI *twi = tabUserLists->getAllUsersList()->getUsers().value(receiverName); @@ -561,6 +563,17 @@ void TabSupervisor::processUserMessageEvent(const Event_UserMessage &event) tab->processUserMessageEvent(event); } +void TabSupervisor::actShowPopup(const QString &message) +{ + qDebug() << "ACT SHOW POPUP"; + if (trayIcon && (QApplication::activeWindow() == nullptr || QApplication::focusWidget() == nullptr)) { + qDebug() << "LAUNCHING POPUP"; + // disconnect(trayIcon, SIGNAL(messageClicked()), nullptr, nullptr); + trayIcon->showMessage(message, tr("Click to view")); + // connect(trayIcon, SIGNAL(messageClicked()), chatView, SLOT(actMessageClicked())); + } +} + void TabSupervisor::processUserLeft(const QString &userName) { TabMessage *tab = messageTabs.value(userName); @@ -568,11 +581,29 @@ void TabSupervisor::processUserLeft(const QString &userName) tab->processUserLeft(); } -void TabSupervisor::processUserJoined(const ServerInfo_User &userInfo) +void TabSupervisor::processUserJoined(const ServerInfo_User &userInfoJoined) { - TabMessage *tab = messageTabs.value(QString::fromStdString(userInfo.name())); + QString userName = QString::fromStdString(userInfoJoined.name()); + if (isUserBuddy(userName)) { + Tab *tab = static_cast(getUserListsTab()); + + if (tab != currentWidget()) { + tab->setContentsChanged(true); + QPixmap avatarPixmap = + UserLevelPixmapGenerator::generatePixmap(13, (UserLevelFlags)userInfoJoined.user_level(), true, + QString::fromStdString(userInfoJoined.privlevel())); + setTabIcon(indexOf(tab), QPixmap(avatarPixmap)); + } + + if (settingsCache->getBuddyConnectNotificationsEnabled()) { + QApplication::alert(this); + this->actShowPopup(tr("Your buddy %1 has signed on!").arg(userName)); + } + } + + TabMessage *tab = messageTabs.value(userName); if (tab) - tab->processUserJoined(userInfo); + tab->processUserJoined(userInfoJoined); } void TabSupervisor::updateCurrent(int index) diff --git a/cockatrice/src/tab_supervisor.h b/cockatrice/src/tab_supervisor.h index 44bee8e2..b1b01110 100644 --- a/cockatrice/src/tab_supervisor.h +++ b/cockatrice/src/tab_supervisor.h @@ -115,11 +115,13 @@ public: bool isUserBuddy(const QString &userName) const; bool isUserIgnored(const QString &userName) const; const ServerInfo_User *getOnlineUser(const QString &userName) const; + void actShowPopup(const QString &message); signals: void setMenu(const QList &newMenuList = QList()); void localGameEnded(); void adminLockChanged(bool lock); void showWindowIfHidden(); + public slots: TabDeckEditor *addDeckEditorTab(const DeckLoader *deckToOpen); void openReplay(GameReplay *replay);