diff --git a/chatterino.pro b/chatterino.pro index b9798f6ab..ed8682ba0 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -52,6 +52,7 @@ include(dependencies/libcommuni.pri) include(dependencies/websocketpp.pri) include(dependencies/openssl.pri) include(dependencies/boost.pri) +include(dependencies/wintoast.pri) # Optional feature: QtWebEngine #exists ($(QTDIR)/include/QtWebEngine/QtWebEngine) { @@ -256,7 +257,8 @@ SOURCES += \ src/util/FunctionEventFilter.cpp \ src/controllers/notifications/notificationcontroller.cpp \ src/widgets/settingspages/NotificationPage.cpp \ - src/controllers/notifications/NotificationModel.cpp + src/controllers/notifications/NotificationModel.cpp \ + src/singletons/Toasts.cpp HEADERS += \ src/Application.hpp \ @@ -460,7 +462,8 @@ HEADERS += \ src/util/FunctionEventFilter.hpp \ src/widgets/settingspages/NotificationPage.hpp \ src/controllers/notifications/NotificationModel.hpp \ - src/controllers/notifications/NotificationPhrase.hpp + src/controllers/notifications/NotificationPhrase.hpp \ + src/singletons/Toasts.hpp RESOURCES += \ resources/resources.qrc \ diff --git a/dependencies/wintoast.pri b/dependencies/wintoast.pri new file mode 100644 index 000000000..051d66487 --- /dev/null +++ b/dependencies/wintoast.pri @@ -0,0 +1,3 @@ +INCLUDEPATH += $$PWD/../lib/wintoast/src/ +SOURCES += \ + $$PWD/../lib/wintoast/src/wintoastlib.cpp diff --git a/src/Application.cpp b/src/Application.cpp index f7ed93102..b90a8d445 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -19,6 +19,7 @@ #include "singletons/Resources.hpp" #include "singletons/Settings.hpp" #include "singletons/Theme.hpp" +#include "singletons/Toasts.hpp" #include "singletons/WindowManager.hpp" #include "util/IsBigEndian.hpp" #include "util/PostToThread.hpp" @@ -54,6 +55,7 @@ Application::Application(Settings &_settings, Paths &_paths) , moderationActions(&this->emplace()) , twitch2(&this->emplace()) , logging(&this->emplace()) + , toasts(&this->emplace()) { this->instance = this; diff --git a/src/Application.hpp b/src/Application.hpp index 64045980a..b1dbe2406 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -28,6 +28,7 @@ class Emotes; class Settings; class Fonts; class Resources; +class Toasts; class Application { @@ -56,6 +57,7 @@ public: Fonts *const fonts{}; Emotes *const emotes{}; WindowManager *const windows{}; + Toasts *const toasts{}; AccountController *const accounts{}; CommandController *const commands{}; diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index e9778a10e..bd6d87de0 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -3,11 +3,14 @@ #include "Application.hpp" #include "controllers/notifications/NotificationModel.hpp" +#include + +#include +#include +#include + namespace chatterino { -NotificationController::NotificationController() -{ -} void NotificationController::initialize(Settings &settings, Paths &paths) { this->initialized_ = true; @@ -40,20 +43,75 @@ bool NotificationController::isChannelNotified(const QString &channelName) } } return false; - /* - const auto &vector = notificationSetting_.getValue(); - return std::find(vector.begin(), vector.end(), channelName) != vector.end(); - */ } +class CustomHandler : public WinToastLib::IWinToastHandler +{ +public: + void toastActivated() const + { + std::wcout << L"The user clicked in this toast" << std::endl; + } + + void toastActivated(int actionIndex) const + { + std::wcout << L"The user clicked on button #" << actionIndex + << L" in this toast" << std::endl; + QDesktopServices::openUrl( + QUrl("http://www.google.com", QUrl::TolerantMode)); + } + + void toastFailed() const + { + std::wcout << L"Error showing current toast" << std::endl; + } + void toastDismissed(WinToastDismissalReason state) const + { + switch (state) { + case UserCanceled: + std::wcout << L"The user dismissed this toast" << std::endl; + break; + case ApplicationHidden: + std::wcout << L"The application hid the toast using " + L"ToastNotifier.hide()" + << std::endl; + break; + case TimedOut: + std::wcout << L"The toast has timed out" << std::endl; + break; + default: + std::wcout << L"Toast not activated" << std::endl; + break; + } + } +}; + void NotificationController::addChannelNotification(const QString &channelName) { notificationVector.appendItem(channelName); - /* - auto vector = notificationSetting_.getValue(); - vector.push_back(channelName); - notificationSetting_.setValue(vector); - */ + + if (WinToastLib::WinToast::isCompatible()) { + QDir dir; + qDebug() << "NaM" << dir.absolutePath(); + ; + + WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate( + WinToastLib::WinToastTemplate::ImageAndText02); + templ.setTextField(L"Your favorite streamer has gone live!", + WinToastLib::WinToastTemplate::FirstLine); + templ.setTextField(L"NaM!", WinToastLib::WinToastTemplate::SecondLine); + // templ.setExpiration(10); + // templ.setImagePath(); + // templ.setAudioOption(WinToastLib::WinToastTemplate::Silent); + // templ.setAudioPath(L"C:/ping2.wav"); + WinToastLib::WinToast::instance()->setAppName(L"Chatterino2"); + WinToastLib::WinToast::instance()->setAppUserModelId( + WinToastLib::WinToast::configureAUMI( + L"mohabouje", L"wintoast", L"wintoastexample", L"20161006")); + WinToastLib::WinToast::instance()->initialize(); + WinToastLib::WinToast::instance()->showToast(templ, + new CustomHandler()); + } } void NotificationController::removeChannelNotification( @@ -66,14 +124,6 @@ void NotificationController::removeChannelNotification( i--; } } - - // notificationVector.removeItem(std::find( - // notificationVector.begin(), notificationVector.end(), channelName)); - /* - auto vector = notificationSetting_.getValue(); - vector.erase(std::find(vector.begin(), vector.end(), channelName)); - notificationSetting_.setValue(vector); - */ } NotificationModel *NotificationController::createModel(QObject *parent) diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index 593897772..fb5c71cfc 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -13,8 +13,6 @@ class NotificationModel; class NotificationController final : public Singleton { public: - NotificationController(); - virtual void initialize(Settings &settings, Paths &paths) override; bool isChannelNotified(const QString &channelName); diff --git a/src/controllers/notifications/NotificationModel.cpp b/src/controllers/notifications/NotificationModel.cpp index cd103d1d3..5de8bc903 100644 --- a/src/controllers/notifications/NotificationModel.cpp +++ b/src/controllers/notifications/NotificationModel.cpp @@ -18,6 +18,7 @@ QString NotificationModel::getItemFromRow(std::vector &row, return QString(row[0]->data(Qt::DisplayRole).toString()); } +// turn a model void NotificationModel::getRowFromItem(const QString &item, std::vector &row) { diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index bc084d73f..fa5746bf7 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -153,6 +153,8 @@ private: QTimer liveStatusTimer_; QTimer chattersListTimer_; + std::vector liveChannels; + friend class TwitchServer; }; diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp new file mode 100644 index 000000000..ed39b7791 --- /dev/null +++ b/src/singletons/Toasts.cpp @@ -0,0 +1,56 @@ +#include "Toasts.hpp" + +#include "Application.hpp" +#include "controllers/notifications/NotificationController.hpp" +#include "providers/twitch/TwitchChannel.hpp" +#include "providers/twitch/TwitchServer.hpp" + +namespace chatterino { + +Toasts::Toasts() +{ +} + +void Toasts::initialize(Settings &settings, Paths &paths) +{ + getApp()->twitch2->forEachChannel([](ChannelPtr chn) { + auto twchn = dynamic_cast(chn.get()); + twchn->liveStatusChanged.connect([twchn]() { + const auto streamStatus = twchn->accessStreamStatus(); + if (streamStatus->live) { + // to Live + getApp()->toasts->updateLiveChannels(twchn->getName()); + } else { + // to Offline + } + }); + }); +} + +void Toasts::updateLiveChannels(const QString &channelName) +{ + if (wasChannelLive(channelName)) { + return; + } else { + std::lock_guard lock(mutex_); + liveChannels.push_back(channelName); + } +} + +bool Toasts::wasChannelLive(const QString &channelName) +{ + std::lock_guard lock(mutex_); + for (const auto &str : liveChannels) { + if (str == channelName) { + return true; + } + } + return false; +} +void Toasts::sendChannelNotification(const QString &channelName) +{ +} + +void Toasts:: + +} // namespace chatterino diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp new file mode 100644 index 000000000..75eeae90a --- /dev/null +++ b/src/singletons/Toasts.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "Application.hpp" +#include "common/Singleton.hpp" + +#include + +namespace chatterino { + +class Toasts final : public Singleton +{ +public: + Toasts(); + virtual void initialize(Settings &settings, Paths &paths) override final; + void updateLiveChannels(const QString &channelName); + void removeFromLiveChannels(const QString &channelName); + +private: + bool wasChannelLive(const QString &channelName); + void sendChannelNotification(const QString &channelName); + std::vector liveChannels; + std::mutex mutex_; +}; +} // namespace chatterino