From c7b3480aaf92625f2a1654296688f5a431114db0 Mon Sep 17 00:00:00 2001 From: fourtf Date: Sat, 16 Sep 2017 00:05:06 +0200 Subject: [PATCH] ChatWidgetView -> ChannelView, added Emote Picker --- chatterino.pro | 10 +- src/channel.cpp | 63 +------- src/channel.hpp | 38 +---- src/channelmanager.cpp | 44 +++--- src/channelmanager.hpp | 16 +- src/concurrentmap.hpp | 89 +---------- src/emotemanager.cpp | 34 +++-- src/emotemanager.hpp | 10 +- src/ircmanager.cpp | 4 +- src/messages/message.hpp | 3 +- src/messages/messagebuilder.cpp | 2 +- src/messages/messagebuilder.hpp | 2 +- src/messages/messageref.cpp | 20 ++- src/messages/messageref.hpp | 2 +- src/messages/word.hpp | 4 +- src/settingsmanager.cpp | 2 + src/twitch/twitchchannel.cpp | 80 ++++++++++ src/twitch/twitchchannel.hpp | 49 ++++++ src/twitch/twitchmessagebuilder.cpp | 14 +- src/twitch/twitchmessagebuilder.hpp | 4 +- .../{chatwidgetview.cpp => channelview.cpp} | 141 ++++++++++++++---- .../{chatwidgetview.hpp => channelview.hpp} | 34 +++-- src/widgets/chatwidget.cpp | 91 +++-------- src/widgets/chatwidget.hpp | 16 +- src/widgets/chatwidgetheader.cpp | 37 +++-- src/widgets/chatwidgetheaderbutton.cpp | 10 +- src/widgets/chatwidgetheaderbutton.hpp | 2 +- src/widgets/chatwidgetinput.cpp | 9 +- src/widgets/chatwidgetinput.hpp | 4 +- src/widgets/emotepopup.cpp | 64 +++++++- src/widgets/emotepopup.h | 13 +- src/widgets/fancybutton.cpp | 2 +- src/widgets/notebook.cpp | 4 +- src/widgets/scrollbar.cpp | 4 +- src/widgets/scrollbar.hpp | 4 +- src/windowmanager.cpp | 12 +- src/windowmanager.hpp | 2 +- 37 files changed, 532 insertions(+), 407 deletions(-) create mode 100644 src/twitch/twitchchannel.cpp create mode 100644 src/twitch/twitchchannel.hpp rename src/widgets/{chatwidgetview.cpp => channelview.cpp} (83%) rename src/widgets/{chatwidgetview.hpp => channelview.hpp} (83%) diff --git a/chatterino.pro b/chatterino.pro index 9135bcb5f..76d236146 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -62,7 +62,6 @@ SOURCES += \ src/widgets/chatwidgetheader.cpp \ src/widgets/chatwidgetheaderbutton.cpp \ src/widgets/chatwidgetinput.cpp \ - src/widgets/chatwidgetview.cpp \ src/widgets/mainwindow.cpp \ src/widgets/notebook.cpp \ src/widgets/notebookbutton.cpp \ @@ -97,7 +96,9 @@ SOURCES += \ src/completionmanager.cpp \ src/widgets/logindialog.cpp \ src/widgets/qualitypopup.cpp \ - src/widgets/emotepopup.cpp + src/widgets/emotepopup.cpp \ + src/widgets/channelview.cpp \ + src/twitch/twitchchannel.cpp HEADERS += \ src/asyncexec.hpp \ @@ -118,7 +119,6 @@ HEADERS += \ src/widgets/chatwidgetheader.hpp \ src/widgets/chatwidgetheaderbutton.hpp \ src/widgets/chatwidgetinput.hpp \ - src/widgets/chatwidgetview.hpp \ src/widgets/mainwindow.hpp \ src/widgets/notebook.hpp \ src/widgets/notebookbutton.hpp \ @@ -159,7 +159,9 @@ HEADERS += \ src/widgets/basewidget.hpp \ src/completionmanager.hpp \ src/widgets/qualitypopup.h \ - src/widgets/emotepopup.h + src/widgets/emotepopup.h \ + src/widgets/channelview.hpp \ + src/twitch/twitchchannel.hpp PRECOMPILED_HEADER = diff --git a/src/channel.cpp b/src/channel.cpp index af979c6a4..8b9361500 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -18,55 +18,14 @@ using namespace chatterino::messages; namespace chatterino { -Channel::Channel(WindowManager &_windowManager, EmoteManager &_emoteManager, - IrcManager &_ircManager, const QString &channelName, bool isSpecial) - : windowManager(_windowManager) - , emoteManager(_emoteManager) - , ircManager(_ircManager) - , name(channelName) - , bttvChannelEmotes(this->emoteManager.bttvChannels[channelName]) - , ffzChannelEmotes(this->emoteManager.ffzChannels[channelName]) - , _subLink("https://www.twitch.tv/" + name + "/subscribe?ref=in_chat_subscriber_link") - , _channelLink("https://twitch.tv/" + name) - , _popoutPlayerLink("https://player.twitch.tv/?channel=" + name) - , isLive(false) +Channel::Channel() // , _loggingChannel(logging::get(_name)) { - qDebug() << "Open channel:" << this->name; - - if (!isSpecial) { - this->reloadChannelEmotes(); - } } -// -// properties -// - bool Channel::isEmpty() const { - return name.isEmpty(); -} - -const QString &Channel::getSubLink() const -{ - return _subLink; -} - -const QString &Channel::getChannelLink() const -{ - return _channelLink; -} - -const QString &Channel::getPopoutPlayerLink() const -{ - return _popoutPlayerLink; -} - -void Channel::setRoomID(std::string id) -{ - this->roomID = id; - this->roomIDchanged(); + return false; } messages::LimitedQueueSnapshot Channel::getMessageSnapshot() @@ -74,9 +33,6 @@ messages::LimitedQueueSnapshot Channel::getMessageSnaps return _messages.getSnapshot(); } -// -// methods -// void Channel::addMessage(std::shared_ptr message) { std::shared_ptr deleted; @@ -90,26 +46,15 @@ void Channel::addMessage(std::shared_ptr message) } this->messageAppended(message); - - this->windowManager.repaintVisibleChatWidgets(this); } -// private methods -void Channel::reloadChannelEmotes() +bool Channel::canSendMessage() const { - printf("[Channel:%s] Reloading channel emotes\n", qPrintable(this->name)); - this->emoteManager.reloadBTTVChannelEmotes(this->name); - this->emoteManager.reloadFFZChannelEmotes(this->name); + return false; } void Channel::sendMessage(const QString &message) { - qDebug() << "Channel send message: " << message; - - // Do last message processing - QString parsedMessage = this->emoteManager.replaceShortCodes(message); - - this->ircManager.sendMessage(name, parsedMessage); } } // namespace chatterino diff --git a/src/channel.hpp b/src/channel.hpp index 5d4c8cbce..ae7e93605 100644 --- a/src/channel.hpp +++ b/src/channel.hpp @@ -19,58 +19,30 @@ namespace messages { class Message; } -class WindowManager; class IrcManager; class Channel { - WindowManager &windowManager; - EmoteManager &emoteManager; - IrcManager &ircManager; - public: - explicit Channel(WindowManager &_windowManager, EmoteManager &_emoteManager, - IrcManager &_ircManager, const QString &channelName, bool isSpecial = false); + explicit Channel(); boost::signals2::signal messageRemovedFromStart; boost::signals2::signal messageAppended; - bool isEmpty() const; - const QString &getSubLink() const; - const QString &getChannelLink() const; - const QString &getPopoutPlayerLink() const; + virtual bool isEmpty() const; messages::LimitedQueueSnapshot getMessageSnapshot(); // methods void addMessage(messages::SharedMessage message); - void reloadChannelEmotes(); + QString name; - void sendMessage(const QString &message); - - std::string roomID; - const QString name; - bool isLive; - QString streamViewerCount; - QString streamStatus; - QString streamGame; - QString streamUptime; - - void setRoomID(std::string id); - boost::signals2::signal roomIDchanged; + virtual bool canSendMessage() const; + virtual void sendMessage(const QString &message); private: // variables messages::LimitedQueue _messages; -public: - const EmoteManager::EmoteMap &bttvChannelEmotes; - const EmoteManager::EmoteMap &ffzChannelEmotes; - -private: - QString _subLink; - QString _channelLink; - QString _popoutPlayerLink; - // std::shared_ptr _loggingChannel; }; diff --git a/src/channelmanager.cpp b/src/channelmanager.cpp index 8b16649ee..5ddc9d340 100644 --- a/src/channelmanager.cpp +++ b/src/channelmanager.cpp @@ -1,6 +1,8 @@ #include "channelmanager.hpp" #include "ircmanager.hpp" +using namespace chatterino::twitch; + namespace chatterino { ChannelManager::ChannelManager(WindowManager &_windowManager, EmoteManager &_emoteManager, @@ -8,9 +10,9 @@ ChannelManager::ChannelManager(WindowManager &_windowManager, EmoteManager &_emo : windowManager(_windowManager) , emoteManager(_emoteManager) , ircManager(_ircManager) - , whispersChannel(new Channel(_windowManager, _emoteManager, _ircManager, "/whispers", true)) - , mentionsChannel(new Channel(_windowManager, _emoteManager, _ircManager, "/mentions", true)) - , emptyChannel(new Channel(_windowManager, _emoteManager, _ircManager, "", true)) + , whispersChannel(new TwitchChannel(_emoteManager, _ircManager, "/whispers", true)) + , mentionsChannel(new TwitchChannel(_emoteManager, _ircManager, "/mentions", true)) + , emptyChannel(new TwitchChannel(_emoteManager, _ircManager, "", true)) { } @@ -20,19 +22,19 @@ const std::vector> ChannelManager::getItems() std::vector> items; - for (auto &item : this->channels.values()) { + for (auto &item : this->twitchChannels.values()) { items.push_back(std::get<0>(item)); } return items; } -std::shared_ptr ChannelManager::addChannel(const QString &rawChannelName) +std::shared_ptr ChannelManager::addTwitchChannel(const QString &rawChannelName) { QString channelName = rawChannelName.toLower(); if (channelName.length() > 1 && channelName.at(0) == '/') { - return this->getChannel(channelName); + return this->getTwitchChannel(channelName); } if (channelName.length() > 0 && channelName.at(0) == '#') { @@ -41,12 +43,13 @@ std::shared_ptr ChannelManager::addChannel(const QString &rawChannelNam QMutexLocker locker(&this->channelsMutex); - auto it = this->channels.find(channelName); + auto it = this->twitchChannels.find(channelName); - if (it == this->channels.end()) { - auto channel = std::make_shared(this->windowManager, this->emoteManager, - this->ircManager, channelName); - this->channels.insert(channelName, std::make_tuple(channel, 1)); + if (it == this->twitchChannels.end()) { + auto channel = + std::make_shared(this->emoteManager, this->ircManager, channelName); + + this->twitchChannels.insert(channelName, std::make_tuple(channel, 1)); this->ircManager.joinChannel(channelName); @@ -58,7 +61,7 @@ std::shared_ptr ChannelManager::addChannel(const QString &rawChannelNam return std::get<0>(it.value()); } -std::shared_ptr ChannelManager::getChannel(const QString &channel) +std::shared_ptr ChannelManager::getTwitchChannel(const QString &channel) { QMutexLocker locker(&this->channelsMutex); @@ -76,16 +79,16 @@ std::shared_ptr ChannelManager::getChannel(const QString &channel) return emptyChannel; } - auto a = this->channels.find(c); + auto a = this->twitchChannels.find(c); - if (a == this->channels.end()) { + if (a == this->twitchChannels.end()) { return emptyChannel; } return std::get<0>(a.value()); } -void ChannelManager::removeChannel(const QString &channel) +void ChannelManager::removeTwitchChannel(const QString &channel) { QMutexLocker locker(&this->channelsMutex); @@ -95,9 +98,9 @@ void ChannelManager::removeChannel(const QString &channel) QString c = channel.toLower(); - auto a = this->channels.find(c); + auto a = this->twitchChannels.find(c); - if (a == this->channels.end()) { + if (a == this->twitchChannels.end()) { return; } @@ -105,7 +108,7 @@ void ChannelManager::removeChannel(const QString &channel) if (std::get<1>(a.value()) == 0) { this->ircManager.partChannel(c); - this->channels.remove(c); + this->twitchChannels.remove(c); } } @@ -123,4 +126,9 @@ const std::string &ChannelManager::getUserID(const std::string &username) return temporary; } +EmoteManager &ChannelManager::getEmoteManager() +{ + return this->emoteManager; +} + } // namespace chatterino diff --git a/src/channelmanager.hpp b/src/channelmanager.hpp index 28c595dd1..c8269b1b4 100644 --- a/src/channelmanager.hpp +++ b/src/channelmanager.hpp @@ -2,6 +2,7 @@ #include "channel.hpp" #include "channeldata.hpp" +#include "twitch/twitchchannel.hpp" #include @@ -23,23 +24,24 @@ public: const std::vector> getItems(); - std::shared_ptr addChannel(const QString &channel); - std::shared_ptr getChannel(const QString &channel); - void removeChannel(const QString &channel); + std::shared_ptr addTwitchChannel(const QString &channel); + std::shared_ptr getTwitchChannel(const QString &channel); + void removeTwitchChannel(const QString &channel); const std::string &getUserID(const std::string &username); + EmoteManager &getEmoteManager(); // Special channels - const std::shared_ptr whispersChannel; - const std::shared_ptr mentionsChannel; - const std::shared_ptr emptyChannel; + const std::shared_ptr whispersChannel; + const std::shared_ptr mentionsChannel; + const std::shared_ptr emptyChannel; private: std::map usernameToID; std::map channelDatas; QMutex channelsMutex; - QMap, int>> channels; + QMap, int>> twitchChannels; }; } // namespace chatterino diff --git a/src/concurrentmap.hpp b/src/concurrentmap.hpp index 0a60204fd..0b4ba6112 100644 --- a/src/concurrentmap.hpp +++ b/src/concurrentmap.hpp @@ -20,7 +20,7 @@ public: bool tryGet(const TKey &name, TValue &value) const { - QMutexLocker lock(this->mutex.get()); + QMutexLocker lock(&this->mutex); auto a = this->data.find(name); if (a == this->data.end()) { @@ -34,7 +34,7 @@ public: TValue getOrAdd(const TKey &name, std::function addLambda) { - QMutexLocker lock(this->mutex.get()); + QMutexLocker lock(&this->mutex); auto a = this->data.find(name); if (a == this->data.end()) { @@ -48,42 +48,28 @@ public: TValue &operator[](const TKey &name) { - QMutexLocker lock(this->mutex.get()); + QMutexLocker lock(&this->mutex); return this->data[name]; } - ConcurrentMap(const ConcurrentMap &o) - : mutex(std::move(o.mutex)) - , data(std::move(o.data)) - { - } - - ConcurrentMap &operator=(const ConcurrentMap &rhs) - { - this->mutex = std::move(rhs.mutex); - this->data = std::move(rhs.data); - - return *this; - } - void clear() { - QMutexLocker lock(this->mutex.get()); + QMutexLocker lock(&this->mutex); this->data.clear(); } void insert(const TKey &name, const TValue &value) { - QMutexLocker lock(this->mutex.get()); + QMutexLocker lock(&this->mutex); this->data.insert(name, value); } - void each(std::function &func) const + void each(std::function func) const { - QMutexLocker lock(this->mutex.get()); + QMutexLocker lock(&this->mutex); QMapIterator it(this->data); @@ -94,66 +80,7 @@ public: } private: - mutable std::unique_ptr mutex; + mutable QMutex mutex; QMap data; }; - -template -class ConcurrentStdMap -{ -public: - bool tryGet(const TKey &name, TValue &value) const - { - QMutexLocker lock(&_mutex); - - auto a = _map.find(name); - if (a == _map.end()) { - return false; - } - - value = a.value(); - - return true; - } - - TValue getOrAdd(const TKey &name, std::function addLambda) - { - QMutexLocker lock(&_mutex); - - auto a = _map.find(name); - if (a == _map.end()) { - TValue value = addLambda(); - _map.insert(name, value); - return value; - } - - return a.value(); - } - - TValue &operator[](const TKey &name) - { - QMutexLocker lock(&_mutex); - - return this->_map[name]; - } - - void clear() - { - QMutexLocker lock(&_mutex); - - _map.clear(); - } - - void insert(const TKey &name, const TValue &value) - { - QMutexLocker lock(&_mutex); - - _map.insert(name, value); - } - -private: - mutable QMutex _mutex; - std::map _map; -}; - } // namespace chatterino diff --git a/src/emotemanager.cpp b/src/emotemanager.cpp index 2d57b9ecd..f909c2229 100644 --- a/src/emotemanager.cpp +++ b/src/emotemanager.cpp @@ -39,15 +39,19 @@ void EmoteManager::loadGlobalEmotes() this->loadFFZEmotes(); } -void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName) +void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName, std::weak_ptr _map) { printf("[EmoteManager] Reload BTTV Channel Emotes for channel %s\n", qPrintable(channelName)); QString url("https://api.betterttv.net/2/channels/" + channelName); - util::urlFetchJSON(url, [this, channelName](QJsonObject &rootNode) { - EmoteMap &channelEmoteMap = this->bttvChannels[channelName]; + util::urlFetchJSON(url, [this, channelName, _map](QJsonObject &rootNode) { + auto map = _map.lock(); - channelEmoteMap.clear(); + if (_map.expired()) { + return; + } + + map->clear(); auto emotesNode = rootNode.value("emotes").toArray(); @@ -72,7 +76,7 @@ void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName) }); this->bttvChannelEmotes.insert(code, emote); - channelEmoteMap.insert(code, emote); + map->insert(code, emote); codes.push_back(code.toStdString()); } @@ -80,16 +84,20 @@ void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName) }); } -void EmoteManager::reloadFFZChannelEmotes(const QString &channelName) +void EmoteManager::reloadFFZChannelEmotes(const QString &channelName, std::weak_ptr _map) { printf("[EmoteManager] Reload FFZ Channel Emotes for channel %s\n", qPrintable(channelName)); QString url("http://api.frankerfacez.com/v1/room/" + channelName); - util::urlFetchJSON(url, [this, channelName](QJsonObject &rootNode) { - EmoteMap &channelEmoteMap = this->ffzChannels[channelName]; + util::urlFetchJSON(url, [this, channelName, _map](QJsonObject &rootNode) { + auto map = _map.lock(); - channelEmoteMap.clear(); + if (_map.expired()) { + return; + } + + map->clear(); auto setsNode = rootNode.value("sets").toObject(); @@ -114,7 +122,7 @@ void EmoteManager::reloadFFZChannelEmotes(const QString &channelName) }); this->ffzChannelEmotes.insert(code, emote); - channelEmoteMap.insert(code, emote); + map->insert(code, emote); codes.push_back(code.toStdString()); } @@ -128,17 +136,17 @@ ConcurrentMap &EmoteManager::getTwitchEmotes() return _twitchEmotes; } -EmoteManager::EmoteMap &EmoteManager::getFFZEmotes() +EmoteMap &EmoteManager::getFFZEmotes() { return ffzGlobalEmotes; } -EmoteManager::EmoteMap &EmoteManager::getChatterinoEmotes() +EmoteMap &EmoteManager::getChatterinoEmotes() { return _chatterinoEmotes; } -EmoteManager::EmoteMap &EmoteManager::getBTTVChannelEmoteFromCaches() +EmoteMap &EmoteManager::getBTTVChannelEmoteFromCaches() { return _bttvChannelEmoteFromCaches; } diff --git a/src/emotemanager.hpp b/src/emotemanager.hpp index ce135fe62..36281eba7 100644 --- a/src/emotemanager.hpp +++ b/src/emotemanager.hpp @@ -32,17 +32,19 @@ struct EmoteData { messages::LazyLoadedImage *image = nullptr; }; +typedef ConcurrentMap EmoteMap; + class EmoteManager { public: - using EmoteMap = ConcurrentMap; - explicit EmoteManager(WindowManager &_windowManager); void loadGlobalEmotes(); - void reloadBTTVChannelEmotes(const QString &channelName); - void reloadFFZChannelEmotes(const QString &channelName); + void reloadBTTVChannelEmotes(const QString &channelName, + std::weak_ptr channelEmoteMap); + void reloadFFZChannelEmotes(const QString &channelName, + std::weak_ptr channelEmoteMap); ConcurrentMap &getTwitchEmotes(); EmoteMap &getFFZEmotes(); diff --git a/src/ircmanager.cpp b/src/ircmanager.cpp index ca2d1a972..8d2d2f4c5 100644 --- a/src/ircmanager.cpp +++ b/src/ircmanager.cpp @@ -237,7 +237,7 @@ void IrcManager::partChannel(const QString &channelName) void IrcManager::privateMessageReceived(Communi::IrcPrivateMessage *message) { this->onPrivateMessage.invoke(message); - auto c = this->channelManager.getChannel(message->target().mid(1)); + auto c = this->channelManager.getTwitchChannel(message->target().mid(1)); if (!c) { return; @@ -283,7 +283,7 @@ void IrcManager::handleRoomStateMessage(Communi::IrcMessage *message) std::string roomID = iterator.value().toString().toStdString(); auto channel = QString(message->toData()).split("#").at(1); - channelManager.getChannel(channel)->setRoomID(roomID); + channelManager.getTwitchChannel(channel)->setRoomID(roomID); this->resources.loadChannelData(roomID); } diff --git a/src/messages/message.hpp b/src/messages/message.hpp index 8eb56d1fd..2646d691a 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; @@ -39,6 +39,7 @@ public: const QString &getId() const; const QString text; + bool centered = false; private: static LazyLoadedImage *badgeStaff; diff --git a/src/messages/messagebuilder.cpp b/src/messages/messagebuilder.cpp index 2a44ae94e..ebc98746f 100644 --- a/src/messages/messagebuilder.cpp +++ b/src/messages/messagebuilder.cpp @@ -12,7 +12,7 @@ MessageBuilder::MessageBuilder() _parseTime = std::chrono::system_clock::now(); } -SharedMessage MessageBuilder::build() +SharedMessage MessageBuilder::getMessage() { return this->message; } diff --git a/src/messages/messagebuilder.hpp b/src/messages/messagebuilder.hpp index f5f236672..a67f7ae40 100644 --- a/src/messages/messagebuilder.hpp +++ b/src/messages/messagebuilder.hpp @@ -14,7 +14,7 @@ class MessageBuilder public: MessageBuilder(); - SharedMessage build(); + SharedMessage getMessage(); void appendWord(const Word &&word); void appendTimestamp(); diff --git a/src/messages/messageref.cpp b/src/messages/messageref.cpp index 6334e3b9c..f75d72a3e 100644 --- a/src/messages/messageref.cpp +++ b/src/messages/messageref.cpp @@ -129,7 +129,7 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) // word wrapping if (word.isText() && word.getWidth() + MARGIN_LEFT > right) { - alignWordParts(lineStart, lineHeight); + alignWordParts(lineStart, lineHeight, width); y += lineHeight; @@ -183,7 +183,7 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) first = false; } else { // doesn't fit in the line - alignWordParts(lineStart, lineHeight); + alignWordParts(lineStart, lineHeight, width); y += lineHeight; @@ -201,7 +201,7 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) } } - alignWordParts(lineStart, lineHeight); + alignWordParts(lineStart, lineHeight, width); if (_height != y + lineHeight) { sizeChanged = true; @@ -224,12 +224,18 @@ const std::vector &MessageRef::getWordParts() const return _wordParts; } -void MessageRef::alignWordParts(int lineStart, int lineHeight) +void MessageRef::alignWordParts(int lineStart, int lineHeight, int width) { - for (size_t i = lineStart; i < _wordParts.size(); i++) { - WordPart &wordPart2 = _wordParts.at(i); + int xOffset = 0; - wordPart2.setY(wordPart2.getY() + lineHeight); + if (this->_message->centered && _wordParts.size() > 0) { + xOffset = (width - this->_wordParts.at(_wordParts.size() - 1).getRight()) / 2; + } + + for (size_t i = lineStart; i < this->_wordParts.size(); i++) { + WordPart &wordPart2 = this->_wordParts.at(i); + + wordPart2.setPosition(wordPart2.getX() + xOffset, wordPart2.getY() + lineHeight); } } diff --git a/src/messages/messageref.hpp b/src/messages/messageref.hpp index c5cfb33a4..1fcb19655 100644 --- a/src/messages/messageref.hpp +++ b/src/messages/messageref.hpp @@ -47,7 +47,7 @@ private: Word::Type _currentWordTypes = Word::None; // methods - void alignWordParts(int lineStart, int lineHeight); + void alignWordParts(int lineStart, int lineHeight, int width); }; } // namespace messages diff --git a/src/messages/word.hpp b/src/messages/word.hpp index 889c6bbb5..00416ba89 100644 --- a/src/messages/word.hpp +++ b/src/messages/word.hpp @@ -77,9 +77,11 @@ public: EmojiImage = (1 << 23), EmojiText = (1 << 24), + AlwaysShow = (1 << 25), + Default = TimestampNoSeconds | Badges | Username | BitsStatic | FfzEmoteImage | BttvEmoteImage | BttvGifEmoteImage | TwitchEmoteImage | BitsAmount | Text | - ButtonBan | ButtonTimeout + ButtonBan | ButtonTimeout | AlwaysShow }; Word() diff --git a/src/settingsmanager.cpp b/src/settingsmanager.cpp index f3a42f194..2b22ab016 100644 --- a/src/settingsmanager.cpp +++ b/src/settingsmanager.cpp @@ -146,6 +146,8 @@ void SettingsManager::updateWordTypeMask() newMaskUint |= Word::Username; + newMaskUint |= Word::AlwaysShow; + Word::Type newMask = static_cast(newMaskUint); if (newMask != _wordTypeMask) { diff --git a/src/twitch/twitchchannel.cpp b/src/twitch/twitchchannel.cpp new file mode 100644 index 000000000..bf3ee193f --- /dev/null +++ b/src/twitch/twitchchannel.cpp @@ -0,0 +1,80 @@ +#include "twitchchannel.hpp" +#include "emotemanager.hpp" + +#include + +namespace chatterino { +namespace twitch { + +TwitchChannel::TwitchChannel(EmoteManager &emoteManager, IrcManager &ircManager, + const QString &channelName, bool isSpecial) + : emoteManager(emoteManager) + , ircManager(ircManager) + // , name(channelName) + , bttvChannelEmotes(new EmoteMap) + , ffzChannelEmotes(new EmoteMap) + , subLink("https://www.twitch.tv/" + name + "/subscribe?ref=in_chat_subscriber_link") + , channelLink("https://twitch.tv/" + name) + , popoutPlayerLink("https://player.twitch.tv/?channel=" + name) + , isLive(false) + , isSpecial(isSpecial) +{ + this->name = channelName; + + qDebug() << "Open twitch channel:" << this->name; + + if (!isSpecial) { + this->reloadChannelEmotes(); + } +} + +bool TwitchChannel::isEmpty() const +{ + return this->name.isEmpty(); +} + +const QString &TwitchChannel::getSubLink() const +{ + return this->subLink; +} + +bool TwitchChannel::canSendMessage() const +{ + return !this->isEmpty() && !this->isSpecial; +} + +const QString &TwitchChannel::getChannelLink() const +{ + return this->channelLink; +} + +const QString &TwitchChannel::getPopoutPlayerLink() const +{ + return this->popoutPlayerLink; +} + +void TwitchChannel::setRoomID(std::string id) +{ + this->roomID = id; + this->roomIDchanged(); +} + +void TwitchChannel::reloadChannelEmotes() +{ + printf("[TwitchChannel:%s] Reloading channel emotes\n", qPrintable(this->name)); + + this->emoteManager.reloadBTTVChannelEmotes(this->name, this->bttvChannelEmotes); + this->emoteManager.reloadFFZChannelEmotes(this->name, this->ffzChannelEmotes); +} + +void TwitchChannel::sendMessage(const QString &message) +{ + qDebug() << "TwitchChannel send message: " << message; + + // Do last message processing + QString parsedMessage = this->emoteManager.replaceShortCodes(message); + + this->ircManager.sendMessage(this->name, parsedMessage); +} +} +} diff --git a/src/twitch/twitchchannel.hpp b/src/twitch/twitchchannel.hpp new file mode 100644 index 000000000..2e87d7d07 --- /dev/null +++ b/src/twitch/twitchchannel.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "channel.hpp" +#include "concurrentmap.hpp" +#include "ircmanager.hpp" + +namespace chatterino { +namespace twitch { + +class TwitchChannel : public Channel +{ +public: + explicit TwitchChannel(EmoteManager &emoteManager, IrcManager &ircManager, + const QString &channelName, bool isSpecial = false); + + void reloadChannelEmotes(); + + bool isEmpty() const override; + bool canSendMessage() const override; + void sendMessage(const QString &message) override; + + const QString &getSubLink() const; + const QString &getChannelLink() const; + const QString &getPopoutPlayerLink() const; + + void setRoomID(std::string id); + boost::signals2::signal roomIDchanged; + + std::string roomID; + bool isLive; + QString streamViewerCount; + QString streamStatus; + QString streamGame; + QString streamUptime; + + const std::shared_ptr bttvChannelEmotes; + const std::shared_ptr ffzChannelEmotes; + +private: + EmoteManager &emoteManager; + IrcManager &ircManager; + + QString subLink; + QString channelLink; + QString popoutPlayerLink; + bool isSpecial; +}; +} +} diff --git a/src/twitch/twitchmessagebuilder.cpp b/src/twitch/twitchmessagebuilder.cpp index acd9c479f..5acbdb92d 100644 --- a/src/twitch/twitchmessagebuilder.cpp +++ b/src/twitch/twitchmessagebuilder.cpp @@ -15,12 +15,13 @@ using namespace chatterino::messages; namespace chatterino { namespace twitch { -TwitchMessageBuilder::TwitchMessageBuilder(Channel *_channel, Resources &_resources, +TwitchMessageBuilder::TwitchMessageBuilder(TwitchChannel *_channel, Resources &_resources, EmoteManager &_emoteManager, WindowManager &_windowManager, const Communi::IrcPrivateMessage *_ircMessage, const messages::MessageParseArgs &_args) : channel(_channel) + , twitchChannel(_channel) , resources(_resources) , windowManager(_windowManager) , colorScheme(this->windowManager.colorScheme) @@ -249,7 +250,7 @@ SharedMessage TwitchMessageBuilder::parse() // HighlightTab = false; // } - return this->build(); + return this->getMessage(); } void TwitchMessageBuilder::parseMessageID() @@ -264,11 +265,12 @@ void TwitchMessageBuilder::parseMessageID() void TwitchMessageBuilder::parseRoomID() { auto iterator = this->tags.find("room-id"); + if (iterator != std::end(this->tags)) { this->roomID = iterator.value().toString().toStdString(); - if (this->channel->roomID.empty()) { - this->channel->roomID = this->roomID; + if (this->twitchChannel->roomID.empty()) { + this->twitchChannel->roomID = this->roomID; } } } @@ -503,13 +505,13 @@ bool TwitchMessageBuilder::tryAppendEmote(QString &emoteString) if (emoteManager.bttvGlobalEmotes.tryGet(emoteString, emoteData)) { // BTTV Global Emote return this->appendEmote(emoteData); - } else if (this->channel->bttvChannelEmotes.tryGet(emoteString, emoteData)) { + } else if (this->twitchChannel->bttvChannelEmotes->tryGet(emoteString, emoteData)) { // BTTV Channel Emote return this->appendEmote(emoteData); } else if (emoteManager.ffzGlobalEmotes.tryGet(emoteString, emoteData)) { // FFZ Global Emote return this->appendEmote(emoteData); - } else if (this->channel->ffzChannelEmotes.tryGet(emoteString, emoteData)) { + } else if (this->twitchChannel->ffzChannelEmotes->tryGet(emoteString, emoteData)) { // FFZ Channel Emote return this->appendEmote(emoteData); } else if (emoteManager.getChatterinoEmotes().tryGet(emoteString, emoteData)) { diff --git a/src/twitch/twitchmessagebuilder.hpp b/src/twitch/twitchmessagebuilder.hpp index 33cb3763b..d4564f70e 100644 --- a/src/twitch/twitchmessagebuilder.hpp +++ b/src/twitch/twitchmessagebuilder.hpp @@ -3,6 +3,7 @@ #include "emotemanager.hpp" #include "messages/messagebuilder.hpp" #include "resources.hpp" +#include "twitch/twitchchannel.hpp" #include #include @@ -26,12 +27,13 @@ public: TwitchMessageBuilder() = delete; - explicit TwitchMessageBuilder(Channel *_channel, Resources &_resources, + explicit TwitchMessageBuilder(TwitchChannel *_channel, Resources &_resources, EmoteManager &_emoteManager, WindowManager &_windowManager, const Communi::IrcPrivateMessage *_ircMessage, const messages::MessageParseArgs &_args); Channel *channel; + TwitchChannel *twitchChannel; Resources &resources; WindowManager &windowManager; ColorScheme &colorScheme; diff --git a/src/widgets/chatwidgetview.cpp b/src/widgets/channelview.cpp similarity index 83% rename from src/widgets/chatwidgetview.cpp rename to src/widgets/channelview.cpp index 79a25c139..7d5c9257f 100644 --- a/src/widgets/chatwidgetview.cpp +++ b/src/widgets/channelview.cpp @@ -1,4 +1,4 @@ -#include "widgets/chatwidgetview.hpp" +#include "widgets/channelview.hpp" #include "channelmanager.hpp" #include "colorscheme.hpp" #include "messages/limitedqueuesnapshot.hpp" @@ -20,14 +20,15 @@ #include #include +using namespace chatterino::messages; + namespace chatterino { namespace widgets { -ChatWidgetView::ChatWidgetView(ChatWidget *_chatWidget) - : BaseWidget(_chatWidget) - , chatWidget(_chatWidget) +ChannelView::ChannelView(BaseWidget *parent) + : BaseWidget(parent) , scrollBar(this) - , userPopupWidget(_chatWidget->getChannelRef()) + , userPopupWidget(std::shared_ptr()) { #ifndef Q_OS_MAC // this->setAttribute(Qt::WA_OpaquePaintEvent); @@ -35,7 +36,7 @@ ChatWidgetView::ChatWidgetView(ChatWidget *_chatWidget) this->setMouseTracking(true); QObject::connect(&SettingsManager::getInstance(), &SettingsManager::wordTypeMaskChanged, this, - &ChatWidgetView::wordTypeMaskChanged); + &ChannelView::wordTypeMaskChanged); this->scrollBar.getCurrentValueChanged().connect([this] { // Whenever the scrollbar value has been changed, re-render the ChatWidgetView @@ -45,15 +46,15 @@ ChatWidgetView::ChatWidgetView(ChatWidget *_chatWidget) }); } -ChatWidgetView::~ChatWidgetView() +ChannelView::~ChannelView() { QObject::disconnect(&SettingsManager::getInstance(), &SettingsManager::wordTypeMaskChanged, - this, &ChatWidgetView::wordTypeMaskChanged); + this, &ChannelView::wordTypeMaskChanged); } -bool ChatWidgetView::layoutMessages() +bool ChannelView::layoutMessages() { - auto messages = this->chatWidget->getMessagesSnapshot(); + auto messages = this->getMessagesSnapshot(); if (messages.getLength() == 0) { this->scrollBar.setVisible(false); @@ -130,21 +131,30 @@ bool ChatWidgetView::layoutMessages() return redraw; } -void ChatWidgetView::updateGifEmotes() +void ChannelView::clearMessages() +{ + // Clear all stored messages in this chat widget + this->messages.clear(); + + // Layout chat widget messages, and force an update regardless if there are no messages + this->layoutMessages(); + this->update(); +} + +void ChannelView::updateGifEmotes() { this->onlyUpdateEmotes = true; this->update(); } -ScrollBar &ChatWidgetView::getScrollBar() +ScrollBar &ChannelView::getScrollBar() { return this->scrollBar; } -QString ChatWidgetView::getSelectedText() const +QString ChannelView::getSelectedText() { - messages::LimitedQueueSnapshot messages = - this->chatWidget->getMessagesSnapshot(); + LimitedQueueSnapshot messages = this->getMessagesSnapshot(); QString text; bool isSingleMessage = this->selection.isSingleMessage(); @@ -232,7 +242,72 @@ QString ChatWidgetView::getSelectedText() const return text; } -void ChatWidgetView::resizeEvent(QResizeEvent *) +messages::LimitedQueueSnapshot ChannelView::getMessagesSnapshot() +{ + return this->messages.getSnapshot(); +} + +void ChannelView::setChannel(std::shared_ptr channel) +{ + if (this->channel) { + this->detachChannel(); + } + this->messages.clear(); + + // on new message + this->messageAppendedConnection = + channel->messageAppended.connect([this](SharedMessage &message) { + SharedMessageRef deleted; + + auto messageRef = new MessageRef(message); + + if (this->messages.appendItem(SharedMessageRef(messageRef), deleted)) { + qreal value = std::max(0.0, this->getScrollBar().getDesiredValue() - 1); + + this->getScrollBar().setDesiredValue(value, false); + } + + layoutMessages(); + update(); + }); + + // on message removed + this->messageRemovedConnection = + channel->messageRemovedFromStart.connect([this](SharedMessage &) { + this->selection.min.messageIndex--; + this->selection.max.messageIndex--; + this->selection.start.messageIndex--; + this->selection.end.messageIndex--; + + layoutMessages(); + update(); + }); + + auto snapshot = channel->getMessageSnapshot(); + + for (size_t i = 0; i < snapshot.getLength(); i++) { + SharedMessageRef deleted; + + auto messageRef = new MessageRef(snapshot[i]); + + this->messages.appendItem(SharedMessageRef(messageRef), deleted); + } + + this->channel = channel; + + this->userPopupWidget.setChannel(channel); +} + +void ChannelView::detachChannel() +{ + // on message added + this->messageAppendedConnection.disconnect(); + + // on message removed + this->messageRemovedConnection.disconnect(); +} + +void ChannelView::resizeEvent(QResizeEvent *) { this->scrollBar.resize(this->scrollBar.width(), height()); this->scrollBar.move(width() - this->scrollBar.width(), 0); @@ -242,7 +317,7 @@ void ChatWidgetView::resizeEvent(QResizeEvent *) this->update(); } -void ChatWidgetView::setSelection(const SelectionItem &start, const SelectionItem &end) +void ChannelView::setSelection(const SelectionItem &start, const SelectionItem &end) { // selections this->selection = Selection(start, end); @@ -251,7 +326,7 @@ void ChatWidgetView::setSelection(const SelectionItem &start, const SelectionIte // << max.charIndex; } -void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) +void ChannelView::paintEvent(QPaintEvent * /*event*/) { QPainter painter(this); @@ -288,9 +363,9 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) } } -void ChatWidgetView::drawMessages(QPainter &painter) +void ChannelView::drawMessages(QPainter &painter) { - auto messages = this->chatWidget->getMessagesSnapshot(); + auto messages = this->getMessagesSnapshot(); size_t start = this->scrollBar.getCurrentValue(); @@ -341,7 +416,9 @@ void ChatWidgetView::drawMessages(QPainter &painter) messageRef->buffer = bufferPtr; + // if (buffer != nullptr) { painter.drawPixmap(0, y, *buffer); + // } y += messageRef->getHeight(); @@ -351,8 +428,8 @@ void ChatWidgetView::drawMessages(QPainter &painter) } } -void ChatWidgetView::updateMessageBuffer(messages::MessageRef *messageRef, QPixmap *buffer, - int messageIndex) +void ChannelView::updateMessageBuffer(messages::MessageRef *messageRef, QPixmap *buffer, + int messageIndex) { QPainter painter(buffer); @@ -403,8 +480,8 @@ void ChatWidgetView::updateMessageBuffer(messages::MessageRef *messageRef, QPixm messageRef->updateBuffer = false; } -void ChatWidgetView::drawMessageSelection(QPainter &painter, messages::MessageRef *messageRef, - int messageIndex, int bufferHeight) +void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef *messageRef, + int messageIndex, int bufferHeight) { if (this->selection.min.messageIndex > messageIndex || this->selection.max.messageIndex < messageIndex) { @@ -552,7 +629,7 @@ void ChatWidgetView::drawMessageSelection(QPainter &painter, messages::MessageRe painter.fillRect(rect, selectionColor); } -void ChatWidgetView::wheelEvent(QWheelEvent *event) +void ChannelView::wheelEvent(QWheelEvent *event) { if (this->scrollBar.isVisible()) { auto mouseMultiplier = SettingsManager::getInstance().mouseScrollMultiplier.get(); @@ -562,7 +639,7 @@ void ChatWidgetView::wheelEvent(QWheelEvent *event) } } -void ChatWidgetView::mouseMoveEvent(QMouseEvent *event) +void ChannelView::mouseMoveEvent(QMouseEvent *event) { std::shared_ptr message; QPoint relativePos; @@ -594,10 +671,8 @@ void ChatWidgetView::mouseMoveEvent(QMouseEvent *event) } } -void ChatWidgetView::mousePressEvent(QMouseEvent *event) +void ChannelView::mousePressEvent(QMouseEvent *event) { - this->chatWidget->giveFocus(Qt::MouseFocusReason); - this->isMouseDown = true; this->lastPressPosition = event->screenPos(); @@ -621,7 +696,7 @@ void ChatWidgetView::mousePressEvent(QMouseEvent *event) this->repaint(); } -void ChatWidgetView::mouseReleaseEvent(QMouseEvent *event) +void ChannelView::mouseReleaseEvent(QMouseEvent *event) { if (!this->isMouseDown) { // We didn't grab the mouse press, so we shouldn't be handling the mouse @@ -682,10 +757,10 @@ void ChatWidgetView::mouseReleaseEvent(QMouseEvent *event) } } -bool ChatWidgetView::tryGetMessageAt(QPoint p, std::shared_ptr &_message, - QPoint &relativePos, int &index) +bool ChannelView::tryGetMessageAt(QPoint p, std::shared_ptr &_message, + QPoint &relativePos, int &index) { - auto messages = this->chatWidget->getMessagesSnapshot(); + auto messages = this->getMessagesSnapshot(); size_t start = this->scrollBar.getCurrentValue(); diff --git a/src/widgets/chatwidgetview.hpp b/src/widgets/channelview.hpp similarity index 83% rename from src/widgets/chatwidgetview.hpp rename to src/widgets/channelview.hpp index a9c940138..0f760243d 100644 --- a/src/widgets/chatwidgetview.hpp +++ b/src/widgets/channelview.hpp @@ -2,6 +2,7 @@ #include "channel.hpp" #include "messages/lazyloadedimage.hpp" +#include "messages/limitedqueuesnapshot.hpp" #include "messages/messageref.hpp" #include "messages/word.hpp" #include "widgets/accountpopup.hpp" @@ -13,6 +14,8 @@ #include #include +#include + namespace chatterino { namespace widgets { @@ -75,21 +78,23 @@ struct Selection { } }; -class ChatWidget; - -class ChatWidgetView : public BaseWidget +class ChannelView : public BaseWidget { - friend class ChatWidget; + Q_OBJECT public: - explicit ChatWidgetView(ChatWidget *_chatWidget); - ~ChatWidgetView(); - - bool layoutMessages(); + explicit ChannelView(BaseWidget *parent = 0); + ~ChannelView(); void updateGifEmotes(); ScrollBar &getScrollBar(); - QString getSelectedText() const; + QString getSelectedText(); + + void setChannel(std::shared_ptr channel); + messages::LimitedQueueSnapshot getMessagesSnapshot(); + bool layoutMessages(); + + void clearMessages(); protected: virtual void resizeEvent(QResizeEvent *) override; @@ -110,15 +115,17 @@ private: QRect rect; }; + void detachChannel(); + void drawMessages(QPainter &painter); void updateMessageBuffer(messages::MessageRef *messageRef, QPixmap *buffer, int messageIndex); void drawMessageSelection(QPainter &painter, messages::MessageRef *messageRef, int messageIndex, int bufferHeight); void setSelection(const SelectionItem &start, const SelectionItem &end); - std::vector gifEmotes; + std::shared_ptr channel; - ChatWidget *const chatWidget; + std::vector gifEmotes; ScrollBar scrollBar; @@ -136,6 +143,11 @@ private: Selection selection; bool selecting = false; + messages::LimitedQueue messages; + + boost::signals2::connection messageAppendedConnection; + boost::signals2::connection messageRemovedConnection; + private slots: void wordTypeMaskChanged() { diff --git a/src/widgets/chatwidget.cpp b/src/widgets/chatwidget.cpp index 059cafb98..b982dce42 100644 --- a/src/widgets/chatwidget.cpp +++ b/src/widgets/chatwidget.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ ChatWidget::ChatWidget(ChannelManager &_channelManager, NotebookPage *parent) , vbox(this) , header(this) , view(this) - , input(this) + , input(this, _channelManager.getEmoteManager()) { this->vbox.setSpacing(0); this->vbox.setMargin(1); @@ -80,11 +81,15 @@ ChatWidget::ChatWidget(ChannelManager &_channelManager, NotebookPage *parent) this->channelNameUpdated(this->channelName.getValue()); this->input.textInput.installEventFilter(parent); + + connect(&view, &this->view.mousePressEvent, this, [&](QMouseEvent *) { + QTimer::singleShot(10, [this] { this->giveFocus(Qt::MouseFocusReason); }); + }); } ChatWidget::~ChatWidget() { - this->detachChannel(); + channelNameUpdated(""); } std::shared_ptr ChatWidget::getChannel() const @@ -99,82 +104,33 @@ std::shared_ptr &ChatWidget::getChannelRef() void ChatWidget::setChannel(std::shared_ptr _newChannel) { + this->view.setChannel(_newChannel); + this->channel = _newChannel; - this->channel->roomIDchanged.connect([this]() { this->header.checkLive(); }); - this->view.userPopupWidget.setChannel(_newChannel); - - // on new message - this->messageAppendedConnection = - this->channel->messageAppended.connect([this](SharedMessage &message) { - SharedMessageRef deleted; - - auto messageRef = new MessageRef(message); - - if (this->messages.appendItem(SharedMessageRef(messageRef), deleted)) { - qreal value = std::max(0.0, this->view.getScrollBar().getDesiredValue() - 1); - - this->view.getScrollBar().setDesiredValue(value, false); - } - }); - - // on message removed - this->messageRemovedConnection = - this->channel->messageRemovedFromStart.connect([this](SharedMessage &) { - this->view.selection.min.messageIndex--; - this->view.selection.max.messageIndex--; - this->view.selection.start.messageIndex--; - this->view.selection.end.messageIndex--; - }); - - auto snapshot = this->channel->getMessageSnapshot(); - - for (size_t i = 0; i < snapshot.getLength(); i++) { - SharedMessageRef deleted; - - auto messageRef = new MessageRef(snapshot[i]); - - this->messages.appendItem(SharedMessageRef(messageRef), deleted); + twitch::TwitchChannel *twitchChannel = dynamic_cast(_newChannel.get()); + if (twitchChannel != nullptr) { + twitchChannel->roomIDchanged.connect([this]() { this->header.checkLive(); }); } } -void ChatWidget::detachChannel() -{ - // on message added - this->messageAppendedConnection.disconnect(); - - // on message removed - this->messageRemovedConnection.disconnect(); -} - void ChatWidget::channelNameUpdated(const std::string &newChannelName) { // remove current channel if (!this->channel->isEmpty()) { - this->channelManager.removeChannel(this->channel->name); - - this->detachChannel(); + this->channelManager.removeTwitchChannel(this->channel->name); } // update messages - this->messages.clear(); - if (newChannelName.empty()) { - this->channel = this->channelManager.emptyChannel; + this->setChannel(this->channelManager.emptyChannel); } else { - this->setChannel(this->channelManager.addChannel(QString::fromStdString(newChannelName))); + this->setChannel( + this->channelManager.addTwitchChannel(QString::fromStdString(newChannelName))); } // update header this->header.updateChannelText(); - - // update view - this->layoutMessages(true); -} - -LimitedQueueSnapshot ChatWidget::getMessagesSnapshot() -{ - return this->messages.getSnapshot(); } bool ChatWidget::showChangeChannelPopup(const char *dialogTitle, bool empty) @@ -202,9 +158,12 @@ bool ChatWidget::showChangeChannelPopup(const char *dialogTitle, bool empty) void ChatWidget::layoutMessages(bool forceUpdate) { - if (this->view.layoutMessages() || forceUpdate) { - this->view.update(); - } + this->view.layoutMessages(); + this->view.update(); + + // if (this->view.layoutMessages() || forceUpdate) { + // this->view.update(); + // } } void ChatWidget::updateGifEmotes() @@ -285,11 +244,7 @@ void ChatWidget::doPopup() void ChatWidget::doClearChat() { - // Clear all stored messages in this chat widget - this->messages.clear(); - - // Layout chat widget messages, and force an update regardless if there are no messages - this->layoutMessages(true); + view.clearMessages(); } void ChatWidget::doOpenChannel() diff --git a/src/widgets/chatwidget.hpp b/src/widgets/chatwidget.hpp index b2dd7cfc4..442733feb 100644 --- a/src/widgets/chatwidget.hpp +++ b/src/widgets/chatwidget.hpp @@ -6,9 +6,9 @@ #include "messages/word.hpp" #include "messages/wordpart.hpp" #include "widgets/basewidget.hpp" +#include "widgets/channelview.hpp" #include "widgets/chatwidgetheader.hpp" #include "widgets/chatwidgetinput.hpp" -#include "widgets/chatwidgetview.hpp" #include #include @@ -49,13 +49,13 @@ public: std::shared_ptr &getChannelRef(); bool showChangeChannelPopup(const char *dialogTitle, bool empty = false); - messages::LimitedQueueSnapshot getMessagesSnapshot(); - void layoutMessages(bool forceUpdate = false); - void updateGifEmotes(); void giveFocus(Qt::FocusReason reason); bool hasFocus() const; + void layoutMessages(bool forceUpdate = false); + void updateGifEmotes(); + protected: virtual void paintEvent(QPaintEvent *) override; @@ -67,24 +67,20 @@ public: private: void setChannel(std::shared_ptr newChannel); - void detachChannel(); void doOpenAccountPopupWidget(AccountPopupWidget *widget, QString user); void channelNameUpdated(const std::string &newChannelName); NotebookPage &parentPage; - messages::LimitedQueue messages; - std::shared_ptr channel; QVBoxLayout vbox; ChatWidgetHeader header; - ChatWidgetView view; + ChannelView view; ChatWidgetInput input; - boost::signals2::connection messageAppendedConnection; - boost::signals2::connection messageRemovedConnection; + boost::signals2::connection channelIDChangedConnection; public: void load(const boost::property_tree::ptree &tree); diff --git a/src/widgets/chatwidgetheader.cpp b/src/widgets/chatwidgetheader.cpp index 45a26f73d..bf77d8bfc 100644 --- a/src/widgets/chatwidgetheader.cpp +++ b/src/widgets/chatwidgetheader.cpp @@ -1,5 +1,6 @@ #include "widgets/chatwidgetheader.hpp" #include "colorscheme.hpp" +#include "twitch/twitchchannel.hpp" #include "util/urlfetch.hpp" #include "widgets/chatwidget.hpp" #include "widgets/notebookpage.hpp" @@ -81,16 +82,22 @@ void ChatWidgetHeader::updateChannelText() if (channelName.empty()) { this->channelNameLabel.setText(""); } else { - if (this->chatWidget->getChannelRef()->isLive) { - auto channel = this->chatWidget->getChannelRef(); + auto channel = this->chatWidget->getChannel(); + + twitch::TwitchChannel *twitchChannel = dynamic_cast(channel.get()); + + if (channel->isEmpty()) { this->channelNameLabel.setText(QString::fromStdString(channelName) + " (live)"); - this->setToolTip( - "" - "

" + - channel->streamStatus + "

" + channel->streamGame + "
" - "Live for " + - channel->streamUptime + " with " + channel->streamViewerCount + " viewers" - "

"); + if (twitchChannel != nullptr) { + this->setToolTip("" + "

" + + twitchChannel->streamStatus + "

" + + twitchChannel->streamGame + "
" + "Live for " + + twitchChannel->streamUptime + " with " + + twitchChannel->streamViewerCount + " viewers" + "

"); + } } else { this->channelNameLabel.setText(QString::fromStdString(channelName)); this->setToolTip(""); @@ -157,7 +164,7 @@ void ChatWidgetHeader::mouseDoubleClickEvent(QMouseEvent *event) void ChatWidgetHeader::leftButtonClicked() { - QTimer::singleShot(100, [&] { + QTimer::singleShot(80, [&] { this->leftMenu.move(this->leftLabel.mapToGlobal(QPoint(0, this->leftLabel.height()))); this->leftMenu.show(); }); @@ -193,10 +200,18 @@ void ChatWidgetHeader::menuShowChangelog() { } +// TODO: this needs to be moved out of here void ChatWidgetHeader::checkLive() { - auto channel = this->chatWidget->getChannelRef(); + twitch::TwitchChannel *channel = + dynamic_cast(this->chatWidget->getChannel().get()); + + if (channel == nullptr) { + return; + } + auto id = QString::fromStdString(channel->roomID); + util::twitch::get("https://api.twitch.tv/kraken/streams/" + id, [=](QJsonObject obj) { if (obj.value("stream").isNull()) { channel->isLive = false; diff --git a/src/widgets/chatwidgetheaderbutton.cpp b/src/widgets/chatwidgetheaderbutton.cpp index 82df8f1da..8a91a6305 100644 --- a/src/widgets/chatwidgetheaderbutton.cpp +++ b/src/widgets/chatwidgetheaderbutton.cpp @@ -23,12 +23,12 @@ ChatWidgetHeaderButton::ChatWidgetHeaderButton(BaseWidget *parent, int spacing) this->setMouseEffectColor(QColor(255, 255, 255, 63)); } -void ChatWidgetHeaderButton::paintEvent(QPaintEvent *) -{ - QPainter painter(this); +// void ChatWidgetHeaderButton::paintEvent(QPaintEvent *) +//{ +// QPainter painter(this); - this->fancyPaint(painter); -} +// this->fancyPaint(painter); +//} } // namespace widgets } // namespace chatterino diff --git a/src/widgets/chatwidgetheaderbutton.hpp b/src/widgets/chatwidgetheaderbutton.hpp index 427aa0c79..07565703e 100644 --- a/src/widgets/chatwidgetheaderbutton.hpp +++ b/src/widgets/chatwidgetheaderbutton.hpp @@ -28,7 +28,7 @@ public: } protected: - virtual void paintEvent(QPaintEvent *) override; + // virtual void paintEvent(QPaintEvent *) override; private: struct { diff --git a/src/widgets/chatwidgetinput.cpp b/src/widgets/chatwidgetinput.cpp index 35e43ec47..a4a76de07 100644 --- a/src/widgets/chatwidgetinput.cpp +++ b/src/widgets/chatwidgetinput.cpp @@ -13,9 +13,10 @@ namespace chatterino { namespace widgets { -ChatWidgetInput::ChatWidgetInput(ChatWidget *_chatWidget) +ChatWidgetInput::ChatWidgetInput(ChatWidget *_chatWidget, EmoteManager &emoteManager) : BaseWidget(_chatWidget) , chatWidget(_chatWidget) + , emoteManager(emoteManager) , emotesLabel(this) { this->setMaximumHeight(150); @@ -46,10 +47,12 @@ ChatWidgetInput::ChatWidgetInput(ChatWidget *_chatWidget) connect(&this->emotesLabel, &ChatWidgetHeaderButton::clicked, [this] { if (this->emotePopup == nullptr) { - this->emotePopup = new EmotePopup(); + this->emotePopup = new EmotePopup(this->colorScheme, this->emoteManager); } - this->emotePopup->show(); // + this->emotePopup->resize(300, 500); + this->emotePopup->loadChannel(this->chatWidget->getChannel()); + this->emotePopup->show(); }); connect(&textInput, &ResizingTextEdit::textChanged, this, &ChatWidgetInput::editTextChanged); diff --git a/src/widgets/chatwidgetinput.hpp b/src/widgets/chatwidgetinput.hpp index 92888e8ba..4e302e2dd 100644 --- a/src/widgets/chatwidgetinput.hpp +++ b/src/widgets/chatwidgetinput.hpp @@ -1,5 +1,6 @@ #pragma once +#include "emotemanager.hpp" #include "resizingtextedit.hpp" #include "widgets/basewidget.hpp" #include "widgets/chatwidgetheaderbutton.hpp" @@ -25,7 +26,7 @@ class ChatWidgetInput : public BaseWidget Q_OBJECT public: - ChatWidgetInput(ChatWidget *_chatWidget); + ChatWidgetInput(ChatWidget *_chatWidget, EmoteManager &); ~ChatWidgetInput(); protected: @@ -37,6 +38,7 @@ protected: private: ChatWidget *const chatWidget; EmotePopup *emotePopup = nullptr; + EmoteManager &emoteManager; boost::signals2::connection textLengthVisibleChangedConnection; QHBoxLayout hbox; diff --git a/src/widgets/emotepopup.cpp b/src/widgets/emotepopup.cpp index 731ff54db..b40083000 100644 --- a/src/widgets/emotepopup.cpp +++ b/src/widgets/emotepopup.cpp @@ -1,18 +1,70 @@ #include "emotepopup.h" + +#include + +#include "messages/messagebuilder.hpp" +#include "twitch/twitchchannel.hpp" + +using namespace chatterino::twitch; +using namespace chatterino::messages; + namespace chatterino { namespace widgets { -EmotePopup::EmotePopup(QWidget *parent) - : QWidget(parent) +EmotePopup::EmotePopup(ColorScheme &colorScheme, EmoteManager &emoteManager) + : BaseWidget(colorScheme, 0) + , emoteManager(emoteManager) { + QHBoxLayout *layout = new QHBoxLayout(this); + this->setLayout(layout); + layout->setMargin(0); + + view = new ChannelView(this); + layout->addWidget(view); } -void EmotePopup::loadChannel(std::shared_ptr channel) +void EmotePopup::loadChannel(std::shared_ptr _channel) { - // channel->bttvChannelEmotes.each([](const QString &key, const EmoteData &value) { + TwitchChannel *channel = dynamic_cast(_channel.get()); - // // - // }); + if (channel == nullptr) { + return; + } + + std::shared_ptr emoteChannel(new Channel); + + auto addEmotes = [&](EmoteMap &map, const QString &title, const QString &emoteDesc) { + // TITLE + messages::MessageBuilder builder1; + + builder1.appendWord( + Word(title, Word::Type::Text, QColor(255, 255, 255), QString(), QString())); + + builder1.getMessage()->centered = true; + emoteChannel->addMessage(builder1.getMessage()); + + // EMOTES + messages::MessageBuilder builder2; + builder2.getMessage()->centered = true; + + map.each([&](const QString &key, const EmoteData &value) { + builder2.appendWord(Word(value.image, Word::Type::AlwaysShow, key, emoteDesc, + Link(Link::Type::InsertText, key))); + }); + + emoteChannel->addMessage(builder2.getMessage()); + }; + + addEmotes(this->emoteManager.bttvGlobalEmotes, "BetterTTV Global Emotes", + "BetterTTV Global Emote"); + addEmotes(*channel->bttvChannelEmotes.get(), "BetterTTV Channel Emotes", + "BetterTTV Channel Emote"); + addEmotes(this->emoteManager.ffzGlobalEmotes, "FrankerFaceZ Global Emotes", + "FrankerFaceZ Global Emote"); + addEmotes(*channel->ffzChannelEmotes.get(), "FrankerFaceZ Channel Emotes", + "FrankerFaceZ Channel Emote"); + + view->setChannel(emoteChannel); } } } diff --git a/src/widgets/emotepopup.h b/src/widgets/emotepopup.h index 779b23d64..4c8255213 100644 --- a/src/widgets/emotepopup.h +++ b/src/widgets/emotepopup.h @@ -1,18 +1,23 @@ #pragma once -#include - #include "channel.hpp" +#include "emotemanager.hpp" +#include "widgets/basewidget.hpp" +#include "widgets/channelview.hpp" namespace chatterino { namespace widgets { -class EmotePopup : public QWidget +class EmotePopup : public BaseWidget { public: - explicit EmotePopup(QWidget *parent = 0); + explicit EmotePopup(ColorScheme &, EmoteManager &); void loadChannel(std::shared_ptr channel); + +private: + ChannelView *view; + EmoteManager &emoteManager; }; } } diff --git a/src/widgets/fancybutton.cpp b/src/widgets/fancybutton.cpp index fb177266a..84285b210 100644 --- a/src/widgets/fancybutton.cpp +++ b/src/widgets/fancybutton.cpp @@ -23,7 +23,7 @@ void FancyButton::setMouseEffectColor(QColor color) void FancyButton::paintEvent(QPaintEvent *) { - QPainter painter; + QPainter painter(this); this->fancyPaint(painter); } diff --git a/src/widgets/notebook.cpp b/src/widgets/notebook.cpp index 3803df89f..b8c19b42c 100644 --- a/src/widgets/notebook.cpp +++ b/src/widgets/notebook.cpp @@ -212,7 +212,7 @@ void Notebook::resizeEvent(QResizeEvent *) void Notebook::settingsButtonClicked() { - QTimer::singleShot(100, [this] { SettingsDialog::showDialog(); }); + QTimer::singleShot(80, [this] { SettingsDialog::showDialog(); }); } void Notebook::usersButtonClicked() @@ -221,7 +221,7 @@ void Notebook::usersButtonClicked() void Notebook::addPageButtonClicked() { - QTimer::singleShot(100, [this] { this->addPage(true); }); + QTimer::singleShot(80, [this] { this->addPage(true); }); } void Notebook::load(const boost::property_tree::ptree &tree) diff --git a/src/widgets/scrollbar.cpp b/src/widgets/scrollbar.cpp index e5fdf6ec7..b6ac33ad8 100644 --- a/src/widgets/scrollbar.cpp +++ b/src/widgets/scrollbar.cpp @@ -1,6 +1,6 @@ #include "widgets/scrollbar.hpp" #include "colorscheme.hpp" -#include "widgets/chatwidgetview.hpp" +#include "widgets/channelview.hpp" #include #include @@ -11,7 +11,7 @@ namespace chatterino { namespace widgets { -ScrollBar::ScrollBar(ChatWidgetView *parent) +ScrollBar::ScrollBar(ChannelView *parent) : BaseWidget(parent) , _currentValueAnimation(this, "_currentValue") , _highlights(nullptr) diff --git a/src/widgets/scrollbar.hpp b/src/widgets/scrollbar.hpp index 626b1dcd4..d621e03ba 100644 --- a/src/widgets/scrollbar.hpp +++ b/src/widgets/scrollbar.hpp @@ -14,14 +14,14 @@ class ColorScheme; namespace widgets { -class ChatWidgetView; +class ChannelView; class ScrollBar : public BaseWidget { Q_OBJECT public: - ScrollBar(ChatWidgetView *parent = 0); + ScrollBar(ChannelView *parent = 0); ~ScrollBar(); void removeHighlightsWhere(std::function func); diff --git a/src/windowmanager.cpp b/src/windowmanager.cpp index ac0dbc9f4..3904862ea 100644 --- a/src/windowmanager.cpp +++ b/src/windowmanager.cpp @@ -46,12 +46,12 @@ void WindowManager::repaintGifEmotes() } } -void WindowManager::updateAll() -{ - if (this->mainWindow != nullptr) { - this->mainWindow->update(); - } -} +// void WindowManager::updateAll() +//{ +// if (this->mainWindow != nullptr) { +// this->mainWindow->update(); +// } +//} widgets::MainWindow &WindowManager::getMainWindow() { diff --git a/src/windowmanager.hpp b/src/windowmanager.hpp index cbf18ae23..69f50aa85 100644 --- a/src/windowmanager.hpp +++ b/src/windowmanager.hpp @@ -23,7 +23,7 @@ public: void layoutVisibleChatWidgets(Channel *channel = nullptr); void repaintVisibleChatWidgets(Channel *channel = nullptr); void repaintGifEmotes(); - void updateAll(); + // void updateAll(); widgets::MainWindow &getMainWindow();