From b68c7ded5f2e48d19dfd9d5f9164dbe94e3b7259 Mon Sep 17 00:00:00 2001 From: apa420 Date: Thu, 9 Aug 2018 15:41:03 +0200 Subject: [PATCH 01/29] WIP notification settings, doesn't actually work --- chatterino.pro | 18 ++++- src/Application.cpp | 2 + src/Application.hpp | 2 + .../notifications/NotificationController.cpp | 62 +++++++++++++++++ .../notifications/NotificationController.hpp | 37 +++++++++++ src/providers/twitch/TwitchChannel.cpp | 3 + src/singletons/Settings.hpp | 6 ++ src/widgets/dialogs/SettingsDialog.cpp | 2 + .../settingspages/NotificationPage.cpp | 66 +++++++++++++++++++ .../settingspages/NotificationPage.hpp | 20 ++++++ src/widgets/splits/SplitHeader.cpp | 15 +++++ 11 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 src/controllers/notifications/NotificationController.cpp create mode 100644 src/controllers/notifications/NotificationController.hpp create mode 100644 src/widgets/settingspages/NotificationPage.cpp create mode 100644 src/widgets/settingspages/NotificationPage.hpp diff --git a/chatterino.pro b/chatterino.pro index 1c2145ea0..b9798f6ab 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -123,6 +123,7 @@ SOURCES += \ src/controllers/highlights/UserHighlightModel.cpp \ src/controllers/ignores/IgnoreController.cpp \ src/controllers/ignores/IgnoreModel.cpp \ + src/controllers/notifications/NotificationController.cpp \ src/controllers/taggedusers/TaggedUser.cpp \ src/controllers/taggedusers/TaggedUsersController.cpp \ src/controllers/taggedusers/TaggedUsersModel.cpp \ @@ -206,6 +207,7 @@ SOURCES += \ src/widgets/settingspages/KeyboardSettingsPage.cpp \ src/widgets/settingspages/LogsPage.cpp \ src/widgets/settingspages/ModerationPage.cpp \ + src/widgets/settingspages/NotificationPage.cpp \ src/widgets/settingspages/SettingsPage.cpp \ src/widgets/settingspages/SpecialChannelsPage.cpp \ src/widgets/splits/Split.cpp \ @@ -228,6 +230,7 @@ SOURCES += \ src/singletons/Updates.cpp \ src/singletons/Theme.cpp \ src/controllers/moderationactions/ModerationActionModel.cpp \ + src/widgets/settingspages/NotificationPage.cpp \ src/widgets/settingspages/LookPage.cpp \ src/widgets/settingspages/FeelPage.cpp \ src/util/InitUpdateButton.cpp \ @@ -250,7 +253,10 @@ SOURCES += \ src/RunGui.cpp \ src/BrowserExtension.cpp \ src/util/FormatTime.cpp \ - src/util/FunctionEventFilter.cpp + src/util/FunctionEventFilter.cpp \ + src/controllers/notifications/notificationcontroller.cpp \ + src/widgets/settingspages/NotificationPage.cpp \ + src/controllers/notifications/NotificationModel.cpp HEADERS += \ src/Application.hpp \ @@ -290,6 +296,7 @@ HEADERS += \ src/controllers/ignores/IgnoreController.hpp \ src/controllers/ignores/IgnoreModel.hpp \ src/controllers/ignores/IgnorePhrase.hpp \ + src/controllers/notifications/NotificationController.hpp \ src/controllers/taggedusers/TaggedUser.hpp \ src/controllers/taggedusers/TaggedUsersController.hpp \ src/controllers/taggedusers/TaggedUsersModel.hpp \ @@ -395,6 +402,7 @@ HEADERS += \ src/widgets/settingspages/KeyboardSettingsPage.hpp \ src/widgets/settingspages/LogsPage.hpp \ src/widgets/settingspages/ModerationPage.hpp \ + src/widgets/settingspages/NotificationPage.hpp \ src/widgets/settingspages/SettingsPage.hpp \ src/widgets/settingspages/SpecialChannelsPage.hpp \ src/widgets/splits/Split.hpp \ @@ -423,6 +431,7 @@ HEADERS += \ src/widgets/dialogs/LogsPopup.hpp \ src/common/Singleton.hpp \ src/controllers/moderationactions/ModerationActionModel.hpp \ + src/widgets/settingspages/NotificationPage.hpp \ src/widgets/settingspages/LookPage.hpp \ src/widgets/settingspages/FeelPage.hpp \ src/util/InitUpdateButton.hpp \ @@ -448,9 +457,12 @@ HEADERS += \ src/RunGui.hpp \ src/BrowserExtension.hpp \ src/util/FormatTime.hpp \ - src/util/FunctionEventFilter.hpp + src/util/FunctionEventFilter.hpp \ + src/widgets/settingspages/NotificationPage.hpp \ + src/controllers/notifications/NotificationModel.hpp \ + src/controllers/notifications/NotificationPhrase.hpp -RESOURCES += \ +RESOURCES += \ resources/resources.qrc \ resources/resources_autogenerated.qrc diff --git a/src/Application.cpp b/src/Application.cpp index c912597c8..f7ed93102 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -5,6 +5,7 @@ #include "controllers/highlights/HighlightController.hpp" #include "controllers/ignores/IgnoreController.hpp" #include "controllers/moderationactions/ModerationActions.hpp" +#include "controllers/notifications/NotificationController.hpp" #include "controllers/taggedusers/TaggedUsersController.hpp" #include "messages/MessageBuilder.hpp" #include "providers/bttv/BttvEmotes.hpp" @@ -47,6 +48,7 @@ Application::Application(Settings &_settings, Paths &_paths) , accounts(&this->emplace()) , commands(&this->emplace()) , highlights(&this->emplace()) + , notifications(&this->emplace()) , ignores(&this->emplace()) , taggedUsers(&this->emplace()) , moderationActions(&this->emplace()) diff --git a/src/Application.hpp b/src/Application.hpp index 2a62503bf..64045980a 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -17,6 +17,7 @@ class IgnoreController; class TaggedUsersController; class AccountController; class ModerationActions; +class NotificationController; class Theme; class WindowManager; @@ -59,6 +60,7 @@ public: AccountController *const accounts{}; CommandController *const commands{}; HighlightController *const highlights{}; + NotificationController *const notifications{}; IgnoreController *const ignores{}; TaggedUsersController *const taggedUsers{}; ModerationActions *const moderationActions{}; diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp new file mode 100644 index 000000000..984363f0f --- /dev/null +++ b/src/controllers/notifications/NotificationController.cpp @@ -0,0 +1,62 @@ +#include "NotificationController.hpp" + +#include "Application.hpp" +#include "controllers/notifications/NotificationModel.hpp" + +namespace chatterino { + +NotificationController::NotificationController() +{ +} +void NotificationController::initialize(Settings &settings, Paths &paths) +{ + this->initialized_ = true; + for (const QString &channelName : this->notificationSetting_.getValue()) { + this->notificationVector.appendItem(channelName); + } + + this->notificationVector.delayedItemsChanged.connect([this] { // + this->notificationSetting_.setValue( + this->notificationVector.getVector()); + }); +} + +void NotificationController::updateChannelNotification( + const QString &channelName) +{ + if (isChannelNotified(channelName)) { + removeChannelNotification(channelName); + } else { + addChannelNotification(channelName); + } +} + +bool NotificationController::isChannelNotified(const QString &channelName) +{ + const auto &vector = notificationSetting_.getValue(); + return std::find(vector.begin(), vector.end(), channelName) != vector.end(); +} + +void NotificationController::addChannelNotification(const QString &channelName) +{ + auto vector = notificationSetting_.getValue(); + vector.push_back(channelName); + notificationSetting_.setValue(vector); +} + +void NotificationController::removeChannelNotification( + const QString &channelName) +{ + auto vector = notificationSetting_.getValue(); + vector.erase(std::find(vector.begin(), vector.end(), channelName)); + notificationSetting_.setValue(vector); +} + +NotificationModel *NotificationController::createModel(QObject *parent) +{ + NotificationModel *model = new NotificationModel(parent); + model->init(&this->notificationVector); + return model; +} + +} // namespace chatterino diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp new file mode 100644 index 000000000..593897772 --- /dev/null +++ b/src/controllers/notifications/NotificationController.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "common/SignalVector.hpp" +#include "singletons/Settings.hpp" + +namespace chatterino { + +class Settings; +class Paths; + +class NotificationModel; + +class NotificationController final : public Singleton +{ +public: + NotificationController(); + + virtual void initialize(Settings &settings, Paths &paths) override; + + bool isChannelNotified(const QString &channelName); + + void updateChannelNotification(const QString &channelName); + void addChannelNotification(const QString &channelName); + void removeChannelNotification(const QString &channelName); + + UnsortedSignalVector notificationVector; + + NotificationModel *createModel(QObject *parent); + +private: + bool initialized_ = false; + + ChatterinoSetting> notificationSetting_ = { + "/notifications/channels"}; +}; + +} // namespace chatterino diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 7753f2668..8ec998774 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -391,6 +391,9 @@ Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document) { auto status = this->streamStatus_.access(); + if (!status->live /*&&*/) { + // notifcation send + } status->live = true; status->viewerCount = stream["viewers"].GetUint(); status->game = stream["game"].GetString(); diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 3db58f9c2..501c43287 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -139,6 +139,12 @@ public: BoolSetting inlineWhispers = {"/whispers/enableInlineWhispers", true}; + /// Notifications + BoolSetting notificationFlashTaskbar = {"/notifications/enableFlashTaskbar", + false}; + BoolSetting notificationPlaySound = {"/notifications/enablePlaySound", + false}; + /// External tools // Streamlink BoolSetting streamlinkUseCustomPath = {"/external/streamlink/useCustomPath", diff --git a/src/widgets/dialogs/SettingsDialog.cpp b/src/widgets/dialogs/SettingsDialog.cpp index 8f0746ccb..cf9c77bb8 100644 --- a/src/widgets/dialogs/SettingsDialog.cpp +++ b/src/widgets/dialogs/SettingsDialog.cpp @@ -16,6 +16,7 @@ #include "widgets/settingspages/LogsPage.hpp" #include "widgets/settingspages/LookPage.hpp" #include "widgets/settingspages/ModerationPage.hpp" +#include "widgets/settingspages/NotificationPage.hpp" #include "widgets/settingspages/SpecialChannelsPage.hpp" #include @@ -100,6 +101,7 @@ void SettingsDialog::addTabs() this->addTab(new KeyboardSettingsPage); // this->addTab(new LogsPage); this->addTab(new ModerationPage); + this->addTab(new NotificationPage); // this->addTab(new SpecialChannelsPage); this->addTab(new BrowserExtensionPage); this->addTab(new ExternalToolsPage); diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp new file mode 100644 index 000000000..5da0a8296 --- /dev/null +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -0,0 +1,66 @@ +#include "NotificationPage.hpp" + +#include "Application.hpp" +#include "singletons/Settings.hpp" +#include "src/controllers/notifications/NotificationController.hpp" +#include "util/LayoutCreator.hpp" +#include "widgets/helper/EditableModelView.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace chatterino { + +NotificationPage::NotificationPage() + : SettingsPage("Notifications", "") +{ + LayoutCreator layoutCreator(this); + + auto layout = layoutCreator.emplace().withoutMargin(); + { + auto tabs = layout.emplace(); + { + auto settings = tabs.appendTab(new QVBoxLayout, "Options"); + { + settings.emplace( + "Enable for channel next to channel name"); + settings.append(this->createCheckBox( + "Flash taskbar", + getApp()->settings->notificationFlashTaskbar)); + settings.append(this->createCheckBox( + "Playsound", getApp()->settings->notificationPlaySound)); + + settings->addStretch(1); + } + auto channels = tabs.appendTab(new QVBoxLayout, "Channels"); + { + EditableModelView *view = + channels + .emplace( + getApp()->notifications->createModel(nullptr)) + .getElement(); + view->setTitles({"Channels"}); + + view->getTableView()->horizontalHeader()->setSectionResizeMode( + QHeaderView::Fixed); + view->getTableView()->horizontalHeader()->setSectionResizeMode( + 0, QHeaderView::Stretch); + + QTimer::singleShot(1, [view] { + view->getTableView()->resizeColumnsToContents(); + view->getTableView()->setColumnWidth(0, 200); + }); + + view->addButtonPressed.connect([] { + getApp()->notifications->addChannelNotification("channel"); + }); + } + } + } +} +} // namespace chatterino diff --git a/src/widgets/settingspages/NotificationPage.hpp b/src/widgets/settingspages/NotificationPage.hpp new file mode 100644 index 000000000..d0e8c12a2 --- /dev/null +++ b/src/widgets/settingspages/NotificationPage.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "widgets/settingspages/SettingsPage.hpp" + +class QPushButton; +class QListWidget; + +class QVBoxLayout; + +namespace chatterino { + +class NotificationPage : public SettingsPage +{ +public: + NotificationPage(); + +private: +}; + +} // namespace chatterino diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index c27014080..4c12be61a 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -2,6 +2,7 @@ #include "Application.hpp" #include "controllers/accounts/AccountController.hpp" +#include "controllers/notifications/NotificationController.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchServer.hpp" #include "singletons/Resources.hpp" @@ -154,6 +155,20 @@ std::unique_ptr SplitHeader::createMainMenu() &Split::openInPopupPlayer); #endif menu->addAction("Open streamlink", this->split_, &Split::openInStreamlink); + + auto action = new QAction(this); + action->setText("Notify when live"); + action->setCheckable(true); + QObject::connect(menu.get(), &QMenu::aboutToShow, this, [action, this]() { + action->setChecked(getApp()->notifications->isChannelNotified( + this->split_->getChannel()->getName())); + }); + action->connect(action, &QAction::triggered, this, [this]() { + getApp()->notifications->updateChannelNotification( + this->split_->getChannel()->getName()); + }); + menu->addAction(action); + menu->addSeparator(); menu->addAction("Reload channel emotes", this, SLOT(menuReloadChannelEmotes())); From 5c6d2f36b5d52aa38517509f06e2c3d7f41503e8 Mon Sep 17 00:00:00 2001 From: apa420 Date: Thu, 9 Aug 2018 15:41:32 +0200 Subject: [PATCH 02/29] WIP notification settings, doesn't actually work --- .../notifications/NotificationModel.cpp | 26 +++++++++++++++++ .../notifications/NotificationModel.hpp | 28 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/controllers/notifications/NotificationModel.cpp create mode 100644 src/controllers/notifications/NotificationModel.hpp diff --git a/src/controllers/notifications/NotificationModel.cpp b/src/controllers/notifications/NotificationModel.cpp new file mode 100644 index 000000000..8049f62b1 --- /dev/null +++ b/src/controllers/notifications/NotificationModel.cpp @@ -0,0 +1,26 @@ +#include "NotificationModel.hpp" + +#include "Application.hpp" +#include "singletons/Settings.hpp" +#include "util/StandardItemHelper.hpp" + +namespace chatterino { + +NotificationModel::NotificationModel(QObject *parent) + : SignalVectorModel(1, parent) +{ +} + +// turn a vector item into a model row +QString NotificationModel::getItemFromRow(std::vector &row, + const QString &original) +{ + return QString(row[0]->data().toString()); +} + +void NotificationModel::getRowFromItem(const QString &item, + std::vector &row) +{ + setStringItem(row[0], item); +} +} // namespace chatterino diff --git a/src/controllers/notifications/NotificationModel.hpp b/src/controllers/notifications/NotificationModel.hpp new file mode 100644 index 000000000..83d14ba08 --- /dev/null +++ b/src/controllers/notifications/NotificationModel.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "common/SignalVectorModel.hpp" +#include "controllers/notifications/NotificationController.hpp" + +namespace chatterino { + +class NotificationController; + +class NotificationModel : public SignalVectorModel +{ + explicit NotificationModel(QObject *parent); + +protected: + // turn a vector item into a model row + virtual QString getItemFromRow(std::vector &row, + const QString &original) override; + + // turns a row in the model into a vector item + virtual void getRowFromItem(const QString &item, + std::vector &row) override; + + friend class NotificationController; +}; + +} // namespace chatterino From 5437a6dd4d963fd0d890bd31d3be5d578ab1c329 Mon Sep 17 00:00:00 2001 From: apa420 Date: Fri, 10 Aug 2018 00:04:50 +0200 Subject: [PATCH 03/29] update which actually let's you compile, but doesn't properly save an item after renaming it --- .../notifications/NotificationController.cpp | 26 ++++++++++++++++++- .../notifications/NotificationModel.cpp | 1 + .../settingspages/NotificationPage.cpp | 6 +++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 984363f0f..e9778a10e 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -1,4 +1,4 @@ -#include "NotificationController.hpp" +#include "controllers/notifications/NotificationController.hpp" #include "Application.hpp" #include "controllers/notifications/NotificationModel.hpp" @@ -33,23 +33,47 @@ void NotificationController::updateChannelNotification( bool NotificationController::isChannelNotified(const QString &channelName) { + for (std::vector::size_type i = 0; + i != notificationVector.getVector().size(); i++) { + if (notificationVector.getVector()[i] == channelName) { + return true; + } + } + return false; + /* const auto &vector = notificationSetting_.getValue(); return std::find(vector.begin(), vector.end(), channelName) != vector.end(); + */ } void NotificationController::addChannelNotification(const QString &channelName) { + notificationVector.appendItem(channelName); + /* auto vector = notificationSetting_.getValue(); vector.push_back(channelName); notificationSetting_.setValue(vector); + */ } void NotificationController::removeChannelNotification( const QString &channelName) { + for (std::vector::size_type i = 0; + i != notificationVector.getVector().size(); i++) { + if (notificationVector.getVector()[i] == channelName) { + notificationVector.removeItem(i); + 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/NotificationModel.cpp b/src/controllers/notifications/NotificationModel.cpp index 8049f62b1..e8ecbc064 100644 --- a/src/controllers/notifications/NotificationModel.cpp +++ b/src/controllers/notifications/NotificationModel.cpp @@ -23,4 +23,5 @@ void NotificationModel::getRowFromItem(const QString &item, { setStringItem(row[0], item); } + } // namespace chatterino diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index 5da0a8296..77ba20d01 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -1,8 +1,9 @@ #include "NotificationPage.hpp" #include "Application.hpp" +#include "controllers/notifications/NotificationController.hpp" +#include "controllers/notifications/NotificationModel.hpp" #include "singletons/Settings.hpp" -#include "src/controllers/notifications/NotificationController.hpp" #include "util/LayoutCreator.hpp" #include "widgets/helper/EditableModelView.hpp" @@ -57,7 +58,8 @@ NotificationPage::NotificationPage() }); view->addButtonPressed.connect([] { - getApp()->notifications->addChannelNotification("channel"); + getApp()->notifications->notificationVector.appendItem( + "channel"); }); } } From 125af43d901c37480d3a245ae464af02c1b55589 Mon Sep 17 00:00:00 2001 From: apa420 Date: Fri, 10 Aug 2018 00:15:42 +0200 Subject: [PATCH 04/29] Fixed issue, everything except the main feature work now --- src/controllers/notifications/NotificationModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/notifications/NotificationModel.cpp b/src/controllers/notifications/NotificationModel.cpp index e8ecbc064..cd103d1d3 100644 --- a/src/controllers/notifications/NotificationModel.cpp +++ b/src/controllers/notifications/NotificationModel.cpp @@ -15,7 +15,7 @@ NotificationModel::NotificationModel(QObject *parent) QString NotificationModel::getItemFromRow(std::vector &row, const QString &original) { - return QString(row[0]->data().toString()); + return QString(row[0]->data(Qt::DisplayRole).toString()); } void NotificationModel::getRowFromItem(const QString &item, From 77411f70127a39744ef8b76538a77a243938a02d Mon Sep 17 00:00:00 2001 From: apa420 Date: Sat, 11 Aug 2018 12:47:03 +0200 Subject: [PATCH 05/29] WIP commit --- chatterino.pro | 7 +- dependencies/wintoast.pri | 3 + src/Application.cpp | 2 + src/Application.hpp | 2 + .../notifications/NotificationController.cpp | 90 ++++++++++++++----- .../notifications/NotificationController.hpp | 2 - .../notifications/NotificationModel.cpp | 1 + src/providers/twitch/TwitchChannel.hpp | 2 + src/singletons/Toasts.cpp | 56 ++++++++++++ src/singletons/Toasts.hpp | 24 +++++ 10 files changed, 165 insertions(+), 24 deletions(-) create mode 100644 dependencies/wintoast.pri create mode 100644 src/singletons/Toasts.cpp create mode 100644 src/singletons/Toasts.hpp 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 From 2de99ca9f5491e1e5964efa183dd0ce37cdaec46 Mon Sep 17 00:00:00 2001 From: apa420 Date: Sat, 11 Aug 2018 16:11:51 +0200 Subject: [PATCH 06/29] update, should now be working Toasts for splitheader channels --- .../notifications/NotificationController.cpp | 13 +- src/singletons/Toasts.cpp | 120 ++++++++++++++++-- src/singletons/Toasts.hpp | 6 +- 3 files changed, 126 insertions(+), 13 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index bd6d87de0..3dcd13901 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -36,6 +36,12 @@ void NotificationController::updateChannelNotification( bool NotificationController::isChannelNotified(const QString &channelName) { + for (std::vector::size_type i = 0; + i != notificationVector.getVector().size(); i++) { + qDebug() << notificationVector.getVector()[i] + << " vector to the left channel to the right " << channelName + << " vectorsize:" << notificationVector.getVector().size(); + } for (std::vector::size_type i = 0; i != notificationVector.getVector().size(); i++) { if (notificationVector.getVector()[i] == channelName) { @@ -44,7 +50,7 @@ bool NotificationController::isChannelNotified(const QString &channelName) } return false; } - +/* class CustomHandler : public WinToastLib::IWinToastHandler { public: @@ -85,7 +91,7 @@ public: } } }; - +*/ void NotificationController::addChannelNotification(const QString &channelName) { notificationVector.appendItem(channelName); @@ -93,7 +99,7 @@ void NotificationController::addChannelNotification(const QString &channelName) if (WinToastLib::WinToast::isCompatible()) { QDir dir; qDebug() << "NaM" << dir.absolutePath(); - ; + /* WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate( WinToastLib::WinToastTemplate::ImageAndText02); @@ -111,6 +117,7 @@ void NotificationController::addChannelNotification(const QString &channelName) WinToastLib::WinToast::instance()->initialize(); WinToastLib::WinToast::instance()->showToast(templ, new CustomHandler()); + */ } } diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index ed39b7791..e49bdccf6 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -5,6 +5,13 @@ #include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchServer.hpp" +#include + +#include +#include + +#include + namespace chatterino { Toasts::Toasts() @@ -13,15 +20,21 @@ Toasts::Toasts() void Toasts::initialize(Settings &settings, Paths &paths) { - getApp()->twitch2->forEachChannel([](ChannelPtr chn) { + getApp()->twitch2->forEachChannel([this](ChannelPtr chn) { auto twchn = dynamic_cast(chn.get()); - twchn->liveStatusChanged.connect([twchn]() { + twchn->liveStatusChanged.connect([twchn, this]() { const auto streamStatus = twchn->accessStreamStatus(); if (streamStatus->live) { - // to Live - getApp()->toasts->updateLiveChannels(twchn->getName()); + // is live + if (getApp()->notifications->isChannelNotified( + twchn->getName()) && + !wasChannelLive(twchn->getName())) { + sendChannelNotification(twchn->getName()); + } + updateLiveChannels(twchn->getName()); } else { - // to Offline + // is Offline + removeFromLiveChannels(twchn->getName()); } }); }); @@ -29,14 +42,21 @@ void Toasts::initialize(Settings &settings, Paths &paths) void Toasts::updateLiveChannels(const QString &channelName) { - if (wasChannelLive(channelName)) { - return; - } else { + if (!wasChannelLive(channelName)) { std::lock_guard lock(mutex_); liveChannels.push_back(channelName); } } +void Toasts::removeFromLiveChannels(const QString &channelName) +{ + if (wasChannelLive(channelName)) { + std::lock_guard lock(mutex_); + liveChannels.erase( + std::find(liveChannels.begin(), liveChannels.end(), channelName)); + } +} + bool Toasts::wasChannelLive(const QString &channelName) { std::lock_guard lock(mutex_); @@ -47,10 +67,92 @@ bool Toasts::wasChannelLive(const QString &channelName) } return false; } + void Toasts::sendChannelNotification(const QString &channelName) { +#ifdef Q_OS_WIN + if (WinToastLib::WinToast::isCompatible()) { + sendWindowsNotification(channelName); + } +#endif + // OSX + + // LINUX } -void Toasts:: +#ifdef Q_OS_WIN + +class CustomHandler : public WinToastLib::IWinToastHandler +{ +public: + void toastActivated() const + { + std::wcout << L"The user clicked in this toast" << std::endl; + QString link = "http://www.google.com"; + QDesktopServices::openUrl(QUrl(link)); + } + + void toastActivated(int actionIndex) const + { + // std::wcout << L"The user clicked on button #" << actionIndex + // << L" in this toast" << std::endl; + } + + 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 Toasts::sendWindowsNotification(const QString &channelName) +{ + WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate( + WinToastLib::WinToastTemplate::ImageAndText02); + QString str = channelName + " has just gone live!"; + std::string utf8_text = str.toUtf8().constData(); + std::wstring widestr = std::wstring(utf8_text.begin(), utf8_text.end()); + + templ.setTextField(widestr, WinToastLib::WinToastTemplate::FirstLine); + templ.setTextField(L"Click here to open in browser", + WinToastLib::WinToastTemplate::SecondLine); + WinToastLib::WinToast::instance()->setAppName(L"Chatterino2"); + int mbstowcs(wchar_t * aumi_version, const char *CHATTERINO_VERSION, + size_t size); + std::string(CHATTERINO_VERSION); + std::wstring aumi_version = + std::wstring(CHATTERINO_VERSION.begin(), CHATTERINO_VERSION.end()); + // int mbstowcs(wchar_t *out, const char *in, size_t size); + /* +std::wstring aumi_version = +std::wstring(std::string(CHATTERINO_VERSION).begin(), + std::string(CHATTERINO_VERSION).end());*/ + WinToastLib::WinToast::instance()->setAppUserModelId( + WinToastLib::WinToast::configureAUMI(L"", L"Chatterino 2", L"", + aumi_version)); + WinToastLib::WinToast::instance()->initialize(); + WinToastLib::WinToast::instance()->showToast(templ, new CustomHandler()); +} +#endif } // namespace chatterino diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp index 75eeae90a..c47728dc0 100644 --- a/src/singletons/Toasts.hpp +++ b/src/singletons/Toasts.hpp @@ -12,12 +12,16 @@ class Toasts final : public Singleton public: Toasts(); virtual void initialize(Settings &settings, Paths &paths) override final; + +private: void updateLiveChannels(const QString &channelName); void removeFromLiveChannels(const QString &channelName); -private: bool wasChannelLive(const QString &channelName); + + void shouldChannelBeNotified(const QString &channelName); void sendChannelNotification(const QString &channelName); + void sendWindowsNotification(const QString &channelName); std::vector liveChannels; std::mutex mutex_; }; From 54166ec130b8242b62f0a90113c88a4142df253a Mon Sep 17 00:00:00 2001 From: apa420 Date: Sun, 12 Aug 2018 15:29:40 +0200 Subject: [PATCH 07/29] temp stuff --- .../notifications/NotificationController.cpp | 87 +++++++++++++------ .../notifications/NotificationController.hpp | 24 +++-- src/providers/twitch/TwitchChannel.cpp | 58 ++++++++++++- src/providers/twitch/TwitchChannel.hpp | 2 + src/singletons/Toasts.cpp | 12 +-- src/singletons/Toasts.hpp | 9 +- .../settingspages/NotificationPage.cpp | 36 ++++++-- src/widgets/splits/SplitHeader.cpp | 7 +- 8 files changed, 185 insertions(+), 50 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 3dcd13901..e6f6fac1d 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -14,38 +14,68 @@ namespace chatterino { void NotificationController::initialize(Settings &settings, Paths &paths) { this->initialized_ = true; - for (const QString &channelName : this->notificationSetting_.getValue()) { - this->notificationVector.appendItem(channelName); + for (const QString &channelName : this->twitchSetting_.getValue()) { + this->twitchVector.appendItem(channelName); } - this->notificationVector.delayedItemsChanged.connect([this] { // - this->notificationSetting_.setValue( - this->notificationVector.getVector()); + this->twitchVector.delayedItemsChanged.connect([this] { // + this->twitchSetting_.setValue(this->twitchVector.getVector()); + }); + + for (const QString &channelName : this->mixerSetting_.getValue()) { + this->mixerVector.appendItem(channelName); + } + + this->mixerVector.delayedItemsChanged.connect([this] { // + this->mixerSetting_.setValue(this->mixerVector.getVector()); }); } void NotificationController::updateChannelNotification( - const QString &channelName) + const QString &channelName, int &i) { - if (isChannelNotified(channelName)) { - removeChannelNotification(channelName); - } else { - addChannelNotification(channelName); + if (i == 0) { + int j = 0; + if (isChannelNotified(channelName, j)) { + removeChannelNotification(channelName, twitchVector); + } else { + addChannelNotification(channelName, twitchVector); + } + } else if (i == 1) { + int k = 1; + if (isChannelNotified(channelName, k)) { + removeChannelNotification(channelName, mixerVector); + } else { + addChannelNotification(channelName, mixerVector); + } } } -bool NotificationController::isChannelNotified(const QString &channelName) +bool NotificationController::isChannelNotified(const QString &channelName, + int &i) { + /* for (std::vector::size_type i = 0; i != notificationVector.getVector().size(); i++) { qDebug() << notificationVector.getVector()[i] << " vector to the left channel to the right " << channelName << " vectorsize:" << notificationVector.getVector().size(); } - for (std::vector::size_type i = 0; - i != notificationVector.getVector().size(); i++) { - if (notificationVector.getVector()[i] == channelName) { - return true; + */ + qDebug() << channelName << " channel and now i: " << i; + if (i == 0) { + for (std::vector::size_type i = 0; + i != twitchVector.getVector().size(); i++) { + if (twitchVector.getVector()[i] == channelName) { + return true; + } + } + } else if (i == 1) { + for (std::vector::size_type i = 0; + i != mixerVector.getVector().size(); i++) { + if (mixerVector.getVector()[i] == channelName) { + return true; + } } } return false; @@ -92,13 +122,14 @@ public: } }; */ -void NotificationController::addChannelNotification(const QString &channelName) +void NotificationController::addChannelNotification( + const QString &channelName, UnsortedSignalVector &vector) { - notificationVector.appendItem(channelName); + vector.appendItem(channelName); if (WinToastLib::WinToast::isCompatible()) { - QDir dir; - qDebug() << "NaM" << dir.absolutePath(); + // QDir dir; + // qDebug() << "NaM" << dir.absolutePath(); /* WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate( @@ -122,21 +153,25 @@ void NotificationController::addChannelNotification(const QString &channelName) } void NotificationController::removeChannelNotification( - const QString &channelName) + const QString &channelName, UnsortedSignalVector &vector) { - for (std::vector::size_type i = 0; - i != notificationVector.getVector().size(); i++) { - if (notificationVector.getVector()[i] == channelName) { - notificationVector.removeItem(i); + for (std::vector::size_type i = 0; i != vector.getVector().size(); + i++) { + if (vector.getVector()[i] == channelName) { + vector.removeItem(i); i--; } } } -NotificationModel *NotificationController::createModel(QObject *parent) +NotificationModel *NotificationController::createModel(QObject *parent, int &i) { NotificationModel *model = new NotificationModel(parent); - model->init(&this->notificationVector); + if (i == 0) { + model->init(&this->twitchVector); + } else if (i == 1) { + model->init(&this->mixerVector); + } return model; } diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index fb5c71cfc..d2fc87e36 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -15,21 +15,27 @@ class NotificationController final : public Singleton public: virtual void initialize(Settings &settings, Paths &paths) override; - bool isChannelNotified(const QString &channelName); + bool isChannelNotified(const QString &channelName, int &i); - void updateChannelNotification(const QString &channelName); - void addChannelNotification(const QString &channelName); - void removeChannelNotification(const QString &channelName); + void updateChannelNotification(const QString &channelName, int &i); + void addChannelNotification(const QString &channelName, + UnsortedSignalVector &vector); + void removeChannelNotification(const QString &channelName, + UnsortedSignalVector &vector); - UnsortedSignalVector notificationVector; + UnsortedSignalVector getVector(int &i); - NotificationModel *createModel(QObject *parent); + UnsortedSignalVector twitchVector; + UnsortedSignalVector mixerVector; + + NotificationModel *createModel(QObject *parent, int &i); private: bool initialized_ = false; - - ChatterinoSetting> notificationSetting_ = { - "/notifications/channels"}; + ChatterinoSetting> twitchSetting_ = { + "/notifications/twitch"}; + ChatterinoSetting> mixerSetting_ = { + "/notifications/mixer"}; }; } // namespace chatterino diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 8ec998774..ce4324388 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -3,6 +3,7 @@ #include "common/Common.hpp" #include "common/NetworkRequest.hpp" #include "controllers/accounts/AccountController.hpp" +#include "controllers/notifications/NotificationController.hpp" #include "debug/Log.hpp" #include "messages/Message.hpp" #include "providers/bttv/LoadBttvChannelEmote.hpp" @@ -12,6 +13,7 @@ #include "providers/twitch/TwitchParseCheerEmotes.hpp" #include "singletons/Emotes.hpp" #include "singletons/Settings.hpp" +#include "singletons/Toasts.hpp" #include "util/PostToThread.hpp" #include @@ -303,6 +305,19 @@ const QString &TwitchChannel::getPopoutPlayerUrl() return this->popoutPlayerUrl_; } +bool Toasts::isEnabled(const QString &channelName) +{ + int i = 0; + return getApp()->notifications->isChannelNotified(channelName, i); +} +/* +bool toastIsEnabled() +{ + QString channelName = this->getName(); + return getApp()->notifications->isChannelNotified(channelName); +} +*/ + void TwitchChannel::setLive(bool newLiveStatus) { bool gotNewLiveStatus = false; @@ -319,6 +334,40 @@ void TwitchChannel::setLive(bool newLiveStatus) } } +/* +void TwitchChannel::setLive(bool newLiveStatus) +{ + // auto guard = this->streamStatus_.access(); + + if (toastIsEnabled() && guard->live != newLiveStatus && guard->live != + newLiveStatus) { Toasts::show + } + + // int i = 0; + // getApp()->toasts->sendChannelNotification(this->getName(), i); + qDebug() << "setLive called here and channel: " << this->getName() + << " status: " << newLiveStatus; + + bool gotNewLiveStatus = false; + { + auto guard = this->streamStatus_.access(); + if (guard->live != newLiveStatus) { + gotNewLiveStatus = true; + guard->live = newLiveStatus; + + if (getApp()->toasts->isEnabled(this->getName()) && + guard->live == true) { + int i = 0; + getApp()->toasts->sendChannelNotification(this->getName(), i); + } + } + } + + if (gotNewLiveStatus) { + this->liveStatusChanged.invoke(); + } +} +*/ void TwitchChannel::refreshLiveStatus() { auto roomID = this->getRoomId(); @@ -391,10 +440,17 @@ Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document) { auto status = this->streamStatus_.access(); - if (!status->live /*&&*/) { + /* + if (!status->live == false && + getApp()->toasts->isEnabled(this->getName())) { + int i = 0; + getApp()->toasts->sendChannelNotification(this->getName(), i); // notifcation send } status->live = true; + */ + this->setLive(true); + // status->live = true; status->viewerCount = stream["viewers"].GetUint(); status->game = stream["game"].GetString(); status->title = streamChannel["status"].GetString(); diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index fa5746bf7..000b1bbec 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -118,6 +118,8 @@ private: void loadRecentMessages(); Outcome parseRecentMessages(const QJsonObject &jsonRoot); + bool toastIsEnabled(); + void setLive(bool newLiveStatus); void loadBadges(); diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index e49bdccf6..31f9931ee 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -14,10 +14,12 @@ namespace chatterino { +/* Toasts::Toasts() { } - +*/ +/* void Toasts::initialize(Settings &settings, Paths &paths) { getApp()->twitch2->forEachChannel([this](ChannelPtr chn) { @@ -67,12 +69,12 @@ bool Toasts::wasChannelLive(const QString &channelName) } return false; } - -void Toasts::sendChannelNotification(const QString &channelName) +*/ +void Toasts::sendChannelNotification(const QString &channelName, int &platform) { #ifdef Q_OS_WIN if (WinToastLib::WinToast::isCompatible()) { - sendWindowsNotification(channelName); + sendWindowsNotification(channelName, platform); } #endif // OSX @@ -125,7 +127,7 @@ public: } }; -void Toasts::sendWindowsNotification(const QString &channelName) +void Toasts::sendWindowsNotification(const QString &channelName, int &platform) { WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate( WinToastLib::WinToastTemplate::ImageAndText02); diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp index c47728dc0..0fc7dad29 100644 --- a/src/singletons/Toasts.hpp +++ b/src/singletons/Toasts.hpp @@ -3,17 +3,23 @@ #include "Application.hpp" #include "common/Singleton.hpp" -#include +//#include namespace chatterino { class Toasts final : public Singleton { public: + void sendChannelNotification(const QString &channelName, int &platform); + bool isEnabled(const QString &channelName); + /* Toasts(); virtual void initialize(Settings &settings, Paths &paths) override final; + */ private: + void sendWindowsNotification(const QString &channelName, int &platform); + /* void updateLiveChannels(const QString &channelName); void removeFromLiveChannels(const QString &channelName); @@ -24,5 +30,6 @@ private: void sendWindowsNotification(const QString &channelName); std::vector liveChannels; std::mutex mutex_; + */ }; } // namespace chatterino diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index 77ba20d01..50e52725f 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -38,14 +38,15 @@ NotificationPage::NotificationPage() settings->addStretch(1); } - auto channels = tabs.appendTab(new QVBoxLayout, "Channels"); + auto twitchChannels = tabs.appendTab(new QVBoxLayout, "Twitch"); { + int i = 0; EditableModelView *view = - channels + twitchChannels .emplace( - getApp()->notifications->createModel(nullptr)) + getApp()->notifications->createModel(nullptr, i)) .getElement(); - view->setTitles({"Channels"}); + view->setTitles({"Twitch channels"}); view->getTableView()->horizontalHeader()->setSectionResizeMode( QHeaderView::Fixed); @@ -58,8 +59,31 @@ NotificationPage::NotificationPage() }); view->addButtonPressed.connect([] { - getApp()->notifications->notificationVector.appendItem( - "channel"); + getApp()->notifications->twitchVector.appendItem("channel"); + }); + } + auto mixerChannels = tabs.appendTab(new QVBoxLayout, "Mixer"); + { + int i = 1; + EditableModelView *view = + mixerChannels + .emplace( + getApp()->notifications->createModel(nullptr, i)) + .getElement(); + view->setTitles({"Mixer channels"}); + + view->getTableView()->horizontalHeader()->setSectionResizeMode( + QHeaderView::Fixed); + view->getTableView()->horizontalHeader()->setSectionResizeMode( + 0, QHeaderView::Stretch); + + QTimer::singleShot(1, [view] { + view->getTableView()->resizeColumnsToContents(); + view->getTableView()->setColumnWidth(0, 200); + }); + + view->addButtonPressed.connect([] { + getApp()->notifications->mixerVector.appendItem("channel"); }); } } diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index 4c12be61a..38682ad12 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -159,13 +159,16 @@ std::unique_ptr SplitHeader::createMainMenu() auto action = new QAction(this); action->setText("Notify when live"); action->setCheckable(true); + QObject::connect(menu.get(), &QMenu::aboutToShow, this, [action, this]() { + int i = 0; action->setChecked(getApp()->notifications->isChannelNotified( - this->split_->getChannel()->getName())); + this->split_->getChannel()->getName(), i)); }); action->connect(action, &QAction::triggered, this, [this]() { + int i = 0; getApp()->notifications->updateChannelNotification( - this->split_->getChannel()->getName()); + this->split_->getChannel()->getName(), i); }); menu->addAction(action); From 05d5709bb99635a48d6f5a9dfb982abea00eddaf Mon Sep 17 00:00:00 2001 From: apa420 Date: Sun, 12 Aug 2018 18:54:32 +0200 Subject: [PATCH 08/29] stuff does compile --- .../notifications/NotificationController.cpp | 27 ++++--- .../notifications/NotificationController.hpp | 14 +++- src/providers/twitch/TwitchChannel.cpp | 73 +++++-------------- src/singletons/Settings.hpp | 1 + src/singletons/Toasts.cpp | 21 ++++-- src/singletons/Toasts.hpp | 8 +- .../settingspages/NotificationPage.cpp | 11 ++- src/widgets/splits/SplitHeader.cpp | 6 +- 8 files changed, 73 insertions(+), 88 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index e6f6fac1d..72624991f 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -32,18 +32,16 @@ void NotificationController::initialize(Settings &settings, Paths &paths) } void NotificationController::updateChannelNotification( - const QString &channelName, int &i) + const QString &channelName, Platform p) { - if (i == 0) { - int j = 0; - if (isChannelNotified(channelName, j)) { + if (p == Platform::Twitch) { + if (isChannelNotified(channelName, Platform::Twitch)) { removeChannelNotification(channelName, twitchVector); } else { addChannelNotification(channelName, twitchVector); } - } else if (i == 1) { - int k = 1; - if (isChannelNotified(channelName, k)) { + } else if (p == Platform::Mixer) { + if (isChannelNotified(channelName, Platform::Mixer)) { removeChannelNotification(channelName, mixerVector); } else { addChannelNotification(channelName, mixerVector); @@ -52,7 +50,7 @@ void NotificationController::updateChannelNotification( } bool NotificationController::isChannelNotified(const QString &channelName, - int &i) + Platform p) { /* for (std::vector::size_type i = 0; @@ -62,15 +60,15 @@ bool NotificationController::isChannelNotified(const QString &channelName, << " vectorsize:" << notificationVector.getVector().size(); } */ - qDebug() << channelName << " channel and now i: " << i; - if (i == 0) { + // qDebug() << channelName << " channel and now i: " << i; + if (p == Platform::Twitch) { for (std::vector::size_type i = 0; i != twitchVector.getVector().size(); i++) { if (twitchVector.getVector()[i] == channelName) { return true; } } - } else if (i == 1) { + } else if (p == Platform::Mixer) { for (std::vector::size_type i = 0; i != mixerVector.getVector().size(); i++) { if (mixerVector.getVector()[i] == channelName) { @@ -164,12 +162,13 @@ void NotificationController::removeChannelNotification( } } -NotificationModel *NotificationController::createModel(QObject *parent, int &i) +NotificationModel *NotificationController::createModel(QObject *parent, + Platform p) { NotificationModel *model = new NotificationModel(parent); - if (i == 0) { + if (p == Platform::Twitch) { model->init(&this->twitchVector); - } else if (i == 1) { + } else if (p == Platform::Mixer) { model->init(&this->mixerVector); } return model; diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index d2fc87e36..8e7a5c974 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -10,25 +10,31 @@ class Paths; class NotificationModel; +enum class Platform : uint8_t { + Twitch = 0, // 0 + Mixer = 1, // 1 + HitBox = 2, // 2 +}; + class NotificationController final : public Singleton { public: virtual void initialize(Settings &settings, Paths &paths) override; - bool isChannelNotified(const QString &channelName, int &i); + bool isChannelNotified(const QString &channelName, Platform p); - void updateChannelNotification(const QString &channelName, int &i); + void updateChannelNotification(const QString &channelName, Platform p); void addChannelNotification(const QString &channelName, UnsortedSignalVector &vector); void removeChannelNotification(const QString &channelName, UnsortedSignalVector &vector); - UnsortedSignalVector getVector(int &i); + UnsortedSignalVector getVector(Platform p); UnsortedSignalVector twitchVector; UnsortedSignalVector mixerVector; - NotificationModel *createModel(QObject *parent, int &i); + NotificationModel *createModel(QObject *parent, Platform p); private: bool initialized_ = false; diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index ce4324388..49147c071 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -305,19 +305,6 @@ const QString &TwitchChannel::getPopoutPlayerUrl() return this->popoutPlayerUrl_; } -bool Toasts::isEnabled(const QString &channelName) -{ - int i = 0; - return getApp()->notifications->isChannelNotified(channelName, i); -} -/* -bool toastIsEnabled() -{ - QString channelName = this->getName(); - return getApp()->notifications->isChannelNotified(channelName); -} -*/ - void TwitchChannel::setLive(bool newLiveStatus) { bool gotNewLiveStatus = false; @@ -325,41 +312,21 @@ void TwitchChannel::setLive(bool newLiveStatus) auto guard = this->streamStatus_.access(); if (guard->live != newLiveStatus) { gotNewLiveStatus = true; - guard->live = newLiveStatus; - } - } - - if (gotNewLiveStatus) { - this->liveStatusChanged.invoke(); - } -} - -/* -void TwitchChannel::setLive(bool newLiveStatus) -{ - // auto guard = this->streamStatus_.access(); - - if (toastIsEnabled() && guard->live != newLiveStatus && guard->live != - newLiveStatus) { Toasts::show - } - - // int i = 0; - // getApp()->toasts->sendChannelNotification(this->getName(), i); - qDebug() << "setLive called here and channel: " << this->getName() - << " status: " << newLiveStatus; - - bool gotNewLiveStatus = false; - { - auto guard = this->streamStatus_.access(); - if (guard->live != newLiveStatus) { - gotNewLiveStatus = true; - guard->live = newLiveStatus; - - if (getApp()->toasts->isEnabled(this->getName()) && - guard->live == true) { - int i = 0; - getApp()->toasts->sendChannelNotification(this->getName(), i); + if (Toasts::isEnabled() && + getApp()->notifications->isChannelNotified(this->getName(), + Platform::Twitch)) { + getApp()->toasts->sendChannelNotification(this->getName(), + Platform::Twitch); } + /* + if (!guard->live && Toasts::isEnabled() && + getApp()->notifications->isChannelNotified( this->getName(), + Platform::Twitch)) { + getApp()->toasts->sendChannelNotification(this->getName(), + Platform::Twitch); + } + */ + guard->live = newLiveStatus; } } @@ -367,7 +334,7 @@ void TwitchChannel::setLive(bool newLiveStatus) this->liveStatusChanged.invoke(); } } -*/ + void TwitchChannel::refreshLiveStatus() { auto roomID = this->getRoomId(); @@ -441,15 +408,13 @@ Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document) { auto status = this->streamStatus_.access(); /* - if (!status->live == false && - getApp()->toasts->isEnabled(this->getName())) { + if (!(status->live) && getApp()->toasts->isEnabled(this->getName())) { + qDebug() << " NaM xd NaM "; int i = 0; getApp()->toasts->sendChannelNotification(this->getName(), i); // notifcation send } - status->live = true; - */ - this->setLive(true); +*/ // status->live = true; status->viewerCount = stream["viewers"].GetUint(); status->game = stream["game"].GetString(); @@ -479,7 +444,7 @@ Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document) } } } - + setLive(true); // Signal all listeners that the stream status has been updated this->liveStatusChanged.invoke(); diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 501c43287..f23189e11 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -144,6 +144,7 @@ public: false}; BoolSetting notificationPlaySound = {"/notifications/enablePlaySound", false}; + BoolSetting notificationToast = {"/notifications/enableToast", false}; /// External tools // Streamlink diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index 31f9931ee..54285e009 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -5,8 +5,12 @@ #include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchServer.hpp" +#ifdef Q_OS_WIN + #include +#endif + #include #include @@ -70,12 +74,19 @@ bool Toasts::wasChannelLive(const QString &channelName) return false; } */ -void Toasts::sendChannelNotification(const QString &channelName, int &platform) +bool Toasts::isEnabled() +{ + return WinToastLib::WinToast::isCompatible() && + getApp()->settings->notificationToast; +} + +void Toasts::sendChannelNotification(const QString &channelName, Platform p) { #ifdef Q_OS_WIN - if (WinToastLib::WinToast::isCompatible()) { - sendWindowsNotification(channelName, platform); - } + + sendWindowsNotification(channelName, p); + return; + #endif // OSX @@ -127,7 +138,7 @@ public: } }; -void Toasts::sendWindowsNotification(const QString &channelName, int &platform) +void Toasts::sendWindowsNotification(const QString &channelName, Platform p) { WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate( WinToastLib::WinToastTemplate::ImageAndText02); diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp index 0fc7dad29..68f7a8875 100644 --- a/src/singletons/Toasts.hpp +++ b/src/singletons/Toasts.hpp @@ -7,18 +7,20 @@ namespace chatterino { +enum class Platform : uint8_t; + class Toasts final : public Singleton { public: - void sendChannelNotification(const QString &channelName, int &platform); - bool isEnabled(const QString &channelName); + void sendChannelNotification(const QString &channelName, Platform p); /* Toasts(); virtual void initialize(Settings &settings, Paths &paths) override final; */ + static bool isEnabled(); private: - void sendWindowsNotification(const QString &channelName, int &platform); + void sendWindowsNotification(const QString &channelName, Platform p); /* void updateLiveChannels(const QString &channelName); void removeFromLiveChannels(const QString &channelName); diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index 50e52725f..269c1ae1e 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -35,16 +35,19 @@ NotificationPage::NotificationPage() getApp()->settings->notificationFlashTaskbar)); settings.append(this->createCheckBox( "Playsound", getApp()->settings->notificationPlaySound)); + settings.append(this->createCheckBox( + "Enable toasts (currently only for windows)", + getApp()->settings->notificationToast)); settings->addStretch(1); } auto twitchChannels = tabs.appendTab(new QVBoxLayout, "Twitch"); { - int i = 0; EditableModelView *view = twitchChannels .emplace( - getApp()->notifications->createModel(nullptr, i)) + getApp()->notifications->createModel( + nullptr, Platform::Twitch)) .getElement(); view->setTitles({"Twitch channels"}); @@ -64,11 +67,11 @@ NotificationPage::NotificationPage() } auto mixerChannels = tabs.appendTab(new QVBoxLayout, "Mixer"); { - int i = 1; EditableModelView *view = mixerChannels .emplace( - getApp()->notifications->createModel(nullptr, i)) + getApp()->notifications->createModel( + nullptr, Platform::Mixer)) .getElement(); view->setTitles({"Mixer channels"}); diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index 38682ad12..e97f4faa1 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -161,14 +161,12 @@ std::unique_ptr SplitHeader::createMainMenu() action->setCheckable(true); QObject::connect(menu.get(), &QMenu::aboutToShow, this, [action, this]() { - int i = 0; action->setChecked(getApp()->notifications->isChannelNotified( - this->split_->getChannel()->getName(), i)); + this->split_->getChannel()->getName(), Platform::Twitch)); }); action->connect(action, &QAction::triggered, this, [this]() { - int i = 0; getApp()->notifications->updateChannelNotification( - this->split_->getChannel()->getName(), i); + this->split_->getChannel()->getName(), Platform::Twitch); }); menu->addAction(action); From 320558ee63102fff595af665c52c798cbe539497 Mon Sep 17 00:00:00 2001 From: apa420 Date: Sun, 12 Aug 2018 20:21:21 +0200 Subject: [PATCH 09/29] more stuff done, does compile, changed vector for map --- .../notifications/NotificationController.cpp | 160 ++++++------------ .../notifications/NotificationController.hpp | 14 +- src/providers/twitch/TwitchChannel.cpp | 44 +++-- src/singletons/Toasts.cpp | 60 +------ src/singletons/Toasts.hpp | 19 +-- .../settingspages/NotificationPage.cpp | 13 +- 6 files changed, 96 insertions(+), 214 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 72624991f..1b1bd2b1c 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace chatterino { @@ -15,162 +16,113 @@ void NotificationController::initialize(Settings &settings, Paths &paths) { this->initialized_ = true; for (const QString &channelName : this->twitchSetting_.getValue()) { - this->twitchVector.appendItem(channelName); + this->channelMap[Platform::Twitch].appendItem(channelName); } - this->twitchVector.delayedItemsChanged.connect([this] { // - this->twitchSetting_.setValue(this->twitchVector.getVector()); + this->channelMap[Platform::Twitch].delayedItemsChanged.connect([this] { // + this->twitchSetting_.setValue( + this->channelMap[Platform::Twitch].getVector()); }); for (const QString &channelName : this->mixerSetting_.getValue()) { - this->mixerVector.appendItem(channelName); + this->channelMap[Platform::Mixer].appendItem(channelName); } - this->mixerVector.delayedItemsChanged.connect([this] { // - this->mixerSetting_.setValue(this->mixerVector.getVector()); + this->channelMap[Platform::Mixer].delayedItemsChanged.connect([this] { // + this->mixerSetting_.setValue( + this->channelMap[Platform::Mixer].getVector()); }); } void NotificationController::updateChannelNotification( const QString &channelName, Platform p) { - if (p == Platform::Twitch) { - if (isChannelNotified(channelName, Platform::Twitch)) { - removeChannelNotification(channelName, twitchVector); - } else { - addChannelNotification(channelName, twitchVector); - } - } else if (p == Platform::Mixer) { - if (isChannelNotified(channelName, Platform::Mixer)) { - removeChannelNotification(channelName, mixerVector); - } else { - addChannelNotification(channelName, mixerVector); - } + if (isChannelNotified(channelName, p)) { + removeChannelNotification(channelName, p); + } else { + addChannelNotification(channelName, p); } } bool NotificationController::isChannelNotified(const QString &channelName, Platform p) { - /* - for (std::vector::size_type i = 0; - i != notificationVector.getVector().size(); i++) { - qDebug() << notificationVector.getVector()[i] - << " vector to the left channel to the right " << channelName - << " vectorsize:" << notificationVector.getVector().size(); + for (const auto &channel : this->channelMap[p].getVector()) { + if (channelName.toLower() == channel.toLower()) { + return true; + } } - */ - // qDebug() << channelName << " channel and now i: " << i; + // for (std::vector::size_type i = 0; i != channelMap[p]) + /* if (p == Platform::Twitch) { for (std::vector::size_type i = 0; i != twitchVector.getVector().size(); i++) { - if (twitchVector.getVector()[i] == channelName) { - return true; + if (twitchVector.getVector()[i].toLower() == + channelName.toLowercase()) { return true; } } } else if (p == Platform::Mixer) { for (std::vector::size_type i = 0; i != mixerVector.getVector().size(); i++) { - if (mixerVector.getVector()[i] == channelName) { - return true; + if (mixerVector.getVector()[i].toLower() == + channelName.toLowercase()) { return true; } } } + */ return false; } -/* -class CustomHandler : public WinToastLib::IWinToastHandler + +void NotificationController::addChannelNotification(const QString &channelName, + Platform p) { -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, UnsortedSignalVector &vector) -{ - vector.appendItem(channelName); - - 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()); - */ - } + channelMap[p].appendItem(channelName); } void NotificationController::removeChannelNotification( - const QString &channelName, UnsortedSignalVector &vector) + const QString &channelName, Platform p) { - for (std::vector::size_type i = 0; i != vector.getVector().size(); - i++) { - if (vector.getVector()[i] == channelName) { - vector.removeItem(i); + for (std::vector::size_type i = 0; + i != channelMap[p].getVector().size(); i++) { + if (channelMap[p].getVector()[i].toLower() == channelName) { + channelMap[p].removeItem(i); i--; } } } +void NotificationController::playSound() +{ + static auto player = new QMediaPlayer; + static QUrl currentPlayerUrl; + + QUrl highlightSoundUrl; + if (getApp()->settings->customHighlightSound) { + highlightSoundUrl = QUrl::fromLocalFile( + getApp()->settings->pathHighlightSound.getValue()); + } else { + highlightSoundUrl = QUrl("qrc:/sounds/ping2.wav"); + } + if (currentPlayerUrl != highlightSoundUrl) { + player->setMedia(highlightSoundUrl); + + currentPlayerUrl = highlightSoundUrl; + } + player->play(); +} + NotificationModel *NotificationController::createModel(QObject *parent, Platform p) { NotificationModel *model = new NotificationModel(parent); + model->init(&this->channelMap[p]); + /* if (p == Platform::Twitch) { model->init(&this->twitchVector); } else if (p == Platform::Mixer) { model->init(&this->mixerVector); } + */ return model; } diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index 8e7a5c974..c3bfad38f 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -22,17 +22,17 @@ public: virtual void initialize(Settings &settings, Paths &paths) override; bool isChannelNotified(const QString &channelName, Platform p); - void updateChannelNotification(const QString &channelName, Platform p); - void addChannelNotification(const QString &channelName, - UnsortedSignalVector &vector); - void removeChannelNotification(const QString &channelName, - UnsortedSignalVector &vector); + void addChannelNotification(const QString &channelName, Platform p); + void removeChannelNotification(const QString &channelName, Platform p); + + void playSound(); UnsortedSignalVector getVector(Platform p); - UnsortedSignalVector twitchVector; - UnsortedSignalVector mixerVector; + std::map> channelMap; + // UnsortedSignalVector twitchVector; + // UnsortedSignalVector mixerVector; NotificationModel *createModel(QObject *parent, Platform p); diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 49147c071..39c451ec4 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -14,6 +14,7 @@ #include "singletons/Emotes.hpp" #include "singletons/Settings.hpp" #include "singletons/Toasts.hpp" +#include "singletons/WindowManager.hpp" #include "util/PostToThread.hpp" #include @@ -312,20 +313,20 @@ void TwitchChannel::setLive(bool newLiveStatus) auto guard = this->streamStatus_.access(); if (guard->live != newLiveStatus) { gotNewLiveStatus = true; - if (Toasts::isEnabled() && - getApp()->notifications->isChannelNotified(this->getName(), + if (getApp()->notifications->isChannelNotified(this->getName(), Platform::Twitch)) { - getApp()->toasts->sendChannelNotification(this->getName(), - Platform::Twitch); + if (Toasts::isEnabled()) { + getApp()->toasts->sendChannelNotification(this->getName(), + Platform::Twitch); + } + if (getApp()->settings->notificationPlaySound) { + getApp()->notifications->playSound(); + } + if (getApp()->settings->notificationFlashTaskbar) { + QApplication::alert( + getApp()->windows->getMainWindow().window(), 2500); + } } - /* - if (!guard->live && Toasts::isEnabled() && - getApp()->notifications->isChannelNotified( this->getName(), - Platform::Twitch)) { - getApp()->toasts->sendChannelNotification(this->getName(), - Platform::Twitch); - } - */ guard->live = newLiveStatus; } } @@ -351,7 +352,8 @@ void TwitchChannel::refreshLiveStatus() QString url("https://api.twitch.tv/kraken/streams/" + roomID); //<<<<<<< HEAD - // auto request = makeGetStreamRequest(roomID, QThread::currentThread()); + // auto request = makeGetStreamRequest(roomID, + // QThread::currentThread()); //======= auto request = NetworkRequest::twitchRequest(url); request.setCaller(QThread::currentThread()); @@ -398,7 +400,8 @@ Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document) const rapidjson::Value &streamChannel = stream["channel"]; if (!streamChannel.IsObject() || !streamChannel.HasMember("status")) { - Log("[TwitchChannel:refreshLiveStatus] Missing member \"status\" in " + Log("[TwitchChannel:refreshLiveStatus] Missing member \"status\" " + "in " "channel"); return Failure; } @@ -407,15 +410,6 @@ Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document) { auto status = this->streamStatus_.access(); - /* - if (!(status->live) && getApp()->toasts->isEnabled(this->getName())) { - qDebug() << " NaM xd NaM "; - int i = 0; - getApp()->toasts->sendChannelNotification(this->getName(), i); - // notifcation send - } -*/ - // status->live = true; status->viewerCount = stream["viewers"].GetUint(); status->game = stream["game"].GetString(); status->title = streamChannel["status"].GetString(); @@ -481,8 +475,8 @@ Outcome TwitchChannel::parseRecentMessages(const QJsonObject &jsonRoot) for (const auto jsonMessage : jsonMessages) { auto content = jsonMessage.toString().toUtf8(); - // passing nullptr as the channel makes the message invalid but we don't - // check for that anyways + // passing nullptr as the channel makes the message invalid but we + // don't check for that anyways auto message = Communi::IrcMessage::fromData(content, nullptr); auto privMsg = dynamic_cast(message); assert(privMsg); diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index 54285e009..3586944fe 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -18,62 +18,6 @@ namespace chatterino { -/* -Toasts::Toasts() -{ -} -*/ -/* -void Toasts::initialize(Settings &settings, Paths &paths) -{ - getApp()->twitch2->forEachChannel([this](ChannelPtr chn) { - auto twchn = dynamic_cast(chn.get()); - twchn->liveStatusChanged.connect([twchn, this]() { - const auto streamStatus = twchn->accessStreamStatus(); - if (streamStatus->live) { - // is live - if (getApp()->notifications->isChannelNotified( - twchn->getName()) && - !wasChannelLive(twchn->getName())) { - sendChannelNotification(twchn->getName()); - } - updateLiveChannels(twchn->getName()); - } else { - // is Offline - removeFromLiveChannels(twchn->getName()); - } - }); - }); -} - -void Toasts::updateLiveChannels(const QString &channelName) -{ - if (!wasChannelLive(channelName)) { - std::lock_guard lock(mutex_); - liveChannels.push_back(channelName); - } -} - -void Toasts::removeFromLiveChannels(const QString &channelName) -{ - if (wasChannelLive(channelName)) { - std::lock_guard lock(mutex_); - liveChannels.erase( - std::find(liveChannels.begin(), liveChannels.end(), channelName)); - } -} - -bool Toasts::wasChannelLive(const QString &channelName) -{ - std::lock_guard lock(mutex_); - for (const auto &str : liveChannels) { - if (str == channelName) { - return true; - } - } - return false; -} -*/ bool Toasts::isEnabled() { return WinToastLib::WinToast::isCompatible() && @@ -149,6 +93,10 @@ void Toasts::sendWindowsNotification(const QString &channelName, Platform p) templ.setTextField(widestr, WinToastLib::WinToastTemplate::FirstLine); templ.setTextField(L"Click here to open in browser", WinToastLib::WinToastTemplate::SecondLine); + if (getApp()->settings->notificationPlaySound) { + templ.setAudioOption( + WinToastLib::WinToastTemplate::AudioOption::Silent); + } WinToastLib::WinToast::instance()->setAppName(L"Chatterino2"); int mbstowcs(wchar_t * aumi_version, const char *CHATTERINO_VERSION, size_t size); diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp index 68f7a8875..5f66d93f4 100644 --- a/src/singletons/Toasts.hpp +++ b/src/singletons/Toasts.hpp @@ -3,8 +3,6 @@ #include "Application.hpp" #include "common/Singleton.hpp" -//#include - namespace chatterino { enum class Platform : uint8_t; @@ -13,25 +11,10 @@ class Toasts final : public Singleton { public: void sendChannelNotification(const QString &channelName, Platform p); - /* - Toasts(); - virtual void initialize(Settings &settings, Paths &paths) override final; - */ + static bool isEnabled(); private: void sendWindowsNotification(const QString &channelName, Platform p); - /* - void updateLiveChannels(const QString &channelName); - void removeFromLiveChannels(const QString &channelName); - - bool wasChannelLive(const QString &channelName); - - void shouldChannelBeNotified(const QString &channelName); - void sendChannelNotification(const QString &channelName); - void sendWindowsNotification(const QString &channelName); - std::vector liveChannels; - std::mutex mutex_; - */ }; } // namespace chatterino diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index 269c1ae1e..6a0b9e55e 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -34,9 +34,10 @@ NotificationPage::NotificationPage() "Flash taskbar", getApp()->settings->notificationFlashTaskbar)); settings.append(this->createCheckBox( - "Playsound", getApp()->settings->notificationPlaySound)); + "Playsound (doesn't mute the Windows 8.x sound of toasts)", + getApp()->settings->notificationPlaySound)); settings.append(this->createCheckBox( - "Enable toasts (currently only for windows)", + "Enable toasts (currently only for windows 8.x or 10)", getApp()->settings->notificationToast)); settings->addStretch(1); @@ -62,7 +63,9 @@ NotificationPage::NotificationPage() }); view->addButtonPressed.connect([] { - getApp()->notifications->twitchVector.appendItem("channel"); + getApp() + ->notifications->channelMap[Platform::Twitch] + .appendItem("channel"); }); } auto mixerChannels = tabs.appendTab(new QVBoxLayout, "Mixer"); @@ -86,7 +89,9 @@ NotificationPage::NotificationPage() }); view->addButtonPressed.connect([] { - getApp()->notifications->mixerVector.appendItem("channel"); + getApp() + ->notifications->channelMap[Platform::Mixer] + .appendItem("channel"); }); } } From 93bbe33664c9b41c973c91f1634410e5a9d62c34 Mon Sep 17 00:00:00 2001 From: apa420 Date: Sun, 12 Aug 2018 21:05:12 +0200 Subject: [PATCH 10/29] Cleaned some stuff up and did some things --- chatterino.pro | 5 ---- .../notifications/NotificationController.cpp | 30 ++----------------- .../notifications/NotificationController.hpp | 9 +++--- src/providers/twitch/TwitchChannel.cpp | 10 +++---- src/providers/twitch/TwitchChannel.hpp | 4 --- .../settingspages/NotificationPage.cpp | 2 ++ 6 files changed, 13 insertions(+), 47 deletions(-) diff --git a/chatterino.pro b/chatterino.pro index ed8682ba0..ea1277208 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -231,7 +231,6 @@ SOURCES += \ src/singletons/Updates.cpp \ src/singletons/Theme.cpp \ src/controllers/moderationactions/ModerationActionModel.cpp \ - src/widgets/settingspages/NotificationPage.cpp \ src/widgets/settingspages/LookPage.cpp \ src/widgets/settingspages/FeelPage.cpp \ src/util/InitUpdateButton.cpp \ @@ -255,8 +254,6 @@ SOURCES += \ src/BrowserExtension.cpp \ src/util/FormatTime.cpp \ src/util/FunctionEventFilter.cpp \ - src/controllers/notifications/notificationcontroller.cpp \ - src/widgets/settingspages/NotificationPage.cpp \ src/controllers/notifications/NotificationModel.cpp \ src/singletons/Toasts.cpp @@ -433,7 +430,6 @@ HEADERS += \ src/widgets/dialogs/LogsPopup.hpp \ src/common/Singleton.hpp \ src/controllers/moderationactions/ModerationActionModel.hpp \ - src/widgets/settingspages/NotificationPage.hpp \ src/widgets/settingspages/LookPage.hpp \ src/widgets/settingspages/FeelPage.hpp \ src/util/InitUpdateButton.hpp \ @@ -460,7 +456,6 @@ HEADERS += \ src/BrowserExtension.hpp \ src/util/FormatTime.hpp \ src/util/FunctionEventFilter.hpp \ - src/widgets/settingspages/NotificationPage.hpp \ src/controllers/notifications/NotificationModel.hpp \ src/controllers/notifications/NotificationPhrase.hpp \ src/singletons/Toasts.hpp diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 1b1bd2b1c..92272f978 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -23,7 +23,7 @@ void NotificationController::initialize(Settings &settings, Paths &paths) this->twitchSetting_.setValue( this->channelMap[Platform::Twitch].getVector()); }); - + /* for (const QString &channelName : this->mixerSetting_.getValue()) { this->channelMap[Platform::Mixer].appendItem(channelName); } @@ -32,6 +32,7 @@ void NotificationController::initialize(Settings &settings, Paths &paths) this->mixerSetting_.setValue( this->channelMap[Platform::Mixer].getVector()); }); + */ } void NotificationController::updateChannelNotification( @@ -52,24 +53,6 @@ bool NotificationController::isChannelNotified(const QString &channelName, return true; } } - // for (std::vector::size_type i = 0; i != channelMap[p]) - /* - if (p == Platform::Twitch) { - for (std::vector::size_type i = 0; - i != twitchVector.getVector().size(); i++) { - if (twitchVector.getVector()[i].toLower() == - channelName.toLowercase()) { return true; - } - } - } else if (p == Platform::Mixer) { - for (std::vector::size_type i = 0; - i != mixerVector.getVector().size(); i++) { - if (mixerVector.getVector()[i].toLower() == - channelName.toLowercase()) { return true; - } - } - } - */ return false; } @@ -84,7 +67,7 @@ void NotificationController::removeChannelNotification( { for (std::vector::size_type i = 0; i != channelMap[p].getVector().size(); i++) { - if (channelMap[p].getVector()[i].toLower() == channelName) { + if (channelMap[p].getVector()[i].toLower() == channelName.toLower()) { channelMap[p].removeItem(i); i--; } @@ -116,13 +99,6 @@ NotificationModel *NotificationController::createModel(QObject *parent, { NotificationModel *model = new NotificationModel(parent); model->init(&this->channelMap[p]); - /* - if (p == Platform::Twitch) { - model->init(&this->twitchVector); - } else if (p == Platform::Mixer) { - model->init(&this->mixerVector); - } - */ return model; } diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index c3bfad38f..da5bcd03a 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -11,9 +11,8 @@ class Paths; class NotificationModel; enum class Platform : uint8_t { - Twitch = 0, // 0 - Mixer = 1, // 1 - HitBox = 2, // 2 + Twitch, // 0 + // Mixer, // 1 }; class NotificationController final : public Singleton @@ -31,8 +30,6 @@ public: UnsortedSignalVector getVector(Platform p); std::map> channelMap; - // UnsortedSignalVector twitchVector; - // UnsortedSignalVector mixerVector; NotificationModel *createModel(QObject *parent, Platform p); @@ -40,8 +37,10 @@ private: bool initialized_ = false; ChatterinoSetting> twitchSetting_ = { "/notifications/twitch"}; + /* ChatterinoSetting> mixerSetting_ = { "/notifications/mixer"}; + */ }; } // namespace chatterino diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 39c451ec4..864fba437 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -352,8 +352,7 @@ void TwitchChannel::refreshLiveStatus() QString url("https://api.twitch.tv/kraken/streams/" + roomID); //<<<<<<< HEAD - // auto request = makeGetStreamRequest(roomID, - // QThread::currentThread()); + // auto request = makeGetStreamRequest(roomID, QThread::currentThread()); //======= auto request = NetworkRequest::twitchRequest(url); request.setCaller(QThread::currentThread()); @@ -400,8 +399,7 @@ Outcome TwitchChannel::parseLiveStatus(const rapidjson::Document &document) const rapidjson::Value &streamChannel = stream["channel"]; if (!streamChannel.IsObject() || !streamChannel.HasMember("status")) { - Log("[TwitchChannel:refreshLiveStatus] Missing member \"status\" " - "in " + Log("[TwitchChannel:refreshLiveStatus] Missing member \"status\" in " "channel"); return Failure; } @@ -475,8 +473,8 @@ Outcome TwitchChannel::parseRecentMessages(const QJsonObject &jsonRoot) for (const auto jsonMessage : jsonMessages) { auto content = jsonMessage.toString().toUtf8(); - // passing nullptr as the channel makes the message invalid but we - // don't check for that anyways + // passing nullptr as the channel makes the message invalid but we don't + // check for that anyways auto message = Communi::IrcMessage::fromData(content, nullptr); auto privMsg = dynamic_cast(message); assert(privMsg); diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index 000b1bbec..bc084d73f 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -118,8 +118,6 @@ private: void loadRecentMessages(); Outcome parseRecentMessages(const QJsonObject &jsonRoot); - bool toastIsEnabled(); - void setLive(bool newLiveStatus); void loadBadges(); @@ -155,8 +153,6 @@ private: QTimer liveStatusTimer_; QTimer chattersListTimer_; - std::vector liveChannels; - friend class TwitchServer; }; diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index 6a0b9e55e..6dd756b80 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -68,6 +68,7 @@ NotificationPage::NotificationPage() .appendItem("channel"); }); } + /* auto mixerChannels = tabs.appendTab(new QVBoxLayout, "Mixer"); { EditableModelView *view = @@ -94,6 +95,7 @@ NotificationPage::NotificationPage() .appendItem("channel"); }); } + */ } } } From b671fc41333523d6a10dfec00c84a93a0ae7bfa0 Mon Sep 17 00:00:00 2001 From: apa420 Date: Tue, 14 Aug 2018 16:29:52 +0200 Subject: [PATCH 11/29] Tried chaning the color of the split when a channel is live --- src/common/Common.hpp | 1 + .../notifications/NotificationController.cpp | 5 +++-- src/providers/twitch/TwitchChannel.cpp | 2 ++ src/providers/twitch/TwitchChannel.hpp | 1 + src/singletons/Theme.cpp | 12 ++++++++++-- src/singletons/Theme.hpp | 1 + src/widgets/helper/NotebookTab.cpp | 6 ++++-- 7 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/common/Common.hpp b/src/common/Common.hpp index 251727c24..180dfb6a3 100644 --- a/src/common/Common.hpp +++ b/src/common/Common.hpp @@ -18,6 +18,7 @@ enum class HighlightState { None, Highlighted, NewMessage, + Notification, }; inline QString qS(const std::string &string) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 92272f978..d07b3a794 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -2,6 +2,7 @@ #include "Application.hpp" #include "controllers/notifications/NotificationModel.hpp" +#include "singletons/Toasts.hpp" #include @@ -73,7 +74,7 @@ void NotificationController::removeChannelNotification( } } } - +/////////////////////////////////////////////////// void NotificationController::playSound() { static auto player = new QMediaPlayer; @@ -93,7 +94,7 @@ void NotificationController::playSound() } player->play(); } - +/////////////////////////////////////////////////// NotificationModel *NotificationController::createModel(QObject *parent, Platform p) { diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 864fba437..dcc083161 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -326,6 +326,8 @@ void TwitchChannel::setLive(bool newLiveStatus) QApplication::alert( getApp()->windows->getMainWindow().window(), 2500); } + this->tabHighlightRequested.invoke( + HighlightState::Notification); } guard->live = newLiveStatus; } diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index bc084d73f..ec690aefd 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -86,6 +86,7 @@ public: pajlada::Signals::NoArgSignal liveStatusChanged; pajlada::Signals::NoArgSignal userStateChanged; pajlada::Signals::NoArgSignal roomModesChanged; + pajlada::Signals::Signal tabHighlightRequested; private: struct NameOptions { diff --git a/src/singletons/Theme.cpp b/src/singletons/Theme.cpp index c5aa16b71..eb20a7647 100644 --- a/src/singletons/Theme.cpp +++ b/src/singletons/Theme.cpp @@ -105,6 +105,10 @@ void Theme::actuallyUpdate(double hue, double multiplier) QColor("#000"), {QColor("#b4d7ff"), QColor("#b4d7ff"), QColor("#b4d7ff")}, {QColor("#00aeef"), QColor("#00aeef"), QColor("#00aeef")}}; + this->tabs.notified = { + fg, + {QColor("#252525"), QColor("#252525"), QColor("#252525")}, + {QColor("#F824A8"), QColor("#F824A8"), QColor("#F824A8")}}; } else { this->tabs.regular = { QColor("#aaa"), @@ -123,6 +127,10 @@ void Theme::actuallyUpdate(double hue, double multiplier) QColor("#fff"), {QColor("#555555"), QColor("#555555"), QColor("#555555")}, {QColor("#00aeef"), QColor("#00aeef"), QColor("#00aeef")}}; + this->tabs.notified = { + fg, + {QColor("#252525"), QColor("#252525"), QColor("#252525")}, + {QColor("#F824A8"), QColor("#F824A8"), QColor("#F824A8")}}; } this->splits.input.focusedLine = highlighted; @@ -150,7 +158,7 @@ void Theme::actuallyUpdate(double hue, double multiplier) // QColor("#777"), QColor("#666")}}; this->tabs.bottomLine = this->tabs.selected.backgrounds.regular.color(); - } + } // namespace chatterino // Split bool flat = isLight_; @@ -232,7 +240,7 @@ void Theme::actuallyUpdate(double hue, double multiplier) isLightTheme() ? QColor(0, 0, 0, 64) : QColor(255, 255, 255, 64); this->updated.invoke(); -} +} // namespace chatterino QColor Theme::blendColors(const QColor &color1, const QColor &color2, qreal ratio) diff --git a/src/singletons/Theme.hpp b/src/singletons/Theme.hpp index 47bb6c3ef..66b859aaa 100644 --- a/src/singletons/Theme.hpp +++ b/src/singletons/Theme.hpp @@ -49,6 +49,7 @@ public: TabColors newMessage; TabColors highlighted; TabColors selected; + TabColors notified; QColor border; QColor bottomLine; } tabs; diff --git a/src/widgets/helper/NotebookTab.cpp b/src/widgets/helper/NotebookTab.cpp index c9c55ff2c..0e9a97662 100644 --- a/src/widgets/helper/NotebookTab.cpp +++ b/src/widgets/helper/NotebookTab.cpp @@ -169,8 +169,8 @@ void NotebookTab::setHighlightState(HighlightState newHighlightStyle) if (this->isSelected()) { return; } - - if (this->highlightState_ != HighlightState::Highlighted) { + if (this->highlightState_ != HighlightState::Highlighted && + this->highlightState_ != HighlightState::Notification) { this->highlightState_ = newHighlightStyle; this->update(); @@ -237,6 +237,8 @@ void NotebookTab::paintEvent(QPaintEvent *) colors = this->theme->tabs.selected; } else if (this->highlightState_ == HighlightState::Highlighted) { colors = this->theme->tabs.highlighted; + } else if (this->highlightState_ == HighlightState::Notification) { + colors = this->theme->tabs.notified; } else if (this->highlightState_ == HighlightState::NewMessage) { colors = this->theme->tabs.newMessage; } else { From 15e9e3e64291ea224db05c48975d71836d55e5f1 Mon Sep 17 00:00:00 2001 From: apa420 Date: Fri, 17 Aug 2018 21:19:15 +0200 Subject: [PATCH 12/29] Added functionality of colored splits when live --- src/messages/Message.hpp | 1 + src/providers/twitch/TwitchChannel.cpp | 7 +++++-- src/widgets/helper/ChannelView.cpp | 9 +++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/messages/Message.hpp b/src/messages/Message.hpp index 76039ec41..06b995b5a 100644 --- a/src/messages/Message.hpp +++ b/src/messages/Message.hpp @@ -26,6 +26,7 @@ enum class MessageFlag : uint16_t { Untimeout = (1 << 9), PubSub = (1 << 10), Subscription = (1 << 11), + Notification = (1 << 12), }; using MessageFlags = FlagsEnum; diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index dcc083161..a26927967 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -38,6 +38,8 @@ TwitchChannel::TwitchChannel(const QString &name) // this->refreshChannelEmotes(); // this->refreshViewerList(); + this->tabHighlightRequested.connect([](HighlightState state) {}); + this->managedConnect(getApp()->accounts->twitch.currentUserChanged, [=] { this->setMod(false); }); @@ -326,9 +328,10 @@ void TwitchChannel::setLive(bool newLiveStatus) QApplication::alert( getApp()->windows->getMainWindow().window(), 2500); } - this->tabHighlightRequested.invoke( - HighlightState::Notification); } + auto live = makeSystemMessage(this->getName() + " is live"); + this->addMessage(live); + this->tabHighlightRequested.invoke(HighlightState::Notification); guard->live = newLiveStatus; } } diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 2dbf4d339..2ea32bb53 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -6,6 +6,7 @@ #include "messages/LimitedQueueSnapshot.hpp" #include "messages/Message.hpp" #include "messages/layouts/MessageLayout.hpp" +#include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchServer.hpp" #include "singletons/Settings.hpp" #include "singletons/Theme.hpp" @@ -552,6 +553,14 @@ void ChannelView::setChannel(ChannelPtr newChannel) this->layoutMessages(); this->queueUpdate(); + + // Notifications + TwitchChannel *tc = dynamic_cast(newChannel.get()); + if (tc != nullptr) { + tc->tabHighlightRequested.connect([this](HighlightState state) { + this->tabHighlightRequested.invoke(HighlightState::Notification); + }); + } } void ChannelView::detachChannel() From 3d109a6ca371e6a0aeb394fe223eee5fcbfde913 Mon Sep 17 00:00:00 2001 From: apa420 Date: Sat, 18 Aug 2018 13:07:12 +0200 Subject: [PATCH 13/29] added settings for dot next to channel name --- src/singletons/Settings.hpp | 1 + src/widgets/settingspages/NotificationPage.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index f23189e11..1dc0b9192 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -145,6 +145,7 @@ public: BoolSetting notificationPlaySound = {"/notifications/enablePlaySound", false}; BoolSetting notificationToast = {"/notifications/enableToast", false}; + BoolSetting notificationDot = {"/notifications/enableDot", false}; /// External tools // Streamlink diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index 6dd756b80..54e342c4a 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -28,8 +28,7 @@ NotificationPage::NotificationPage() { auto settings = tabs.appendTab(new QVBoxLayout, "Options"); { - settings.emplace( - "Enable for channel next to channel name"); + settings.emplace("Enable for selected channels"); settings.append(this->createCheckBox( "Flash taskbar", getApp()->settings->notificationFlashTaskbar)); @@ -39,6 +38,9 @@ NotificationPage::NotificationPage() settings.append(this->createCheckBox( "Enable toasts (currently only for windows 8.x or 10)", getApp()->settings->notificationToast)); + settings.append( + this->createCheckBox("Red dot next to live splits", + getApp()->settings->notificationDot)); settings->addStretch(1); } From 21c4880ace8c66a290ebb68beef9efaec75f5c27 Mon Sep 17 00:00:00 2001 From: apa420 Date: Sun, 19 Aug 2018 15:09:00 +0200 Subject: [PATCH 14/29] for pajlada --- chatterino.pro | 6 +- src/Application.cpp | 4 +- src/Application.hpp | 2 + src/providers/twitch/TwitchChannel.cpp | 4 + src/singletons/Toasts.cpp | 180 ++++++++++++++++++++----- src/singletons/Toasts.hpp | 10 ++ 6 files changed, 172 insertions(+), 34 deletions(-) diff --git a/chatterino.pro b/chatterino.pro index ea1277208..3252d9e60 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -255,7 +255,8 @@ SOURCES += \ src/util/FormatTime.cpp \ src/util/FunctionEventFilter.cpp \ src/controllers/notifications/NotificationModel.cpp \ - src/singletons/Toasts.cpp + src/singletons/Toasts.cpp \ + src/singletons/DownloadManager.cpp HEADERS += \ src/Application.hpp \ @@ -458,7 +459,8 @@ HEADERS += \ src/util/FunctionEventFilter.hpp \ src/controllers/notifications/NotificationModel.hpp \ src/controllers/notifications/NotificationPhrase.hpp \ - src/singletons/Toasts.hpp + src/singletons/Toasts.hpp \ + src/singletons/DownloadManager.hpp RESOURCES += \ resources/resources.qrc \ diff --git a/src/Application.cpp b/src/Application.cpp index b90a8d445..cf0cb2ef3 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -12,6 +12,7 @@ #include "providers/ffz/FfzEmotes.hpp" #include "providers/twitch/PubsubClient.hpp" #include "providers/twitch/TwitchServer.hpp" +#include "singletons/DownloadManager.hpp" #include "singletons/Fonts.hpp" #include "singletons/Logging.hpp" #include "singletons/NativeMessaging.hpp" @@ -46,6 +47,7 @@ Application::Application(Settings &_settings, Paths &_paths) , emotes(&this->emplace()) , windows(&this->emplace()) + , toasts(&this->emplace()) , accounts(&this->emplace()) , commands(&this->emplace()) , highlights(&this->emplace()) @@ -55,7 +57,7 @@ Application::Application(Settings &_settings, Paths &_paths) , moderationActions(&this->emplace()) , twitch2(&this->emplace()) , logging(&this->emplace()) - , toasts(&this->emplace()) + , downloads(&this->emplace()) { this->instance = this; diff --git a/src/Application.hpp b/src/Application.hpp index b1dbe2406..64f926621 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -29,6 +29,7 @@ class Settings; class Fonts; class Resources; class Toasts; +class DownloadManager; class Application { @@ -58,6 +59,7 @@ public: Emotes *const emotes{}; WindowManager *const windows{}; Toasts *const toasts{}; + DownloadManager *const downloads{}; AccountController *const accounts{}; CommandController *const commands{}; diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index a26927967..6915372c7 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -39,6 +39,10 @@ TwitchChannel::TwitchChannel(const QString &name) // this->refreshViewerList(); this->tabHighlightRequested.connect([](HighlightState state) {}); + this->liveStatusChanged.connect([this]() { + if (this->isLive() == 1) { + } + }); this->managedConnect(getApp()->accounts->twitch.currentUserChanged, [=] { this->setMod(false); }); diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index 3586944fe..bf6542850 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -1,8 +1,10 @@ #include "Toasts.hpp" #include "Application.hpp" +#include "common/NetworkRequest.hpp" #include "controllers/notifications/NotificationController.hpp" #include "providers/twitch/TwitchChannel.hpp" +#include "providers/twitch/TwitchCommon.hpp" #include "providers/twitch/TwitchServer.hpp" #ifdef Q_OS_WIN @@ -12,6 +14,10 @@ #endif #include +#include +//#include +#include +#include #include #include @@ -39,60 +45,87 @@ void Toasts::sendChannelNotification(const QString &channelName, Platform p) #ifdef Q_OS_WIN +/*const override void CustomToastHandler::toastActivated() +{ +}*/ + class CustomHandler : public WinToastLib::IWinToastHandler { +private: + QString channelName_; + Platform platform_; + public: + CustomHandler(QString channelName, Platform p) + : channelName_(channelName) + , platform_(p) + { + } void toastActivated() const { - std::wcout << L"The user clicked in this toast" << std::endl; - QString link = "http://www.google.com"; + QString link; + if (platform_ == Platform::Twitch) { + link = "http://www.twitch.tv/" + channelName_; + } QDesktopServices::openUrl(QUrl(link)); } void toastActivated(int actionIndex) const { - // std::wcout << L"The user clicked on button #" << actionIndex - // << L" in this toast" << std::endl; } 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 Toasts::sendWindowsNotification(const QString &channelName, Platform p) +{ + // Fetch user profile avatar + if (p == Platform::Twitch) { + QFileInfo check_file( + QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + + "2/cache/profileAvatars/twitch/" + channelName + ".png"); + if (check_file.exists() && check_file.isFile()) { + qDebug() << " OMEGA2NAM "; + this->sendActualWindowsNotification(channelName, p); + } else { + qDebug() << " OMEGA1NAM "; + this->fetchChannelAvatar( + channelName, [this, channelName, p](QString avatarLink) { + qDebug() << " OMEGANAM " << avatarLink; + this->sendActualWindowsNotification(channelName, p); + }); + } + } + qDebug() << " YOU'RE TOO SLOW! "; +} + +void Toasts::sendActualWindowsNotification(const QString &channelName, + Platform p) { WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate( WinToastLib::WinToastTemplate::ImageAndText02); - QString str = channelName + " has just gone live!"; + QString str = channelName + " is live!"; std::string utf8_text = str.toUtf8().constData(); std::wstring widestr = std::wstring(utf8_text.begin(), utf8_text.end()); templ.setTextField(widestr, WinToastLib::WinToastTemplate::FirstLine); templ.setTextField(L"Click here to open in browser", WinToastLib::WinToastTemplate::SecondLine); + QString Path; + if (p == Platform::Twitch) { + Path = + QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + + "2/cache/profileAvatars/twitch/" + channelName + ".png"; + } + std::string temp_Utf8 = Path.toUtf8().constData(); + std::wstring imagePath = std::wstring(temp_Utf8.begin(), temp_Utf8.end()); + templ.setImagePath(imagePath); if (getApp()->settings->notificationPlaySound) { templ.setAudioOption( WinToastLib::WinToastTemplate::AudioOption::Silent); @@ -103,17 +136,102 @@ void Toasts::sendWindowsNotification(const QString &channelName, Platform p) std::string(CHATTERINO_VERSION); std::wstring aumi_version = std::wstring(CHATTERINO_VERSION.begin(), CHATTERINO_VERSION.end()); - // int mbstowcs(wchar_t *out, const char *in, size_t size); - /* -std::wstring aumi_version = -std::wstring(std::string(CHATTERINO_VERSION).begin(), - std::string(CHATTERINO_VERSION).end());*/ WinToastLib::WinToast::instance()->setAppUserModelId( WinToastLib::WinToast::configureAUMI(L"", L"Chatterino 2", L"", aumi_version)); WinToastLib::WinToast::instance()->initialize(); - WinToastLib::WinToast::instance()->showToast(templ, new CustomHandler()); + WinToastLib::WinToast::instance()->showToast( + templ, new CustomHandler(channelName, p)); } -#endif +#endif +/* +void Toasts::fetchChannelAvatar(const QString &channelName, + std::function successCallback) +{ + QString requestUrl("https://api.twitch.tv/kraken/users?login=" + + channelName); + NetworkRequest request(requestUrl, NetworkRequestType::Put); + request.setCaller(QThread::currentThread()); + request.makeAuthorizedV5(getDefaultClientID()); + request.setTimeout(30000); + request.onSuccess([successCallback](auto result) -> Outcome { + auto root = result.parseJson(); + if (!root.value("users").isArray()) { + Log("API Error while getting user id, users is not an array"); + successCallback(""); + return Failure; + } + auto users = root.value("users").toArray(); + if (users.size() != 1) { + Log("API Error while getting user id, users array size is not 1"); + successCallback(""); + return Failure; + } + if (!users[0].isObject()) { + Log("API Error while getting user id, first user is not an object"); + successCallback(""); + return Failure; + } + auto firstUser = users[0].toObject(); + auto avatar = firstUser.value("logo"); + if (!avatar.isString()) { + Log("API Error: while getting user logo, first user object `logo` " + "key " + "is not a " + "string"); + successCallback(""); + return Failure; + } + successCallback(avatar.toString()); + return Success; + }); + + request.execute(); +} +*/ +void Toasts::fetchChannelAvatar(const QString channelName, + std::function successCallback) +{ + QString requestUrl("https://api.twitch.tv/kraken/users?login=" + + channelName); + + NetworkRequest request(requestUrl); + request.setCaller(QThread::currentThread()); + request.makeAuthorizedV5(getDefaultClientID()); + request.setTimeout(30000); + request.onSuccess([successCallback](auto result) mutable -> Outcome { + auto root = result.parseJson(); + if (!root.value("users").isArray()) { + Log("API Error while getting user id, users is not an array"); + successCallback(""); + return Failure; + } + auto users = root.value("users").toArray(); + if (users.size() != 1) { + Log("API Error while getting user id, users array size is not 1"); + successCallback(""); + return Failure; + } + if (!users[0].isObject()) { + Log("API Error while getting user id, first user is not an object"); + successCallback(""); + return Failure; + } + auto firstUser = users[0].toObject(); + auto avatar = firstUser.value("logo"); + if (!avatar.isString()) { + Log("API Error: while getting user avatar, first user object " + "`avatar` key " + "is not a " + "string"); + successCallback(""); + return Failure; + } + successCallback(avatar.toString()); + return Success; + }); + + request.execute(); +} } // namespace chatterino diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp index 5f66d93f4..c51dd3915 100644 --- a/src/singletons/Toasts.hpp +++ b/src/singletons/Toasts.hpp @@ -2,7 +2,13 @@ #include "Application.hpp" #include "common/Singleton.hpp" +/* +#ifdef Q_OS_WIN +#include "wintoastlib.h" + +#endif +*/ namespace chatterino { enum class Platform : uint8_t; @@ -16,5 +22,9 @@ public: private: void sendWindowsNotification(const QString &channelName, Platform p); + void sendActualWindowsNotification(const QString &channelName, Platform p); + static void fetchChannelAvatar( + const QString channelName, + std::function successCallback); }; } // namespace chatterino From 8d5b93fe82a71490e17a442d795d9f4a30aafe26 Mon Sep 17 00:00:00 2001 From: apa420 Date: Sun, 19 Aug 2018 19:02:49 +0200 Subject: [PATCH 15/29] push for now --- chatterino.pro | 5 +- src/Application.cpp | 5 +- src/Application.hpp | 2 - src/common/DownloadManager.cpp | 80 ++++++++++++++ src/common/DownloadManager.hpp | 36 ++++++ src/singletons/Settings.hpp | 2 + src/singletons/Toasts.cpp | 104 +++++------------- src/singletons/Toasts.hpp | 7 -- .../settingspages/NotificationPage.cpp | 3 + src/widgets/splits/SplitHeader.cpp | 16 ++- 10 files changed, 170 insertions(+), 90 deletions(-) create mode 100644 src/common/DownloadManager.cpp create mode 100644 src/common/DownloadManager.hpp diff --git a/chatterino.pro b/chatterino.pro index 3252d9e60..8003eba1a 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -256,7 +256,7 @@ SOURCES += \ src/util/FunctionEventFilter.cpp \ src/controllers/notifications/NotificationModel.cpp \ src/singletons/Toasts.cpp \ - src/singletons/DownloadManager.cpp + src/common/DownloadManager.cpp HEADERS += \ src/Application.hpp \ @@ -458,9 +458,8 @@ HEADERS += \ src/util/FormatTime.hpp \ src/util/FunctionEventFilter.hpp \ src/controllers/notifications/NotificationModel.hpp \ - src/controllers/notifications/NotificationPhrase.hpp \ src/singletons/Toasts.hpp \ - src/singletons/DownloadManager.hpp + src/common/DownloadManager.hpp RESOURCES += \ resources/resources.qrc \ diff --git a/src/Application.cpp b/src/Application.cpp index cf0cb2ef3..cde5c1c09 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -12,7 +12,6 @@ #include "providers/ffz/FfzEmotes.hpp" #include "providers/twitch/PubsubClient.hpp" #include "providers/twitch/TwitchServer.hpp" -#include "singletons/DownloadManager.hpp" #include "singletons/Fonts.hpp" #include "singletons/Logging.hpp" #include "singletons/NativeMessaging.hpp" @@ -46,8 +45,8 @@ Application::Application(Settings &_settings, Paths &_paths) , fonts(&this->emplace()) , emotes(&this->emplace()) , windows(&this->emplace()) - , toasts(&this->emplace()) + , accounts(&this->emplace()) , commands(&this->emplace()) , highlights(&this->emplace()) @@ -57,7 +56,7 @@ Application::Application(Settings &_settings, Paths &_paths) , moderationActions(&this->emplace()) , twitch2(&this->emplace()) , logging(&this->emplace()) - , downloads(&this->emplace()) + { this->instance = this; diff --git a/src/Application.hpp b/src/Application.hpp index 64f926621..b1dbe2406 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -29,7 +29,6 @@ class Settings; class Fonts; class Resources; class Toasts; -class DownloadManager; class Application { @@ -59,7 +58,6 @@ public: Emotes *const emotes{}; WindowManager *const windows{}; Toasts *const toasts{}; - DownloadManager *const downloads{}; AccountController *const accounts{}; CommandController *const commands{}; diff --git a/src/common/DownloadManager.cpp b/src/common/DownloadManager.cpp new file mode 100644 index 000000000..41d2aad62 --- /dev/null +++ b/src/common/DownloadManager.cpp @@ -0,0 +1,80 @@ +#include "DownloadManager.hpp" + +#include + +namespace chatterino { + +DownloadManager::DownloadManager(QObject *parent) + : QObject(parent) +{ + manager = new QNetworkAccessManager; +} + +DownloadManager::~DownloadManager() +{ + manager->deleteLater(); +} + +void DownloadManager::setFile(QString fileURL, const QString &channelName) +{ + QString filePath = fileURL; + QString saveFilePath; + QStringList filePathList = filePath.split('/'); + // QString fileName = filePathList.at(filePathList.count() - 1); + saveFilePath = QString( + QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + + "2/cache/profileAvatars/twitch/" + channelName + ".png"); + + QNetworkRequest request; + request.setUrl(QUrl(fileURL)); + reply = manager->get(request); + + file = new QFile; + file->setFileName(saveFilePath); + file->open(QIODevice::WriteOnly); + + connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, + SLOT(onDownloadProgress(qint64, qint64))); + connect(manager, SIGNAL(finished(QNetworkReply *)), this, + SLOT(onFinished(QNetworkReply *))); + connect(reply, SIGNAL(readyRead()), this, SLOT(onReadyRead())); + connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished())); +} + +void DownloadManager::onDownloadProgress(qint64 bytesRead, qint64 bytesTotal) +{ + qDebug(QString::number(bytesRead).toLatin1() + " - " + + QString::number(bytesTotal).toLatin1()); +} + +void DownloadManager::onFinished(QNetworkReply *reply) +{ + switch (reply->error()) { + case QNetworkReply::NoError: { + qDebug("file is downloaded successfully."); + } break; + default: { + qDebug(reply->errorString().toLatin1()); + }; + } + + if (file->isOpen()) { + file->close(); + file->deleteLater(); + } + emit downloadComplete(); +} + +void DownloadManager::onReadyRead() +{ + file->write(reply->readAll()); +} + +void DownloadManager::onReplyFinished() +{ + if (file->isOpen()) { + file->close(); + file->deleteLater(); + } +} +} // namespace chatterino diff --git a/src/common/DownloadManager.hpp b/src/common/DownloadManager.hpp new file mode 100644 index 000000000..ac49a927c --- /dev/null +++ b/src/common/DownloadManager.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "Application.hpp" + +#include +#include +#include +#include +#include +#include + +namespace chatterino { + +class DownloadManager : public QObject +{ + Q_OBJECT +public: + explicit DownloadManager(QObject *parent = 0); + virtual ~DownloadManager(); + void setFile(QString fileURL, const QString &channelName); + +private: + QNetworkAccessManager *manager; + QNetworkReply *reply; + QFile *file; + +private slots: + void onDownloadProgress(qint64, qint64); + void onFinished(QNetworkReply *); + void onReadyRead(); + void onReplyFinished(); + +signals: + void downloadComplete(); +}; +} // namespace chatterino diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 1dc0b9192..9a48d2bbd 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -146,6 +146,8 @@ public: false}; BoolSetting notificationToast = {"/notifications/enableToast", false}; BoolSetting notificationDot = {"/notifications/enableDot", false}; + BoolSetting notificationSplitheaderHighlight = { + "/notifications/enableSplitheaderHighlight", false}; /// External tools // Streamlink diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index bf6542850..c6c1fac96 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -1,6 +1,7 @@ #include "Toasts.hpp" #include "Application.hpp" +#include "common/DownloadManager.hpp" #include "common/NetworkRequest.hpp" #include "controllers/notifications/NotificationController.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -15,7 +16,6 @@ #include #include -//#include #include #include #include @@ -32,15 +32,38 @@ bool Toasts::isEnabled() void Toasts::sendChannelNotification(const QString &channelName, Platform p) { + // Fetch user profile avatar + if (p == Platform::Twitch) { + QFileInfo check_file( + QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + + "2/cache/profileAvatars/twitch/" + channelName + ".png"); + if (check_file.exists() && check_file.isFile()) { #ifdef Q_OS_WIN - - sendWindowsNotification(channelName, p); - return; - + this->sendWindowsNotification(channelName, p); #endif - // OSX + // OSX - // LINUX + // LINUX + + } else { + this->fetchChannelAvatar( + channelName, [this, channelName, p](QString avatarLink) { + DownloadManager *manager = new DownloadManager(); + manager->setFile(avatarLink, channelName); + manager->connect( + manager, &DownloadManager::downloadComplete, + [this, channelName, p]() { +#ifdef Q_OS_WIN + this->sendWindowsNotification(channelName, p); +#endif + // OSX + + // LINUX + }); + }); + } + } + return; } #ifdef Q_OS_WIN @@ -84,29 +107,6 @@ public: }; void Toasts::sendWindowsNotification(const QString &channelName, Platform p) -{ - // Fetch user profile avatar - if (p == Platform::Twitch) { - QFileInfo check_file( - QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + - "2/cache/profileAvatars/twitch/" + channelName + ".png"); - if (check_file.exists() && check_file.isFile()) { - qDebug() << " OMEGA2NAM "; - this->sendActualWindowsNotification(channelName, p); - } else { - qDebug() << " OMEGA1NAM "; - this->fetchChannelAvatar( - channelName, [this, channelName, p](QString avatarLink) { - qDebug() << " OMEGANAM " << avatarLink; - this->sendActualWindowsNotification(channelName, p); - }); - } - } - qDebug() << " YOU'RE TOO SLOW! "; -} - -void Toasts::sendActualWindowsNotification(const QString &channelName, - Platform p) { WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate( WinToastLib::WinToastTemplate::ImageAndText02); @@ -145,51 +145,7 @@ void Toasts::sendActualWindowsNotification(const QString &channelName, } #endif -/* -void Toasts::fetchChannelAvatar(const QString &channelName, - std::function successCallback) -{ - QString requestUrl("https://api.twitch.tv/kraken/users?login=" + - channelName); - NetworkRequest request(requestUrl, NetworkRequestType::Put); - request.setCaller(QThread::currentThread()); - request.makeAuthorizedV5(getDefaultClientID()); - request.setTimeout(30000); - request.onSuccess([successCallback](auto result) -> Outcome { - auto root = result.parseJson(); - if (!root.value("users").isArray()) { - Log("API Error while getting user id, users is not an array"); - successCallback(""); - return Failure; - } - auto users = root.value("users").toArray(); - if (users.size() != 1) { - Log("API Error while getting user id, users array size is not 1"); - successCallback(""); - return Failure; - } - if (!users[0].isObject()) { - Log("API Error while getting user id, first user is not an object"); - successCallback(""); - return Failure; - } - auto firstUser = users[0].toObject(); - auto avatar = firstUser.value("logo"); - if (!avatar.isString()) { - Log("API Error: while getting user logo, first user object `logo` " - "key " - "is not a " - "string"); - successCallback(""); - return Failure; - } - successCallback(avatar.toString()); - return Success; - }); - request.execute(); -} -*/ void Toasts::fetchChannelAvatar(const QString channelName, std::function successCallback) { diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp index c51dd3915..4ffb8d742 100644 --- a/src/singletons/Toasts.hpp +++ b/src/singletons/Toasts.hpp @@ -2,13 +2,7 @@ #include "Application.hpp" #include "common/Singleton.hpp" -/* -#ifdef Q_OS_WIN -#include "wintoastlib.h" - -#endif -*/ namespace chatterino { enum class Platform : uint8_t; @@ -22,7 +16,6 @@ public: private: void sendWindowsNotification(const QString &channelName, Platform p); - void sendActualWindowsNotification(const QString &channelName, Platform p); static void fetchChannelAvatar( const QString channelName, std::function successCallback); diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index 54e342c4a..e856679ff 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -41,6 +41,9 @@ NotificationPage::NotificationPage() settings.append( this->createCheckBox("Red dot next to live splits", getApp()->settings->notificationDot)); + settings.append(this->createCheckBox( + "Change color of Splitheader (click to remove)", + getApp()->settings->notificationSplitheaderHighlight)); settings->addStretch(1); } diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index e97f4faa1..348b3f958 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -549,7 +549,21 @@ void SplitHeader::themeChangedEvent() getApp()->resources->buttons.menuLight); } - this->titleLabel->setPalette(palette); + // this->titleLabel->setPalette(palette); + auto darkPalette = palette; + darkPalette.setColor(QPalette::Window, QColor(53, 53, 53)); + darkPalette.setColor(QPalette::WindowText, Qt::white); + darkPalette.setColor(QPalette::Base, QColor(25, 25, 25)); + darkPalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53)); + darkPalette.setColor(QPalette::ToolTipBase, Qt::white); + darkPalette.setColor(QPalette::ToolTipText, Qt::white); + darkPalette.setColor(QPalette::Text, Qt::white); + darkPalette.setColor(QPalette::Button, QColor(53, 53, 53)); + darkPalette.setColor(QPalette::ButtonText, Qt::white); + darkPalette.setColor(QPalette::BrightText, Qt::red); + darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); + + this->titleLabel->setPalette(darkPalette); } void SplitHeader::menuMoveSplit() From e58e76ef1ecb04c2575f9b507d4cd20589a160c1 Mon Sep 17 00:00:00 2001 From: apa420 Date: Fri, 24 Aug 2018 18:05:36 +0200 Subject: [PATCH 16/29] added more playsound stuff --- .../notifications/NotificationController.cpp | 4 +-- src/singletons/Settings.hpp | 7 ++++-- src/widgets/helper/ChannelView.cpp | 12 +++++++++ .../settingspages/NotificationPage.cpp | 25 ++++++++++++++++--- src/widgets/splits/SplitHeader.cpp | 17 ++----------- 5 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index d07b3a794..5f184bc33 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -81,9 +81,9 @@ void NotificationController::playSound() static QUrl currentPlayerUrl; QUrl highlightSoundUrl; - if (getApp()->settings->customHighlightSound) { + if (getApp()->settings->notificationCustomSound) { highlightSoundUrl = QUrl::fromLocalFile( - getApp()->settings->pathHighlightSound.getValue()); + getApp()->settings->notificationPathSound.getValue()); } else { highlightSoundUrl = QUrl("qrc:/sounds/ping2.wav"); } diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 9a48d2bbd..1105470cb 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -144,10 +144,13 @@ public: false}; BoolSetting notificationPlaySound = {"/notifications/enablePlaySound", false}; + BoolSetting notificationCustomSound = {"/notifications/customPlaySound", + false}; + QStringSetting notificationPathSound = {"/notifications/highlightSoundPath", + "qrc:/sounds/ping3.wav"}; + BoolSetting notificationToast = {"/notifications/enableToast", false}; BoolSetting notificationDot = {"/notifications/enableDot", false}; - BoolSetting notificationSplitheaderHighlight = { - "/notifications/enableSplitheaderHighlight", false}; /// External tools // Streamlink diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 2ea32bb53..448354e13 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -559,6 +559,18 @@ void ChannelView::setChannel(ChannelPtr newChannel) if (tc != nullptr) { tc->tabHighlightRequested.connect([this](HighlightState state) { this->tabHighlightRequested.invoke(HighlightState::Notification); + /* + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.translate(2, 2); + painter.setPen(QColor("#6441A4")); + painter.drawEllipse(QRectF(10, 10, 5, 5)); +*/ + + QPainter painter(this); + auto radius = 10; + painter.setPen(QColor("#6441A4")); + painter.drawEllipse(this->rect().center(), radius, radius); }); } } diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index e856679ff..e5ef7b9f0 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -8,10 +8,12 @@ #include "widgets/helper/EditableModelView.hpp" #include +#include #include #include #include #include +#include #include #include @@ -35,15 +37,32 @@ NotificationPage::NotificationPage() settings.append(this->createCheckBox( "Playsound (doesn't mute the Windows 8.x sound of toasts)", getApp()->settings->notificationPlaySound)); +#ifdef Q_OS_WIN settings.append(this->createCheckBox( "Enable toasts (currently only for windows 8.x or 10)", getApp()->settings->notificationToast)); +#endif settings.append( this->createCheckBox("Red dot next to live splits", getApp()->settings->notificationDot)); - settings.append(this->createCheckBox( - "Change color of Splitheader (click to remove)", - getApp()->settings->notificationSplitheaderHighlight)); + auto customSound = + layout.emplace().withoutMargin(); + { + customSound.append(this->createCheckBox( + "Custom sound", + getApp()->settings->notificationCustomSound)); + auto selectFile = customSound.emplace( + "Select custom sound file"); + QObject::connect( + selectFile.getElement(), &QPushButton::clicked, this, + [this] { + auto fileName = QFileDialog::getOpenFileName( + this, tr("Open Sound"), "", + tr("Audio Files (*.mp3 *.wav)")); + getApp()->settings->notificationPathSound = + fileName; + }); + } settings->addStretch(1); } diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index 348b3f958..aa28bb18c 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -168,6 +168,7 @@ std::unique_ptr SplitHeader::createMainMenu() getApp()->notifications->updateChannelNotification( this->split_->getChannel()->getName(), Platform::Twitch); }); + menu->addAction(action); menu->addSeparator(); @@ -549,21 +550,7 @@ void SplitHeader::themeChangedEvent() getApp()->resources->buttons.menuLight); } - // this->titleLabel->setPalette(palette); - auto darkPalette = palette; - darkPalette.setColor(QPalette::Window, QColor(53, 53, 53)); - darkPalette.setColor(QPalette::WindowText, Qt::white); - darkPalette.setColor(QPalette::Base, QColor(25, 25, 25)); - darkPalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53)); - darkPalette.setColor(QPalette::ToolTipBase, Qt::white); - darkPalette.setColor(QPalette::ToolTipText, Qt::white); - darkPalette.setColor(QPalette::Text, Qt::white); - darkPalette.setColor(QPalette::Button, QColor(53, 53, 53)); - darkPalette.setColor(QPalette::ButtonText, Qt::white); - darkPalette.setColor(QPalette::BrightText, Qt::red); - darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); - - this->titleLabel->setPalette(darkPalette); + this->titleLabel->setPalette(palette); } void SplitHeader::menuMoveSplit() From 8f77dccb91adb68473118170775da0c828b354f0 Mon Sep 17 00:00:00 2001 From: apa420 Date: Fri, 24 Aug 2018 18:38:27 +0200 Subject: [PATCH 17/29] testing emoji because having windows 8 sucks --- src/controllers/notifications/NotificationController.cpp | 3 +-- src/singletons/Toasts.cpp | 7 +++---- src/widgets/splits/SplitHeader.cpp | 3 +++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 5f184bc33..325e92998 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -74,7 +74,6 @@ void NotificationController::removeChannelNotification( } } } -/////////////////////////////////////////////////// void NotificationController::playSound() { static auto player = new QMediaPlayer; @@ -94,7 +93,7 @@ void NotificationController::playSound() } player->play(); } -/////////////////////////////////////////////////// + NotificationModel *NotificationController::createModel(QObject *parent, Platform p) { diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index c6c1fac96..f314a422c 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -68,10 +68,6 @@ void Toasts::sendChannelNotification(const QString &channelName, Platform p) #ifdef Q_OS_WIN -/*const override void CustomToastHandler::toastActivated() -{ -}*/ - class CustomHandler : public WinToastLib::IWinToastHandler { private: @@ -122,6 +118,9 @@ void Toasts::sendWindowsNotification(const QString &channelName, Platform p) Path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "2/cache/profileAvatars/twitch/" + channelName + ".png"; + // Change it to this below v + // Path = getApp()->paths->cacheDirectory() + "profileAvatars/twitch/" + + // channelName + ".png"; } std::string temp_Utf8 = Path.toUtf8().constData(); std::wstring imagePath = std::wstring(temp_Utf8.begin(), temp_Utf8.end()); diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index aa28bb18c..5cc4d85fe 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -383,6 +383,9 @@ void SplitHeader::updateChannelText() } else { title += " (live)"; } + if (getSettings()->notificationDot) { + title += QByteArray(" 🔴 "); + } if (getSettings()->showViewerCount) { title += " - " + QString::number(streamStatus->viewerCount) + " viewers"; From c4679bf048146c8535e5fe3dc37b24dc98c86e11 Mon Sep 17 00:00:00 2001 From: apa420 Date: Sat, 25 Aug 2018 14:13:26 +0200 Subject: [PATCH 18/29] almost implemented the faekchannels, just need to fix the timer, pls help pajlada --- .../notifications/NotificationController.cpp | 99 +++++++++++++++++++ .../notifications/NotificationController.hpp | 9 ++ src/singletons/Settings.hpp | 1 - .../settingspages/NotificationPage.cpp | 3 - src/widgets/splits/SplitHeader.cpp | 3 - 5 files changed, 108 insertions(+), 7 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 325e92998..54a964cfb 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -1,8 +1,12 @@ #include "controllers/notifications/NotificationController.hpp" #include "Application.hpp" +#include "common/NetworkRequest.hpp" #include "controllers/notifications/NotificationModel.hpp" +#include "providers/twitch/TwitchApi.hpp" +#include "providers/twitch/TwitchServer.hpp" #include "singletons/Toasts.hpp" +#include "singletons/WindowManager.hpp" #include @@ -34,6 +38,16 @@ void NotificationController::initialize(Settings &settings, Paths &paths) this->channelMap[Platform::Mixer].getVector()); }); */ + + /* + connect(liveStatusTimer_, SIGNAL(timeout()), this, SLOT()); + liveStatusTimer_.start(60 * 1000); + */ + liveStatusTimer_ = new QTimer(); + QObject::connect(liveStatusTimer_, this, SIGNAL(timeout()), + SLOT(fetchFakeChannels())); + connect(liveStatusTimer_, SIGNAL(timeout()), SLOT(fetchFakeChannels())); + liveStatusTimer_->start(1000); } void NotificationController::updateChannelNotification( @@ -102,4 +116,89 @@ NotificationModel *NotificationController::createModel(QObject *parent, return model; } +void NotificationController::fetchFakeChannels() +{ + for (std::vector::size_type i = 0; + i != channelMap[Platform::Twitch].getVector().size(); i++) { + auto chan = getApp()->twitch.server->getChannelOrEmpty( + channelMap[Platform::Twitch].getVector()[i]); + + /* + auto chan = getApp()->twitch.server->getChannelOrEmpty(chanName); + if (auto *twitchChannel = dynamic_cast(chan.get())) { + if (channelMap[Platform::Twitch].getVector()[i].toLower() == + channelName.toLower()) { channelMap[Platform::Twitch].removeItem(i); + i--; + } + }*/ + } +} + +void NotificationController::getFakeTwitchChannelLiveStatus( + const QString &channelName) +{ + TwitchApi::findUserId(channelName, [channelName, this](QString roomID) { + if (roomID.isEmpty()) { + Log("[TwitchChannel:{}] Refreshing live status (Missing ID)", + channelName); + removeFakeChannel(channelName); + return; + } + Log("[TwitchChannel:{}] Refreshing live status", channelName); + + QString url("https://api.twitch.tv/kraken/streams/" + roomID); + auto request = NetworkRequest::twitchRequest(url); + request.setCaller(QThread::currentThread()); + + request.onSuccess([this, channelName](auto result) -> Outcome { + rapidjson::Document document = result.parseRapidJson(); + if (!document.IsObject()) { + Log("[TwitchChannel:refreshLiveStatus] root is not an object"); + return Failure; + } + + if (!document.HasMember("stream")) { + Log("[TwitchChannel:refreshLiveStatus] Missing stream in root"); + return Failure; + } + + const auto &stream = document["stream"]; + + if (!stream.IsObject()) { + // Stream is offline (stream is most likely null) + removeFakeChannel(channelName); + return Failure; + } + // Stream is live + auto i = std::find(fakeTwitchChannels.begin(), + fakeTwitchChannels.end(), channelName); + if (i != fakeTwitchChannels.end()) { + fakeTwitchChannels.push_back(channelName); + if (Toasts::isEnabled()) { + getApp()->toasts->sendChannelNotification(channelName, + Platform::Twitch); + } + if (getApp()->settings->notificationPlaySound) { + getApp()->notifications->playSound(); + } + if (getApp()->settings->notificationFlashTaskbar) { + QApplication::alert( + getApp()->windows->getMainWindow().window(), 2500); + } + } + }); + + request.execute(); + }); +} + +void NotificationController::removeFakeChannel(const QString channelName) +{ + auto i = std::find(fakeTwitchChannels.begin(), fakeTwitchChannels.end(), + channelName); + if (i != fakeTwitchChannels.end()) { + fakeTwitchChannels.erase(i); + } +} + } // namespace chatterino diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index da5bcd03a..a7cdbaf41 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -3,6 +3,8 @@ #include "common/SignalVector.hpp" #include "singletons/Settings.hpp" +#include + namespace chatterino { class Settings; @@ -35,12 +37,19 @@ public: private: bool initialized_ = false; + QTimer *liveStatusTimer_; + void removeFakeChannel(const QString channelName); + std::vector fakeTwitchChannels; + void getFakeTwitchChannelLiveStatus(const QString &channelName); + ChatterinoSetting> twitchSetting_ = { "/notifications/twitch"}; /* ChatterinoSetting> mixerSetting_ = { "/notifications/mixer"}; */ +private slots: + void fetchFakeChannels(); }; } // namespace chatterino diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 1105470cb..9a286ab33 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -150,7 +150,6 @@ public: "qrc:/sounds/ping3.wav"}; BoolSetting notificationToast = {"/notifications/enableToast", false}; - BoolSetting notificationDot = {"/notifications/enableDot", false}; /// External tools // Streamlink diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index e5ef7b9f0..62b9650e9 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -42,9 +42,6 @@ NotificationPage::NotificationPage() "Enable toasts (currently only for windows 8.x or 10)", getApp()->settings->notificationToast)); #endif - settings.append( - this->createCheckBox("Red dot next to live splits", - getApp()->settings->notificationDot)); auto customSound = layout.emplace().withoutMargin(); { diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index 5cc4d85fe..aa28bb18c 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -383,9 +383,6 @@ void SplitHeader::updateChannelText() } else { title += " (live)"; } - if (getSettings()->notificationDot) { - title += QByteArray(" 🔴 "); - } if (getSettings()->showViewerCount) { title += " - " + QString::number(streamStatus->viewerCount) + " viewers"; From 8ea3b6c8eebf2475d8472ead52220cfb2251ab2a Mon Sep 17 00:00:00 2001 From: apa420 Date: Sun, 26 Aug 2018 13:19:09 +0200 Subject: [PATCH 19/29] Added fakechannels --- .../notifications/NotificationController.cpp | 34 ++++++++----------- .../notifications/NotificationController.hpp | 11 +++--- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 54a964cfb..b35dc4cdc 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -36,18 +36,17 @@ void NotificationController::initialize(Settings &settings, Paths &paths) this->channelMap[Platform::Mixer].delayedItemsChanged.connect([this] { // this->mixerSetting_.setValue( this->channelMap[Platform::Mixer].getVector()); - }); - */ + });*/ - /* - connect(liveStatusTimer_, SIGNAL(timeout()), this, SLOT()); - liveStatusTimer_.start(60 * 1000); - */ liveStatusTimer_ = new QTimer(); - QObject::connect(liveStatusTimer_, this, SIGNAL(timeout()), - SLOT(fetchFakeChannels())); - connect(liveStatusTimer_, SIGNAL(timeout()), SLOT(fetchFakeChannels())); - liveStatusTimer_->start(1000); + + this->fetchFakeChannels(); + + QObject::connect(this->liveStatusTimer_, &QTimer::timeout, [=] { + this->fetchFakeChannels(); + qDebug() << " MY CODE IS SHIT OMEGALUL "; + }); + this->liveStatusTimer_->start(60 * 1000); } void NotificationController::updateChannelNotification( @@ -118,19 +117,15 @@ NotificationModel *NotificationController::createModel(QObject *parent, void NotificationController::fetchFakeChannels() { + qDebug() << " USING DEBUGGER "; for (std::vector::size_type i = 0; i != channelMap[Platform::Twitch].getVector().size(); i++) { auto chan = getApp()->twitch.server->getChannelOrEmpty( channelMap[Platform::Twitch].getVector()[i]); - - /* - auto chan = getApp()->twitch.server->getChannelOrEmpty(chanName); - if (auto *twitchChannel = dynamic_cast(chan.get())) { - if (channelMap[Platform::Twitch].getVector()[i].toLower() == - channelName.toLower()) { channelMap[Platform::Twitch].removeItem(i); - i--; + if (chan->isEmpty()) { + getFakeTwitchChannelLiveStatus( + channelMap[Platform::Twitch].getVector()[i]); } - }*/ } } @@ -172,7 +167,8 @@ void NotificationController::getFakeTwitchChannelLiveStatus( // Stream is live auto i = std::find(fakeTwitchChannels.begin(), fakeTwitchChannels.end(), channelName); - if (i != fakeTwitchChannels.end()) { + + if (!(i != fakeTwitchChannels.end())) { fakeTwitchChannels.push_back(channelName); if (Toasts::isEnabled()) { getApp()->toasts->sendChannelNotification(channelName, diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index a7cdbaf41..77e8d46b1 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -17,7 +17,7 @@ enum class Platform : uint8_t { // Mixer, // 1 }; -class NotificationController final : public Singleton +class NotificationController final : public Singleton, private QObject { public: virtual void initialize(Settings &settings, Paths &paths) override; @@ -37,19 +37,20 @@ public: private: bool initialized_ = false; - QTimer *liveStatusTimer_; + + void fetchFakeChannels(); void removeFakeChannel(const QString channelName); - std::vector fakeTwitchChannels; void getFakeTwitchChannelLiveStatus(const QString &channelName); + std::vector fakeTwitchChannels; + QTimer *liveStatusTimer_; + ChatterinoSetting> twitchSetting_ = { "/notifications/twitch"}; /* ChatterinoSetting> mixerSetting_ = { "/notifications/mixer"}; */ -private slots: - void fetchFakeChannels(); }; } // namespace chatterino From 15bcb5a2fb972f2e0d0b5b0aadc2ae327eaf0967 Mon Sep 17 00:00:00 2001 From: apa420 Date: Sun, 26 Aug 2018 13:49:15 +0200 Subject: [PATCH 20/29] Initially done with PR --- src/common/DownloadManager.cpp | 1 - src/common/DownloadManager.hpp | 2 +- src/singletons/Toasts.cpp | 8 ++------ src/widgets/helper/ChannelView.cpp | 12 ------------ 4 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/common/DownloadManager.cpp b/src/common/DownloadManager.cpp index 41d2aad62..38a987060 100644 --- a/src/common/DownloadManager.cpp +++ b/src/common/DownloadManager.cpp @@ -20,7 +20,6 @@ void DownloadManager::setFile(QString fileURL, const QString &channelName) QString filePath = fileURL; QString saveFilePath; QStringList filePathList = filePath.split('/'); - // QString fileName = filePathList.at(filePathList.count() - 1); saveFilePath = QString( QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "2/cache/profileAvatars/twitch/" + channelName + ".png"); diff --git a/src/common/DownloadManager.hpp b/src/common/DownloadManager.hpp index ac49a927c..a160570c3 100644 --- a/src/common/DownloadManager.hpp +++ b/src/common/DownloadManager.hpp @@ -15,7 +15,7 @@ class DownloadManager : public QObject { Q_OBJECT public: - explicit DownloadManager(QObject *parent = 0); + explicit DownloadManager(QObject *parent = nullptr); virtual ~DownloadManager(); void setFile(QString fileURL, const QString &channelName); diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index f314a422c..58595e56e 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -115,12 +115,8 @@ void Toasts::sendWindowsNotification(const QString &channelName, Platform p) WinToastLib::WinToastTemplate::SecondLine); QString Path; if (p == Platform::Twitch) { - Path = - QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + - "2/cache/profileAvatars/twitch/" + channelName + ".png"; - // Change it to this below v - // Path = getApp()->paths->cacheDirectory() + "profileAvatars/twitch/" + - // channelName + ".png"; + Path = getApp()->paths->cacheDirectory() + "/" + + "profileAvatars/twitch/" + channelName + ".png"; } std::string temp_Utf8 = Path.toUtf8().constData(); std::wstring imagePath = std::wstring(temp_Utf8.begin(), temp_Utf8.end()); diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 448354e13..2ea32bb53 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -559,18 +559,6 @@ void ChannelView::setChannel(ChannelPtr newChannel) if (tc != nullptr) { tc->tabHighlightRequested.connect([this](HighlightState state) { this->tabHighlightRequested.invoke(HighlightState::Notification); - /* - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing, true); - painter.translate(2, 2); - painter.setPen(QColor("#6441A4")); - painter.drawEllipse(QRectF(10, 10, 5, 5)); -*/ - - QPainter painter(this); - auto radius = 10; - painter.setPen(QColor("#6441A4")); - painter.drawEllipse(this->rect().center(), radius, radius); }); } } From df7d256c7f37e62fbea5143742580a6c8fdff841 Mon Sep 17 00:00:00 2001 From: apa420 <17131426+apa420@users.noreply.github.com> Date: Wed, 29 Aug 2018 09:57:10 +0200 Subject: [PATCH 21/29] Update chatterino.pro --- chatterino.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chatterino.pro b/chatterino.pro index 16ba15c6b..e281901d7 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -254,7 +254,7 @@ SOURCES += \ src/util/FunctionEventFilter.cpp \ src/controllers/notifications/NotificationModel.cpp \ src/singletons/Toasts.cpp \ - src/common/DownloadManager.cpp + src/common/DownloadManager.cpp \ src/widgets/helper/EffectLabel.cpp \ src/widgets/helper/Button.cpp \ src/messages/MessageContainer.cpp \ @@ -454,7 +454,7 @@ HEADERS += \ src/util/FunctionEventFilter.hpp \ src/controllers/notifications/NotificationModel.hpp \ src/singletons/Toasts.hpp \ - src/common/DownloadManager.hpp + src/common/DownloadManager.hpp \ src/widgets/helper/EffectLabel.hpp \ src/util/LayoutHelper.hpp \ src/widgets/helper/Button.hpp \ From c5a88f6af373c919571e4cef5bf3e57bd9d920a6 Mon Sep 17 00:00:00 2001 From: apa420 Date: Wed, 29 Aug 2018 19:25:37 +0200 Subject: [PATCH 22/29] fixed stuff --- .../notifications/NotificationController.cpp | 22 +++++++++------- .../notifications/NotificationController.hpp | 1 + src/providers/twitch/TwitchApi.cpp | 1 + src/providers/twitch/TwitchChannel.cpp | 5 ++-- src/providers/twitch/TwitchChannel.hpp | 2 ++ src/singletons/Toasts.cpp | 26 ++++++++++--------- .../settingspages/NotificationPage.cpp | 10 +++---- 7 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index b35dc4cdc..1e8e1b802 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -2,11 +2,14 @@ #include "Application.hpp" #include "common/NetworkRequest.hpp" +#include "common/Outcome.hpp" #include "controllers/notifications/NotificationModel.hpp" +#include "debug/Log.hpp" #include "providers/twitch/TwitchApi.hpp" #include "providers/twitch/TwitchServer.hpp" #include "singletons/Toasts.hpp" #include "singletons/WindowManager.hpp" +#include "widgets/Window.hpp" #include @@ -93,9 +96,9 @@ void NotificationController::playSound() static QUrl currentPlayerUrl; QUrl highlightSoundUrl; - if (getApp()->settings->notificationCustomSound) { + if (getSettings()->notificationCustomSound) { highlightSoundUrl = QUrl::fromLocalFile( - getApp()->settings->notificationPathSound.getValue()); + getSettings()->notificationPathSound.getValue()); } else { highlightSoundUrl = QUrl("qrc:/sounds/ping2.wav"); } @@ -134,12 +137,12 @@ void NotificationController::getFakeTwitchChannelLiveStatus( { TwitchApi::findUserId(channelName, [channelName, this](QString roomID) { if (roomID.isEmpty()) { - Log("[TwitchChannel:{}] Refreshing live status (Missing ID)", + log("[TwitchChannel:{}] Refreshing live status (Missing ID)", channelName); removeFakeChannel(channelName); return; } - Log("[TwitchChannel:{}] Refreshing live status", channelName); + log("[TwitchChannel:{}] Refreshing live status", channelName); QString url("https://api.twitch.tv/kraken/streams/" + roomID); auto request = NetworkRequest::twitchRequest(url); @@ -148,12 +151,12 @@ void NotificationController::getFakeTwitchChannelLiveStatus( request.onSuccess([this, channelName](auto result) -> Outcome { rapidjson::Document document = result.parseRapidJson(); if (!document.IsObject()) { - Log("[TwitchChannel:refreshLiveStatus] root is not an object"); + log("[TwitchChannel:refreshLiveStatus]root is not an object"); return Failure; } if (!document.HasMember("stream")) { - Log("[TwitchChannel:refreshLiveStatus] Missing stream in root"); + log("[TwitchChannel:refreshLiveStatus] Missing stream in root"); return Failure; } @@ -161,7 +164,7 @@ void NotificationController::getFakeTwitchChannelLiveStatus( if (!stream.IsObject()) { // Stream is offline (stream is most likely null) - removeFakeChannel(channelName); + // removeFakeChannel(channelName); return Failure; } // Stream is live @@ -174,14 +177,15 @@ void NotificationController::getFakeTwitchChannelLiveStatus( getApp()->toasts->sendChannelNotification(channelName, Platform::Twitch); } - if (getApp()->settings->notificationPlaySound) { + if (getSettings()->notificationPlaySound) { getApp()->notifications->playSound(); } - if (getApp()->settings->notificationFlashTaskbar) { + if (getSettings()->notificationFlashTaskbar) { QApplication::alert( getApp()->windows->getMainWindow().window(), 2500); } } + return Success; }); request.execute(); diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index 77e8d46b1..228348add 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -1,6 +1,7 @@ #pragma once #include "common/SignalVector.hpp" +#include "common/Singleton.hpp" #include "singletons/Settings.hpp" #include diff --git a/src/providers/twitch/TwitchApi.cpp b/src/providers/twitch/TwitchApi.cpp index 33e982191..eb4ddb0cf 100644 --- a/src/providers/twitch/TwitchApi.cpp +++ b/src/providers/twitch/TwitchApi.cpp @@ -6,6 +6,7 @@ #include "providers/twitch/TwitchCommon.hpp" #include +#include namespace chatterino { diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 674c5831a..b091ea42f 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -18,6 +18,7 @@ #include "singletons/Toasts.hpp" #include "singletons/WindowManager.hpp" #include "util/PostToThread.hpp" +#include "widgets/Window.hpp" #include #include @@ -400,10 +401,10 @@ void TwitchChannel::setLive(bool newLiveStatus) getApp()->toasts->sendChannelNotification(this->getName(), Platform::Twitch); } - if (getApp()->settings->notificationPlaySound) { + if (getSettings()->notificationPlaySound) { getApp()->notifications->playSound(); } - if (getApp()->settings->notificationFlashTaskbar) { + if (getSettings()->notificationFlashTaskbar) { QApplication::alert( getApp()->windows->getMainWindow().window(), 2500); } diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index 208a80e5b..a4a180135 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -19,6 +19,8 @@ namespace chatterino { +enum class HighlightState; + struct Emote; using EmotePtr = std::shared_ptr; class EmoteMap; diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index 58595e56e..6fdd65e68 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -10,7 +10,7 @@ #ifdef Q_OS_WIN -#include +# include #endif @@ -27,7 +27,7 @@ namespace chatterino { bool Toasts::isEnabled() { return WinToastLib::WinToast::isCompatible() && - getApp()->settings->notificationToast; + getSettings()->notificationToast; } void Toasts::sendChannelNotification(const QString &channelName, Platform p) @@ -115,13 +115,13 @@ void Toasts::sendWindowsNotification(const QString &channelName, Platform p) WinToastLib::WinToastTemplate::SecondLine); QString Path; if (p == Platform::Twitch) { - Path = getApp()->paths->cacheDirectory() + "/" + - "profileAvatars/twitch/" + channelName + ".png"; + Path = Path = getPaths()->cacheDirectory() + "/" + + "profileAvatars/twitch/" + channelName + ".png"; } std::string temp_Utf8 = Path.toUtf8().constData(); std::wstring imagePath = std::wstring(temp_Utf8.begin(), temp_Utf8.end()); templ.setImagePath(imagePath); - if (getApp()->settings->notificationPlaySound) { + if (getSettings()->notificationPlaySound) { templ.setAudioOption( WinToastLib::WinToastTemplate::AudioOption::Silent); } @@ -154,28 +154,30 @@ void Toasts::fetchChannelAvatar(const QString channelName, request.onSuccess([successCallback](auto result) mutable -> Outcome { auto root = result.parseJson(); if (!root.value("users").isArray()) { - Log("API Error while getting user id, users is not an array"); + // log("API Error while getting user id, users is not an array"); successCallback(""); return Failure; } auto users = root.value("users").toArray(); if (users.size() != 1) { - Log("API Error while getting user id, users array size is not 1"); + // log("API Error while getting user id, users array size is not + // 1"); successCallback(""); return Failure; } if (!users[0].isObject()) { - Log("API Error while getting user id, first user is not an object"); + // log("API Error while getting user id, first user is not an + // object"); successCallback(""); return Failure; } auto firstUser = users[0].toObject(); auto avatar = firstUser.value("logo"); if (!avatar.isString()) { - Log("API Error: while getting user avatar, first user object " - "`avatar` key " - "is not a " - "string"); + // log("API Error: while getting user avatar, first user object " + // "`avatar` key " + // "is not a " + // "string"); successCallback(""); return Failure; } diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index 62b9650e9..e07b6915c 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -33,21 +33,21 @@ NotificationPage::NotificationPage() settings.emplace("Enable for selected channels"); settings.append(this->createCheckBox( "Flash taskbar", - getApp()->settings->notificationFlashTaskbar)); + getSettings()->notificationFlashTaskbar)); settings.append(this->createCheckBox( "Playsound (doesn't mute the Windows 8.x sound of toasts)", - getApp()->settings->notificationPlaySound)); + getSettings()->notificationPlaySound)); #ifdef Q_OS_WIN settings.append(this->createCheckBox( "Enable toasts (currently only for windows 8.x or 10)", - getApp()->settings->notificationToast)); + getSettings()->notificationToast)); #endif auto customSound = layout.emplace().withoutMargin(); { customSound.append(this->createCheckBox( "Custom sound", - getApp()->settings->notificationCustomSound)); + getSettings()->notificationCustomSound)); auto selectFile = customSound.emplace( "Select custom sound file"); QObject::connect( @@ -56,7 +56,7 @@ NotificationPage::NotificationPage() auto fileName = QFileDialog::getOpenFileName( this, tr("Open Sound"), "", tr("Audio Files (*.mp3 *.wav)")); - getApp()->settings->notificationPathSound = + getSettings()->notificationPathSound = fileName; }); } From 6b3ee6b09c7add1410dc284e2edef86faa0577e3 Mon Sep 17 00:00:00 2001 From: apa420 Date: Wed, 29 Aug 2018 20:01:07 +0200 Subject: [PATCH 23/29] changed dir-name for linux --- dependencies/wintoast.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/wintoast.pri b/dependencies/wintoast.pri index 051d66487..1966436a7 100644 --- a/dependencies/wintoast.pri +++ b/dependencies/wintoast.pri @@ -1,3 +1,3 @@ INCLUDEPATH += $$PWD/../lib/wintoast/src/ SOURCES += \ - $$PWD/../lib/wintoast/src/wintoastlib.cpp + $$PWD/../lib/WinToast/src/wintoastlib.cpp From 01ca055763da79af6aeed40f2c8111f4c8e8feef Mon Sep 17 00:00:00 2001 From: apa420 Date: Wed, 29 Aug 2018 22:22:32 +0200 Subject: [PATCH 24/29] fixed issue where when a channel was going offline it would do a toast if the channel was notified --- .../notifications/NotificationController.cpp | 7 +--- src/providers/twitch/TwitchChannel.cpp | 37 +++++++++++-------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 1e8e1b802..bab44b76b 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -45,10 +45,8 @@ void NotificationController::initialize(Settings &settings, Paths &paths) this->fetchFakeChannels(); - QObject::connect(this->liveStatusTimer_, &QTimer::timeout, [=] { - this->fetchFakeChannels(); - qDebug() << " MY CODE IS SHIT OMEGALUL "; - }); + QObject::connect(this->liveStatusTimer_, &QTimer::timeout, + [=] { this->fetchFakeChannels(); }); this->liveStatusTimer_->start(60 * 1000); } @@ -120,7 +118,6 @@ NotificationModel *NotificationController::createModel(QObject *parent, void NotificationController::fetchFakeChannels() { - qDebug() << " USING DEBUGGER "; for (std::vector::size_type i = 0; i != channelMap[Platform::Twitch].getVector().size(); i++) { auto chan = getApp()->twitch.server->getChannelOrEmpty( diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index b091ea42f..fecaffe0c 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -395,23 +395,30 @@ void TwitchChannel::setLive(bool newLiveStatus) auto guard = this->streamStatus_.access(); if (guard->live != newLiveStatus) { gotNewLiveStatus = true; - if (getApp()->notifications->isChannelNotified(this->getName(), - Platform::Twitch)) { - if (Toasts::isEnabled()) { - getApp()->toasts->sendChannelNotification(this->getName(), - Platform::Twitch); - } - if (getSettings()->notificationPlaySound) { - getApp()->notifications->playSound(); - } - if (getSettings()->notificationFlashTaskbar) { - QApplication::alert( - getApp()->windows->getMainWindow().window(), 2500); + if (newLiveStatus) { + if (getApp()->notifications->isChannelNotified( + this->getName(), Platform::Twitch)) { + if (Toasts::isEnabled()) { + getApp()->toasts->sendChannelNotification( + this->getName(), Platform::Twitch); + } + if (getSettings()->notificationPlaySound) { + getApp()->notifications->playSound(); + } + if (getSettings()->notificationFlashTaskbar) { + QApplication::alert( + getApp()->windows->getMainWindow().window(), 2500); + } } + auto live = makeSystemMessage(this->getName() + " is live"); + this->addMessage(live); + this->tabHighlightRequested.invoke( + HighlightState::Notification); + } else { + auto offline = + makeSystemMessage(this->getName() + " is offline"); + this->addMessage(offline); } - auto live = makeSystemMessage(this->getName() + " is live"); - this->addMessage(live); - this->tabHighlightRequested.invoke(HighlightState::Notification); guard->live = newLiveStatus; } } From 5555c41d7e3385da8407649c085ae33d108e3855 Mon Sep 17 00:00:00 2001 From: apa420 Date: Wed, 29 Aug 2018 23:39:02 +0200 Subject: [PATCH 25/29] fixed toasts for all platforms --- src/common/DownloadManager.cpp | 9 +++++---- src/singletons/Paths.cpp | 2 ++ src/singletons/Paths.hpp | 3 +++ src/singletons/Toasts.cpp | 6 +++--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/common/DownloadManager.cpp b/src/common/DownloadManager.cpp index 38a987060..d19a6fd69 100644 --- a/src/common/DownloadManager.cpp +++ b/src/common/DownloadManager.cpp @@ -1,6 +1,9 @@ #include "DownloadManager.hpp" +#include "singletons/Paths.hpp" + #include +#include namespace chatterino { @@ -20,10 +23,8 @@ void DownloadManager::setFile(QString fileURL, const QString &channelName) QString filePath = fileURL; QString saveFilePath; QStringList filePathList = filePath.split('/'); - saveFilePath = QString( - QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + - "2/cache/profileAvatars/twitch/" + channelName + ".png"); - + saveFilePath = + getPaths()->twitchProfileAvatars + "/twitch/" + channelName + ".png"; QNetworkRequest request; request.setUrl(QUrl(fileURL)); reply = manager->get(request); diff --git a/src/singletons/Paths.cpp b/src/singletons/Paths.cpp index 90a094e76..2fd8cef85 100644 --- a/src/singletons/Paths.cpp +++ b/src/singletons/Paths.cpp @@ -130,6 +130,8 @@ void Paths::initSubDirectories() this->cacheDirectory_ = makePath("Cache"); this->messageLogDirectory = makePath("Logs"); this->miscDirectory = makePath("Misc"); + this->twitchProfileAvatars = makePath("ProfileAvatars"); + QDir().mkdir(this->twitchProfileAvatars + "/twitch"); } Paths *getPaths() diff --git a/src/singletons/Paths.hpp b/src/singletons/Paths.hpp index de67e8065..1df1fc77f 100644 --- a/src/singletons/Paths.hpp +++ b/src/singletons/Paths.hpp @@ -28,6 +28,9 @@ public: // Hash of QCoreApplication::applicationFilePath() QString applicationFilePathHash; + // Profile avatars for twitch /cache/twitch + QString twitchProfileAvatars; + bool createFolder(const QString &folderPath); bool isPortable(); diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index 6fdd65e68..0e840c260 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -105,7 +105,7 @@ public: void Toasts::sendWindowsNotification(const QString &channelName, Platform p) { WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate( - WinToastLib::WinToastTemplate::ImageAndText02); + WinToastLib::WinToastTemplate::ImageAndText03); QString str = channelName + " is live!"; std::string utf8_text = str.toUtf8().constData(); std::wstring widestr = std::wstring(utf8_text.begin(), utf8_text.end()); @@ -115,8 +115,8 @@ void Toasts::sendWindowsNotification(const QString &channelName, Platform p) WinToastLib::WinToastTemplate::SecondLine); QString Path; if (p == Platform::Twitch) { - Path = Path = getPaths()->cacheDirectory() + "/" + - "profileAvatars/twitch/" + channelName + ".png"; + Path = getPaths()->twitchProfileAvatars + "/twitch/" + channelName + + ".png"; } std::string temp_Utf8 = Path.toUtf8().constData(); std::wstring imagePath = std::wstring(temp_Utf8.begin(), temp_Utf8.end()); From 8994307e5182a581171ed55ffd36a6da532d230f Mon Sep 17 00:00:00 2001 From: apa420 Date: Wed, 29 Aug 2018 23:52:13 +0200 Subject: [PATCH 26/29] forgot to remove an include --- src/common/DownloadManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/DownloadManager.cpp b/src/common/DownloadManager.cpp index d19a6fd69..f1f701fbc 100644 --- a/src/common/DownloadManager.cpp +++ b/src/common/DownloadManager.cpp @@ -3,7 +3,6 @@ #include "singletons/Paths.hpp" #include -#include namespace chatterino { From 05d0b20919a2b3dd8cead9f37bbd9633275f7fe3 Mon Sep 17 00:00:00 2001 From: apa420 Date: Fri, 31 Aug 2018 18:18:05 +0200 Subject: [PATCH 27/29] I checked the wrong filepath --- src/singletons/Toasts.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index 0e840c260..af342675f 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -34,9 +34,8 @@ void Toasts::sendChannelNotification(const QString &channelName, Platform p) { // Fetch user profile avatar if (p == Platform::Twitch) { - QFileInfo check_file( - QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + - "2/cache/profileAvatars/twitch/" + channelName + ".png"); + QFileInfo check_file(getPaths()->twitchProfileAvatars + "/twitch/" + + channelName + ".png"); if (check_file.exists() && check_file.isFile()) { #ifdef Q_OS_WIN this->sendWindowsNotification(channelName, p); From ca5bb104db0ce17dbf3aa692e2b7d3c4cc3215a8 Mon Sep 17 00:00:00 2001 From: apa420 Date: Sat, 1 Sep 2018 13:01:54 +0200 Subject: [PATCH 28/29] hopefully it will now compile on linux --- dependencies/wintoast.pri | 8 +++++--- src/controllers/notifications/NotificationController.cpp | 4 +++- src/singletons/Toasts.cpp | 3 +++ src/singletons/Toasts.hpp | 2 ++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/dependencies/wintoast.pri b/dependencies/wintoast.pri index 1966436a7..b8a5ee85c 100644 --- a/dependencies/wintoast.pri +++ b/dependencies/wintoast.pri @@ -1,3 +1,5 @@ -INCLUDEPATH += $$PWD/../lib/wintoast/src/ -SOURCES += \ - $$PWD/../lib/WinToast/src/wintoastlib.cpp +win32 { + INCLUDEPATH += $$PWD/../lib/wintoast/src/ + SOURCES += \ + $$PWD/../lib/WinToast/src/wintoastlib.cpp +} diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index bab44b76b..2b68b130f 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -11,7 +11,9 @@ #include "singletons/WindowManager.hpp" #include "widgets/Window.hpp" -#include +#ifdef Q_OS_WIN +# include +#endif #include #include diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index af342675f..33df8e3b5 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -26,8 +26,11 @@ namespace chatterino { bool Toasts::isEnabled() { +#ifdef Q_OS_WIN return WinToastLib::WinToast::isCompatible() && getSettings()->notificationToast; +#endif + return false; } void Toasts::sendChannelNotification(const QString &channelName, Platform p) diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp index 4ffb8d742..3a245346f 100644 --- a/src/singletons/Toasts.hpp +++ b/src/singletons/Toasts.hpp @@ -15,7 +15,9 @@ public: static bool isEnabled(); private: +#ifdef Q_OS_WIN void sendWindowsNotification(const QString &channelName, Platform p); +#endif static void fetchChannelAvatar( const QString channelName, std::function successCallback); From e89caa9e78c8df4ee80f8b58726ec25ea6ec1180 Mon Sep 17 00:00:00 2001 From: apa420 <17131426+apa420@users.noreply.github.com> Date: Sat, 1 Sep 2018 22:00:53 +0200 Subject: [PATCH 29/29] Update .gitmodules --- .gitmodules | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitmodules b/.gitmodules index 32042876c..478720eb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,3 +20,7 @@ [submodule "lib/qBreakpad"] path = lib/qBreakpad url = https://github.com/jiakuan/qBreakpad.git +[submodule "lib/WinToast"] + path = lib/WinToast + url = https://github.com/mohabouje/WinToast +