From 8fb06718345a61b513a0151f99ea3bc577a6bcbf Mon Sep 17 00:00:00 2001 From: Cranken Date: Mon, 31 Jul 2017 00:37:22 +0200 Subject: [PATCH] Added Highlights (#86) Added Highlights --- chatterino.pro | 2 +- lib/settings | 2 +- resources/resources.qrc | 1 + resources/sounds/ping2.wav | Bin 0 -> 47968 bytes src/messages/message.cpp | 3 +- src/messages/message.hpp | 2 +- src/messages/messagebuilder.cpp | 6 +- src/messages/messagebuilder.hpp | 2 + src/setting.hpp | 10 +++ src/settingsmanager.cpp | 38 +++++++- src/settingsmanager.hpp | 3 + src/settingssnapshot.hpp | 9 ++ src/twitch/twitchmessagebuilder.cpp | 43 +++++++++- src/twitch/twitchmessagebuilder.hpp | 1 + src/widgets/chatwidgetview.cpp | 3 +- src/widgets/settingsdialog.cpp | 129 ++++++++++++++++++++++++++++ src/widgets/settingsdialog.hpp | 3 + 17 files changed, 245 insertions(+), 12 deletions(-) create mode 100644 resources/sounds/ping2.wav diff --git a/chatterino.pro b/chatterino.pro index c9987cfc7..c0626b5cb 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += core gui network +QT += core gui network multimedia CONFIG += communi COMMUNI += core model util CONFIG += c++14 diff --git a/lib/settings b/lib/settings index d3faa9b39..1282c351d 160000 --- a/lib/settings +++ b/lib/settings @@ -1 +1 @@ -Subproject commit d3faa9b3996e0871473b0e2b1821c93a50821f40 +Subproject commit 1282c351db528f9e2f166b2bb1c217c9d67a8bc8 diff --git a/resources/resources.qrc b/resources/resources.qrc index 0195cedce..e1e4f1a76 100644 --- a/resources/resources.qrc +++ b/resources/resources.qrc @@ -31,5 +31,6 @@ images/StatusAnnotations_Blocked_16xLG_color.png images/UserProfile_22x.png images/VSO_Link_blue_16x.png + sounds/ping2.wav diff --git a/resources/sounds/ping2.wav b/resources/sounds/ping2.wav new file mode 100644 index 0000000000000000000000000000000000000000..0a83c0007eba93733ff7a4f8133fcaa20b368d6a GIT binary patch literal 47968 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 literal 0 HcmV?d00001 diff --git a/src/messages/message.cpp b/src/messages/message.cpp index 36ec05263..6b3797c9a 100644 --- a/src/messages/message.cpp +++ b/src/messages/message.cpp @@ -29,9 +29,10 @@ Message::Message(const QString &text) } */ -Message::Message(const QString &text, const std::vector &words) +Message::Message(const QString &text, const std::vector &words, const bool &highlight) : text(text) , words(words) + , highlightTab(highlight) { } diff --git a/src/messages/message.hpp b/src/messages/message.hpp index f6a843f41..1aa708c47 100644 --- a/src/messages/message.hpp +++ b/src/messages/message.hpp @@ -24,7 +24,7 @@ class Message { public: // explicit Message(const QString &text); - explicit Message(const QString &text, const std::vector &words); + explicit Message(const QString &text, const std::vector &words, const bool &highlight); bool getCanHighlightTab() const; const QString &getTimeoutUser() const; diff --git a/src/messages/messagebuilder.cpp b/src/messages/messagebuilder.cpp index 6c2bf89f7..aa1fa95cc 100644 --- a/src/messages/messagebuilder.cpp +++ b/src/messages/messagebuilder.cpp @@ -16,7 +16,7 @@ MessageBuilder::MessageBuilder() SharedMessage MessageBuilder::build() { - return SharedMessage(new Message(this->originalMessage, _words)); + return SharedMessage(new Message(this->originalMessage, _words,highlight)); } void MessageBuilder::appendWord(const Word &word) @@ -31,6 +31,10 @@ void MessageBuilder::appendTimestamp() appendTimestamp(t); } +void MessageBuilder::setHighlight(const bool &value){ + highlight = value; +} + void MessageBuilder::appendTimestamp(time_t time) { char timeStampBuffer[69]; diff --git a/src/messages/messagebuilder.hpp b/src/messages/messagebuilder.hpp index fddd63169..27c01737b 100644 --- a/src/messages/messagebuilder.hpp +++ b/src/messages/messagebuilder.hpp @@ -18,6 +18,7 @@ public: void appendWord(const Word &word); void appendTimestamp(); void appendTimestamp(std::time_t time); + void setHighlight(const bool &value); QString matchLink(const QString &string); QRegularExpression regex; @@ -26,6 +27,7 @@ public: private: std::vector _words; + bool highlight = false; std::chrono::time_point _parseTime; }; diff --git a/src/setting.hpp b/src/setting.hpp index e69bfa1dd..73fc850db 100644 --- a/src/setting.hpp +++ b/src/setting.hpp @@ -43,6 +43,10 @@ public: return _value; } + T &getnonConst() { + return _value; + } + void set(const T &newValue) { if (_value != newValue) { @@ -65,6 +69,12 @@ public: } } + void insertMap(QString id, bool sound, bool task){ + QPair pair(sound,task); + _value.insert(id,pair); + } + + boost::signals2::signal valueChanged; private: diff --git a/src/settingsmanager.cpp b/src/settingsmanager.cpp index 33134ff6f..81cf0b250 100644 --- a/src/settingsmanager.cpp +++ b/src/settingsmanager.cpp @@ -27,9 +27,12 @@ SettingsManager::SettingsManager() , mentionUsersWithAt(_settingsItems, "mentionUsersWithAt", false) , allowCommandsAtEnd(_settingsItems, "allowCommandsAtEnd", false) , enableHighlights(_settingsItems, "enableHighlights", true) + , enableHighlightsSelf(_settingsItems,"enableHighlightsSelf", true) , enableHighlightSound(_settingsItems, "enableHighlightSound", true) , enableHighlightTaskbar(_settingsItems, "enableHighlightTaskbar", true) , customHighlightSound(_settingsItems, "customHighlightSound", false) + , pathHighlightSound(_settingsItems, "pathHighlightSound", "qrc:/sounds/ping2.wav") + , highlightProperties(_settingsItems,"highlightProperties",QMap>()) , enableTwitchEmotes(_settingsItems, "enableTwitchEmotes", true) , enableBttvEmotes(_settingsItems, "enableBttvEmotes", true) , enableFfzEmotes(_settingsItems, "enableFfzEmotes", true) @@ -61,17 +64,44 @@ SettingsManager::SettingsManager() void SettingsManager::save() { for (auto &item : _settingsItems) { - _settings.setValue(item.get().getName(), item.get().getVariant()); + if(item.get().getName() != "highlightProperties"){ + _settings.setValue(item.get().getName(), item.get().getVariant()); + } else { + _settings.beginGroup("Highlights"); + QStringList list = highlightProperties.get().keys(); + list.removeAll(""); + _settings.remove(""); + for (auto string : list){ + _settings.beginGroup(string); + _settings.setValue("highlightSound",highlightProperties.get().value(string).first); + _settings.setValue("highlightTask",highlightProperties.get().value(string).second); + _settings.endGroup(); + } + _settings.endGroup(); + } } } void SettingsManager::load() { for (auto &item : _settingsItems) { - item.get().setVariant(_settings.value(item.get().getName())); + if(item.get().getName() != "highlightProperties"){ + item.get().setVariant(_settings.value(item.get().getName())); + } else { + _settings.beginGroup("Highlights"); + QStringList list = _settings.childGroups(); + qDebug() << list.join(","); + for (auto string : list){ + _settings.beginGroup(string); + highlightProperties.insertMap(string,_settings.value("highlightSound").toBool(),_settings.value("highlightTask").toBool()); + _settings.endGroup(); + } + _settings.endGroup(); + } } } + Word::Type SettingsManager::getWordTypeMask() { return _wordTypeMask; @@ -129,7 +159,11 @@ SettingsSnapshot SettingsManager::createSnapshot() SettingsSnapshot snapshot; for (auto &item : this->_settingsItems) { + if(item.get().getName() != "highlightProperties"){ snapshot.addItem(item, item.get().getVariant()); + } else { + snapshot._mapItems = highlightProperties.get(); + } } return snapshot; diff --git a/src/settingsmanager.hpp b/src/settingsmanager.hpp index 57ad83371..c59564e01 100644 --- a/src/settingsmanager.hpp +++ b/src/settingsmanager.hpp @@ -57,9 +57,12 @@ public: Setting mentionUsersWithAt; Setting allowCommandsAtEnd; Setting enableHighlights; + Setting enableHighlightsSelf; Setting enableHighlightSound; Setting enableHighlightTaskbar; Setting customHighlightSound; + Setting pathHighlightSound; + Setting>> highlightProperties; Setting enableTwitchEmotes; Setting enableBttvEmotes; Setting enableFfzEmotes; diff --git a/src/settingssnapshot.hpp b/src/settingssnapshot.hpp index d17225c74..990352acf 100644 --- a/src/settingssnapshot.hpp +++ b/src/settingssnapshot.hpp @@ -8,6 +8,7 @@ struct SettingsSnapshot { public: SettingsSnapshot() : _items() + , _mapItems() { } @@ -17,6 +18,12 @@ public: std::pair, QVariant>(setting.get(), value)); } + void addMapItem(QString string,QPair pair){ + QMap> map; + _mapItems.insert(string,pair); + } + + void apply() { for (auto &item : _items) { @@ -24,6 +31,8 @@ public: } } + QMap> _mapItems; + private: std::vector, QVariant>> _items; }; diff --git a/src/twitch/twitchmessagebuilder.cpp b/src/twitch/twitchmessagebuilder.cpp index 11fc29990..4d1ed7fea 100644 --- a/src/twitch/twitchmessagebuilder.cpp +++ b/src/twitch/twitchmessagebuilder.cpp @@ -3,8 +3,13 @@ #include "emotemanager.hpp" #include "ircmanager.hpp" #include "resources.hpp" +#include "settingsmanager.hpp" #include "windowmanager.hpp" +#include +#include +#include + using namespace chatterino::messages; namespace chatterino { @@ -48,7 +53,41 @@ SharedMessage TwitchMessageBuilder::parse() this->parseUsername(); // highlights - // TODO: implement this xD + const QString &originalMessage = ircMessage->content(); + this->originalMessage = originalMessage; + SettingsManager &settings = SettingsManager::getInstance(); + static auto player = new QMediaPlayer; + if(settings.customHighlightSound.get()){ + player->setMedia(QUrl(settings.pathHighlightSound.get())); + } else { + player->setMedia(QUrl("qrc:/sounds/ping2.wav")); + } + if(settings.enableHighlights.get() && ircMessage->nick().compare(settings.selectedUser.get(), Qt::CaseInsensitive)){ + if(settings.enableHighlightsSelf.get() && originalMessage.contains(settings.selectedUser.get(), Qt::CaseInsensitive)){ + this->setHighlight(true); + if(settings.enableHighlightSound.get()){ + player->play(); + } + if(settings.enableHighlightTaskbar.get()){ + QApplication::alert(windowManager.getMainWindow().window(),2500); + } + } else { + QStringList lines = settings.highlightProperties.get().keys(); + for(QString string : lines){ + if(originalMessage.contains(string,Qt::CaseInsensitive)){ + this->setHighlight(true); + // Sound + if(settings.highlightProperties.get().value(string).first){ + player->play(); + } + // Taskbar + if(settings.highlightProperties.get().value(string).second){ + QApplication::alert(windowManager.getMainWindow().window(),2500); + } + } + } + } + } // bits QString bits = ""; @@ -85,8 +124,6 @@ SharedMessage TwitchMessageBuilder::parse() // words QColor textColor = ircMessage->isAction() ? this->usernameColor : this->colorScheme.Text; - const QString &originalMessage = ircMessage->content(); - this->originalMessage = originalMessage; QStringList splits = originalMessage.split(' '); long int i = 0; diff --git a/src/twitch/twitchmessagebuilder.hpp b/src/twitch/twitchmessagebuilder.hpp index 64dd5fb65..96efbc812 100644 --- a/src/twitch/twitchmessagebuilder.hpp +++ b/src/twitch/twitchmessagebuilder.hpp @@ -53,6 +53,7 @@ private: std::string roomID; QColor usernameColor; + bool highlight; void parseMessageID(); void parseRoomID(); diff --git a/src/widgets/chatwidgetview.cpp b/src/widgets/chatwidgetview.cpp index b360b4415..0ef5e2053 100644 --- a/src/widgets/chatwidgetview.cpp +++ b/src/widgets/chatwidgetview.cpp @@ -227,8 +227,7 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) // update messages that have been changed if (updateBuffer) { QPainter painter(buffer); - painter.fillRect(buffer->rect(), this->colorScheme.ChatBackground); - + painter.fillRect(buffer->rect(), (messageRef->getMessage()->getCanHighlightTab()) ? this->colorScheme.ChatBackgroundHighlighted : this->colorScheme.ChatBackground); for (messages::WordPart const &wordPart : messageRef->getWordParts()) { // image if (wordPart.getWord().isImage()) { diff --git a/src/widgets/settingsdialog.cpp b/src/widgets/settingsdialog.cpp index 14de56c5c..2459746e7 100644 --- a/src/widgets/settingsdialog.cpp +++ b/src/widgets/settingsdialog.cpp @@ -11,10 +11,12 @@ #include #include #include +#include #include #include #include #include +#include #include namespace chatterino { @@ -106,6 +108,23 @@ void SettingsDialog::addTabs() listWidget->addItem(user.getUserName()); } + if(listWidget->count()){ + int itemIndex = 0; + for(; itemIndex < listWidget->count(); ++itemIndex){ + if(listWidget->item(itemIndex)->text().compare(settings.selectedUser.get(),Qt::CaseInsensitive)){ + ++itemIndex; + break; + } + } + listWidget->setCurrentRow(itemIndex); + } + + QObject::connect(listWidget,&QListWidget::clicked,this,[&,listWidget]{ + if(!listWidget->selectedItems().isEmpty()){ + settings.selectedUser.set(listWidget->currentItem()->text()); + } + }); + vbox->addWidget(listWidget); } @@ -347,6 +366,105 @@ void SettingsDialog::addTabs() // Highlighting vbox = new QVBoxLayout(); + auto highlights = new QListWidget(); + globalHighlights = highlights; + QStringList items = settings.highlightProperties.get().keys(); + highlights->addItems(items); + auto customSound = new QHBoxLayout(); + auto soundForm = new QFormLayout(); + { + vbox->addWidget(createCheckbox("Enable Highlighting", settings.enableHighlights)); + vbox->addWidget(createCheckbox("Highlight messages containing your name", settings.enableHighlightsSelf)); + vbox->addWidget(createCheckbox("Play sound when your name is mentioned", settings.enableHighlightSound)); + vbox->addWidget(createCheckbox("Flash taskbar when your name is mentioned", settings.enableHighlightTaskbar)); + customSound->addWidget(createCheckbox("Custom sound", settings.customHighlightSound)); + auto selectBtn = new QPushButton("Select"); + QObject::connect(selectBtn,&QPushButton::clicked,this,[&settings,this]{ + auto fileName = QFileDialog::getOpenFileName(this, + tr("Open Sound"), "", tr("Image Files (*.mp3 *.wav)")); + settings.pathHighlightSound.set(fileName); + }); + customSound->addWidget(selectBtn); + } + + soundForm->addRow(customSound); + + { + auto hbox = new QHBoxLayout(); + auto addBtn = new QPushButton("Add"); + auto editBtn = new QPushButton("Edit"); + auto delBtn = new QPushButton("Remove"); + + QObject::connect(addBtn,&QPushButton::clicked,this,[highlights,this,&settings]{ + auto show = new QWidget(); + auto box = new QBoxLayout(QBoxLayout::TopToBottom); + + auto edit = new QLineEdit(); + auto add = new QPushButton("Add"); + + auto sound = new QCheckBox("Play sound"); + auto task = new QCheckBox("Flash taskbar"); + + QObject::connect(add,&QPushButton::clicked,this,[=,&settings]{ + if(edit->text().length()){ + highlights->addItem(edit->text()); + settings.highlightProperties.insertMap(edit->text(),sound->isChecked(),task->isChecked()); + show->close(); + } + }); + box->addWidget(edit); + box->addWidget(add); + box->addWidget(sound); + box->addWidget(task); + show->setLayout(box); + show->show(); + }); + QObject::connect(editBtn,&QPushButton::clicked,this,[highlights,this,&settings]{ + if(!highlights->selectedItems().isEmpty()){ + auto show = new QWidget(); + auto box = new QBoxLayout(QBoxLayout::TopToBottom); + + auto edit = new QLineEdit(); + edit->setText(highlights->selectedItems().first()->text()); + auto add = new QPushButton("Apply"); + + auto sound = new QCheckBox("Play sound"); + auto task = new QCheckBox("Flash taskbar"); + + QObject::connect(add,&QPushButton::clicked,this,[=,&settings]{ + if(edit->text().length()){ + settings.highlightProperties.getnonConst().remove(highlights->selectedItems().first()->text()); + delete highlights->selectedItems().first(); + highlights->addItem(edit->text()); + settings.highlightProperties.insertMap(edit->text(),sound->isChecked(),task->isChecked()); + show->close(); + } + }); + box->addWidget(edit); + box->addWidget(add); + box->addWidget(sound); + sound->setChecked(settings.highlightProperties.get().value(highlights->selectedItems().first()->text()).first); + box->addWidget(task); + task->setChecked(settings.highlightProperties.get().value(highlights->selectedItems().first()->text()).second); + show->setLayout(box); + show->show(); + } + }); + QObject::connect(delBtn,&QPushButton::clicked,this,[highlights,&settings]{ + if(!highlights->selectedItems().isEmpty()){ + settings.highlightProperties.getnonConst().remove(highlights->selectedItems().first()->text()); + delete highlights->selectedItems().first(); + } + }); + vbox->addLayout(soundForm); + vbox->addWidget(highlights); + + hbox->addWidget(addBtn); + hbox->addWidget(editBtn); + hbox->addWidget(delBtn); + + vbox->addLayout(hbox); + } vbox->addStretch(1); addTab(vbox, "Highlighting", ":/images/format_Bold_16xLG.png"); @@ -461,7 +579,18 @@ void SettingsDialog::okButtonClicked() void SettingsDialog::cancelButtonClicked() { // TODO: Re-implement the snapshot feature properly + auto &instance = SettingsManager::getInstance(); + this->snapshot.apply(); + instance.highlightProperties.set(this->snapshot._mapItems); + + QStringList list = instance.highlightProperties.get().keys(); + list.removeDuplicates(); + while(globalHighlights->count()>0) + { + delete globalHighlights->takeItem(0); + } + globalHighlights->addItems(list); this->close(); } diff --git a/src/widgets/settingsdialog.hpp b/src/widgets/settingsdialog.hpp index 982d6247c..cb8988610 100644 --- a/src/widgets/settingsdialog.hpp +++ b/src/widgets/settingsdialog.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,8 @@ private: SettingsDialogTab *selectedTab = nullptr; + QListWidget* globalHighlights; + /// Widget creation helpers QCheckBox *createCheckbox(const QString &title, Setting &setting); QCheckBox *createCheckbox(const QString &title, pajlada::Settings::Setting &setting);