diff --git a/chatterino.pro b/chatterino.pro index 5f3b48706..3b704d192 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -169,7 +169,8 @@ HEADERS += \ src/widgets/window.hpp \ src/widgets/splitcontainer.hpp \ src/widgets/helper/droppreview.hpp \ - src/widgets/helper/splitcolumn.hpp + src/widgets/helper/splitcolumn.hpp \ + src/util/irchelpers.hpp PRECOMPILED_HEADER = diff --git a/src/accountmanager.cpp b/src/accountmanager.cpp index c5dc51454..04ec59a24 100644 --- a/src/accountmanager.cpp +++ b/src/accountmanager.cpp @@ -1,7 +1,6 @@ #include "accountmanager.hpp" #include "common.hpp" - -#include +#include "debug/log.hpp" namespace chatterino { @@ -19,18 +18,84 @@ inline QString getEnvString(const char *target) } // namespace -AccountManager::AccountManager() - : currentUser("/accounts/current", "") - , twitchAnonymousUser("justinfan64537", "", "") +std::shared_ptr TwitchAccountManager::getCurrent() { + if (!this->currentUser) { + return this->anonymousUser; + } + + return this->currentUser; +} + +std::vector TwitchAccountManager::getUsernames() const +{ + std::vector userNames; + + std::lock_guard lock(this->mutex); + + for (const auto &user : this->users) { + userNames.push_back(user->getUserName()); + } + + return userNames; +} + +std::shared_ptr TwitchAccountManager::findUserByUsername( + const QString &username) const +{ + std::lock_guard lock(this->mutex); + + for (const auto &user : this->users) { + if (username.compare(user->getUserName(), Qt::CaseInsensitive) == 0) { + return user; + } + } + + return nullptr; +} + +bool TwitchAccountManager::userExists(const QString &username) const +{ + return this->findUserByUsername(username) != nullptr; +} + +bool TwitchAccountManager::addUser(std::shared_ptr user) +{ + if (this->userExists(user->getNickName())) { + // User already exists in user list + return false; + } + + std::lock_guard lock(this->mutex); + + this->users.push_back(user); + + return true; +} + +AccountManager::AccountManager() +{ + this->Twitch.anonymousUser.reset(new twitch::TwitchUser("justinfan64537", "", "")); + + this->Twitch.currentUsername.getValueChangedSignal().connect([this](const auto &newValue) { + QString newUsername(QString::fromStdString(newValue)); + auto user = this->Twitch.findUserByUsername(newUsername); + if (user) { + debug::Log("[AccountManager:currentUsernameChanged] User successfully updated to {}", + newUsername); + // XXX: Should we set the user regardless if the username is found or not? + // I can see the logic in setting it to nullptr if the `currentUsername` value has been + // set to "" or an invalid username + this->Twitch.currentUser = user; + this->Twitch.userChanged.invoke(); + } + }); } void AccountManager::load() { auto keys = pajlada::Settings::SettingManager::getObjectKeys("/accounts"); - bool first = true; - for (const auto &uid : keys) { if (uid == "current") { continue; @@ -49,74 +114,20 @@ void AccountManager::load() continue; } - if (first) { - this->setCurrentTwitchUser(qS(username)); - first = false; - } + auto user = + std::make_shared(qS(username), qS(oauthToken), qS(clientID)); - twitch::TwitchUser user(qS(username), qS(oauthToken), qS(clientID)); - - this->addTwitchUser(user); + this->Twitch.addUser(user); printf("Adding user %s(%s)\n", username.c_str(), userID.c_str()); } -} -twitch::TwitchUser &AccountManager::getTwitchAnon() -{ - return this->twitchAnonymousUser; -} - -twitch::TwitchUser &AccountManager::getTwitchUser() -{ - std::lock_guard lock(this->twitchUsersMutex); - - if (this->twitchUsers.size() == 0) { - return this->getTwitchAnon(); + auto currentUser = this->Twitch.findUserByUsername( + QString::fromStdString(this->Twitch.currentUsername.getValue())); + if (currentUser) { + this->Twitch.currentUser = currentUser; + this->Twitch.userChanged.invoke(); } - - QString currentUsername = QString::fromStdString(this->currentUser); - - for (auto &user : this->twitchUsers) { - if (user.getUserName() == currentUsername) { - return user; - } - } - - return this->twitchUsers.front(); -} - -void AccountManager::setCurrentTwitchUser(const QString &username) -{ - this->currentUser.setValue(username.toStdString()); -} - -std::vector AccountManager::getTwitchUsers() -{ - std::lock_guard lock(this->twitchUsersMutex); - - return std::vector(this->twitchUsers); -} - -bool AccountManager::removeTwitchUser(const QString &userName) -{ - std::lock_guard lock(this->twitchUsersMutex); - - for (auto it = this->twitchUsers.begin(); it != this->twitchUsers.end(); it++) { - if ((*it).getUserName() == userName) { - this->twitchUsers.erase(it); - return true; - } - } - - return false; -} - -void AccountManager::addTwitchUser(const twitch::TwitchUser &user) -{ - std::lock_guard lock(this->twitchUsersMutex); - - this->twitchUsers.push_back(user); } } // namespace chatterino diff --git a/src/accountmanager.hpp b/src/accountmanager.hpp index 970e7972c..f496c7ffc 100644 --- a/src/accountmanager.hpp +++ b/src/accountmanager.hpp @@ -9,6 +9,34 @@ namespace chatterino { +class AccountManager; + +class TwitchAccountManager +{ +public: + // Returns the current twitchUsers, or the anonymous user if we're not currently logged in + std::shared_ptr getCurrent(); + + std::vector getUsernames() const; + + std::shared_ptr findUserByUsername(const QString &username) const; + bool userExists(const QString &username) const; + + pajlada::Settings::Setting currentUsername = {"/accounts/current", ""}; + pajlada::Signals::NoArgSignal userChanged; + +private: + bool addUser(std::shared_ptr user); + + std::shared_ptr currentUser; + + std::shared_ptr anonymousUser; + std::vector> users; + mutable std::mutex mutex; + + friend class AccountManager; +}; + class AccountManager { public: @@ -20,30 +48,10 @@ public: void load(); - twitch::TwitchUser &getTwitchAnon(); - - // Returns first user from twitchUsers, or twitchAnonymousUser if twitchUsers is empty - twitch::TwitchUser &getTwitchUser(); - - // Return a copy of the current available twitch users - std::vector getTwitchUsers(); - - // Remove twitch user with the given username - bool removeTwitchUser(const QString &userName); - - void setCurrentTwitchUser(const QString &username); - - // Add twitch user to the list of available twitch users - void addTwitchUser(const twitch::TwitchUser &user); + TwitchAccountManager Twitch; private: AccountManager(); - - pajlada::Settings::Setting currentUser; - - twitch::TwitchUser twitchAnonymousUser; - std::vector twitchUsers; - std::mutex twitchUsersMutex; }; } // namespace chatterino diff --git a/src/application.cpp b/src/application.cpp index 9ae0b6cc4..5949c0d4f 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -18,7 +18,6 @@ Application::Application() , channelManager(this->windowManager, this->emoteManager, this->ircManager) , ircManager(this->channelManager, this->resources, this->emoteManager, this->windowManager) { - // TODO(pajlada): Get rid of all singletons logging::init(); SettingsManager::getInstance().load(); @@ -29,8 +28,6 @@ Application::Application() AccountManager::getInstance().load(); - this->ircManager.setUser(AccountManager::getInstance().getTwitchUser()); - // XXX SettingsManager::getInstance().updateWordTypeMask(); diff --git a/src/asyncexec.hpp b/src/asyncexec.hpp index ba36b2682..7899676c7 100644 --- a/src/asyncexec.hpp +++ b/src/asyncexec.hpp @@ -25,3 +25,30 @@ public: private: std::function action; }; + +// Taken from +// https://stackoverflow.com/questions/21646467/how-to-execute-a-functor-or-a-lambda-in-a-given-thread-in-qt-gcd-style +// Qt 5/4 - preferred, has least allocations +template +static void postToThread(F &&fun, QObject *obj = qApp) +{ + struct Event : public QEvent { + using Fun = typename std::decay::type; + Fun fun; + Event(Fun &&fun) + : QEvent(QEvent::None) + , fun(std::move(fun)) + { + } + Event(const Fun &fun) + : QEvent(QEvent::None) + , fun(fun) + { + } + ~Event() + { + fun(); + } + }; + QCoreApplication::postEvent(obj, new Event(std::forward(fun))); +} diff --git a/src/channelmanager.cpp b/src/channelmanager.cpp index 7f26232c9..9e9cdd2c7 100644 --- a/src/channelmanager.cpp +++ b/src/channelmanager.cpp @@ -136,4 +136,14 @@ WindowManager &ChannelManager::getWindowManager() return this->windowManager; } +void ChannelManager::doOnAll(std::function)> func) +{ + for (const auto &channel : this->twitchChannels) { + func(std::get<0>(channel)); + } + + func(this->whispersChannel); + func(this->mentionsChannel); +} + } // namespace chatterino diff --git a/src/channelmanager.hpp b/src/channelmanager.hpp index a4cd71b30..77a5712a4 100644 --- a/src/channelmanager.hpp +++ b/src/channelmanager.hpp @@ -32,6 +32,8 @@ public: EmoteManager &getEmoteManager(); WindowManager &getWindowManager(); + void doOnAll(std::function)> func); + // Special channels const std::shared_ptr whispersChannel; const std::shared_ptr mentionsChannel; diff --git a/src/emotemanager.cpp b/src/emotemanager.cpp index f9b6e9bf9..fcdb2348b 100644 --- a/src/emotemanager.cpp +++ b/src/emotemanager.cpp @@ -505,7 +505,6 @@ void EmoteManager::loadFFZEmotes() EmoteData EmoteManager::getTwitchEmoteById(long id, const QString &emoteName) { return _twitchEmoteFromCache.getOrAdd(id, [this, &emoteName, &id] { - qDebug() << "added twitch emote: " << id; qreal scale; QString url = getTwitchEmoteLink(id, scale); return new LazyLoadedImage(*this, this->windowManager, url, scale, emoteName, diff --git a/src/ircmanager.cpp b/src/ircmanager.cpp index 9a1bcf3d5..1e2bd605c 100644 --- a/src/ircmanager.cpp +++ b/src/ircmanager.cpp @@ -3,6 +3,7 @@ #include "asyncexec.hpp" #include "channel.hpp" #include "channelmanager.hpp" +#include "debug/log.hpp" #include "emotemanager.hpp" #include "messages/messageparseargs.hpp" #include "twitch/twitchmessagebuilder.hpp" @@ -12,7 +13,6 @@ #include "windowmanager.hpp" #include -#include #include #include #include @@ -31,46 +31,65 @@ IrcManager::IrcManager(ChannelManager &_channelManager, Resources &_resources, , resources(_resources) , emoteManager(_emoteManager) , windowManager(_windowManager) - , account(AccountManager::getInstance().getTwitchAnon()) - , currentUser("/accounts/current") { - this->currentUser.getValueChangedSignal().connect([](const auto &newUsername) { - // TODO: Implement - qDebug() << "Current user changed, fetch new credentials and reconnect"; + AccountManager::getInstance().Twitch.userChanged.connect([this]() { + this->setUser(AccountManager::getInstance().Twitch.getCurrent()); + + debug::Log("[IrcManager] Reconnecting to Twitch IRC as new user {}", + this->account->getUserName()); + + postToThread([this] { this->connect(); }); }); + + // Initialize the connections + this->writeConnection.reset(new Communi::IrcConnection); + this->writeConnection->moveToThread(QCoreApplication::instance()->thread()); + + QObject::connect(this->writeConnection.get(), &Communi::IrcConnection::messageReceived, this, + &IrcManager::writeConnectionMessageReceived); + + this->readConnection.reset(new Communi::IrcConnection); + this->readConnection->moveToThread(QCoreApplication::instance()->thread()); + + // Listen to read connection message signals + QObject::connect(this->readConnection.get(), &Communi::IrcConnection::messageReceived, this, + &IrcManager::messageReceived); + QObject::connect(this->readConnection.get(), &Communi::IrcConnection::privateMessageReceived, + this, &IrcManager::privateMessageReceived); + + QObject::connect(this->readConnection.get(), &Communi::IrcConnection::connected, this, + &IrcManager::onConnected); + QObject::connect(this->readConnection.get(), &Communi::IrcConnection::disconnected, this, + &IrcManager::onDisconnected); } -const twitch::TwitchUser &IrcManager::getUser() const +void IrcManager::setUser(std::shared_ptr newAccount) { - return this->account; -} - -void IrcManager::setUser(const twitch::TwitchUser &account) -{ - this->account = account; + this->account = newAccount; } void IrcManager::connect() { - disconnect(); + this->disconnect(); - async_exec([this] { beginConnecting(); }); + this->initializeConnection(this->writeConnection, false); + this->initializeConnection(this->readConnection, true); + + // XXX(pajlada): Disabled the async_exec for now, because if we happen to run the + // `beginConnecting` function in a different thread than last time, we won't be able to connect + // because we can't clean up the previous connection properly + // async_exec([this] { beginConnecting(); }); + this->beginConnecting(); } -Communi::IrcConnection *IrcManager::createConnection(bool doRead) +void IrcManager::initializeConnection(const std::unique_ptr &connection, + bool isReadConnection) { - Communi::IrcConnection *connection = new Communi::IrcConnection; + assert(this->account); - if (doRead) { - QObject::connect(connection, &Communi::IrcConnection::messageReceived, this, - &IrcManager::messageReceived); - QObject::connect(connection, &Communi::IrcConnection::privateMessageReceived, this, - &IrcManager::privateMessageReceived); - } - - QString username = this->account.getUserName(); - QString oauthClient = this->account.getOAuthClient(); - QString oauthToken = this->account.getOAuthToken(); + QString username = this->account->getUserName(); + QString oauthClient = this->account->getOAuthClient(); + QString oauthToken = this->account->getOAuthToken(); if (!oauthToken.startsWith("oauth:")) { oauthToken.prepend("oauth:"); } @@ -79,23 +98,27 @@ Communi::IrcConnection *IrcManager::createConnection(bool doRead) connection->setNickName(username); connection->setRealName(username); - if (!this->account.isAnon()) { + if (!this->account->isAnon()) { connection->setPassword(oauthToken); this->refreshIgnoredUsers(username, oauthClient, oauthToken); } - if (doRead) { + if (isReadConnection) { connection->sendCommand( Communi::IrcCommand::createCapability("REQ", "twitch.tv/membership")); connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/commands")); connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/tags")); + } else { + connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/tags")); + + connection->sendCommand( + Communi::IrcCommand::createCapability("REQ", "twitch.tv/membership")); + connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/commands")); } connection->setHost("irc.chat.twitch.tv"); connection->setPort(6667); - - return connection; } void IrcManager::refreshIgnoredUsers(const QString &username, const QString &oauthClient, @@ -136,43 +159,23 @@ void IrcManager::refreshIgnoredUsers(const QString &username, const QString &oau void IrcManager::beginConnecting() { - uint32_t generation = ++this->connectionGeneration; - - Communi::IrcConnection *_writeConnection = this->createConnection(false); - Communi::IrcConnection *_readConnection = this->createConnection(true); - std::lock_guard locker(this->connectionMutex); - if (generation == this->connectionGeneration) { - this->writeConnection = std::shared_ptr(_writeConnection); - this->readConnection = std::shared_ptr(_readConnection); - - this->writeConnection->moveToThread(QCoreApplication::instance()->thread()); - this->readConnection->moveToThread(QCoreApplication::instance()->thread()); - - for (auto &channel : this->channelManager.getItems()) { - this->writeConnection->sendRaw("JOIN #" + channel->name); - this->readConnection->sendRaw("JOIN #" + channel->name); - } - this->writeConnection->open(); - this->readConnection->open(); - } else { - delete _writeConnection; - delete _readConnection; + for (auto &channel : this->channelManager.getItems()) { + this->writeConnection->sendRaw("JOIN #" + channel->name); + this->readConnection->sendRaw("JOIN #" + channel->name); } + + this->writeConnection->open(); + this->readConnection->open(); } void IrcManager::disconnect() { - this->connectionMutex.lock(); + std::lock_guard locker(this->connectionMutex); - auto _readConnection = this->readConnection; - auto _writeConnection = this->writeConnection; - - this->readConnection.reset(); - this->writeConnection.reset(); - - this->connectionMutex.unlock(); + this->readConnection->close(); + this->writeConnection->close(); } void IrcManager::sendMessage(const QString &channelName, const QString &message) @@ -184,29 +187,6 @@ void IrcManager::sendMessage(const QString &channelName, const QString &message) } this->connectionMutex.unlock(); - - // DEBUGGING - /* - Communi::IrcPrivateMessage msg(this->readConnection.get()); - - QStringList params{"#pajlada", message}; - - qDebug() << params; - - if (message == "COMIC SANS LOL") { - FontManager::getInstance().currentFontFamily = "Comic Sans MS"; - } else if (message == "ARIAL LOL") { - FontManager::getInstance().currentFontFamily = "Arial"; - } else if (message == "WINGDINGS LOL") { - FontManager::getInstance().currentFontFamily = "Wingdings"; - } - - msg.setParameters(params); - - msg.setPrefix("pajlada!pajlada@pajlada"); - - this->privateMessageReceived(&msg); - */ } void IrcManager::joinChannel(const QString &channelName) @@ -271,6 +251,18 @@ void IrcManager::messageReceived(Communi::IrcMessage *message) this->handleUserNoticeMessage(message); } else if (command == "MODE") { this->handleModeMessage(message); + } else if (command == "NOTICE") { + this->handleNoticeMessage(static_cast(message)); + } +} + +void IrcManager::writeConnectionMessageReceived(Communi::IrcMessage *message) +{ + switch (message->type()) { + case Communi::IrcMessage::Type::Notice: { + this->handleWriteConnectionNoticeMessage( + static_cast(message)); + } break; } } @@ -292,17 +284,59 @@ void IrcManager::handleRoomStateMessage(Communi::IrcMessage *message) void IrcManager::handleClearChatMessage(Communi::IrcMessage *message) { - // do nothing + assert(message->parameters().length() >= 1); + + auto rawChannelName = message->parameter(0); + + assert(rawChannelName.length() >= 2); + + auto trimmedChannelName = rawChannelName.mid(1); + + auto c = this->channelManager.getTwitchChannel(trimmedChannelName); + + if (!c) { + debug::Log("[IrcManager:handleClearChatMessage] Channel {} not found in channel manager", + trimmedChannelName); + return; + } + + if (message->parameters().length() == 1) { + std::shared_ptr msg( + Message::createSystemMessage("Chat has been cleared by a moderator.")); + + c->addMessage(msg); + + return; + } + + assert(message->parameters().length() >= 2); + + QString username = message->parameter(1); + QString durationInSeconds, reason; + QVariant v = message->tag("ban-duration"); + if (v.isValid()) { + durationInSeconds = v.toString(); + } + + v = message->tag("ban-reason"); + if (v.isValid()) { + reason = v.toString(); + } + + std::shared_ptr msg( + Message::createTimeoutMessage(username, durationInSeconds, reason)); + + c->addMessage(msg); } void IrcManager::handleUserStateMessage(Communi::IrcMessage *message) { - // do nothing + // TODO: Implement } void IrcManager::handleWhisperMessage(Communi::IrcMessage *message) { - // do nothing + // TODO: Implement } void IrcManager::handleUserNoticeMessage(Communi::IrcMessage *message) @@ -312,16 +346,15 @@ void IrcManager::handleUserNoticeMessage(Communi::IrcMessage *message) void IrcManager::handleModeMessage(Communi::IrcMessage *message) { - auto channel = channelManager.getTwitchChannel(message->parameter(0).remove(0,1)); - if(message->parameter(1) == "+o") - { - channel->modList.append(message->parameter(2)); - } else if(message->parameter(1) == "-o") - { - channel->modList.append(message->parameter(2)); - } + auto channel = channelManager.getTwitchChannel(message->parameter(0).remove(0, 1)); + if (message->parameter(1) == "+o") { + channel->modList.append(message->parameter(2)); + } else if (message->parameter(1) == "-o") { + channel->modList.append(message->parameter(2)); + } } +// XXX: This does not fit in IrcManager bool IrcManager::isTwitchBlockedUser(QString const &username) { QMutexLocker locker(&this->twitchBlockedUsersMutex); @@ -331,11 +364,14 @@ bool IrcManager::isTwitchBlockedUser(QString const &username) return iterator != this->twitchBlockedUsers.end(); } +// XXX: This does not fit in IrcManager bool IrcManager::tryAddIgnoredUser(QString const &username, QString &errorMessage) { - QUrl url("https://api.twitch.tv/kraken/users/" + this->account.getUserName() + "/blocks/" + - username + "?oauth_token=" + this->account.getOAuthToken() + - "&client_id=" + this->account.getOAuthClient()); + assert(this->account); + + QUrl url("https://api.twitch.tv/kraken/users/" + this->account->getUserName() + "/blocks/" + + username + "?oauth_token=" + this->account->getOAuthToken() + + "&client_id=" + this->account->getOAuthClient()); QNetworkRequest request(url); auto reply = this->networkAccessManager.put(request, QByteArray()); @@ -352,9 +388,11 @@ bool IrcManager::tryAddIgnoredUser(QString const &username, QString &errorMessag reply->deleteLater(); errorMessage = "Error while ignoring user \"" + username + "\": " + reply->errorString(); + return false; } +// XXX: This does not fit in IrcManager void IrcManager::addIgnoredUser(QString const &username) { QString errorMessage; @@ -363,11 +401,14 @@ void IrcManager::addIgnoredUser(QString const &username) } } +// XXX: This does not fit in IrcManager bool IrcManager::tryRemoveIgnoredUser(QString const &username, QString &errorMessage) { - QUrl url("https://api.twitch.tv/kraken/users/" + this->account.getUserName() + "/blocks/" + - username + "?oauth_token=" + this->account.getOAuthToken() + - "&client_id=" + this->account.getOAuthClient()); + assert(this->account); + + QUrl url("https://api.twitch.tv/kraken/users/" + this->account->getUserName() + "/blocks/" + + username + "?oauth_token=" + this->account->getOAuthToken() + + "&client_id=" + this->account->getOAuthClient()); QNetworkRequest request(url); auto reply = this->networkAccessManager.deleteResource(request); @@ -384,9 +425,11 @@ bool IrcManager::tryRemoveIgnoredUser(QString const &username, QString &errorMes reply->deleteLater(); errorMessage = "Error while unignoring user \"" + username + "\": " + reply->errorString(); + return false; } +// XXX: This does not fit in IrcManager void IrcManager::removeIgnoredUser(QString const &username) { QString errorMessage; @@ -395,4 +438,79 @@ void IrcManager::removeIgnoredUser(QString const &username) } } +void IrcManager::handleNoticeMessage(Communi::IrcNoticeMessage *message) +{ + auto rawChannelName = message->target(); + + assert(rawChannelName.length() >= 2); + + auto trimmedChannelName = rawChannelName.mid(1); + + auto c = this->channelManager.getTwitchChannel(trimmedChannelName); + + if (!c) { + debug::Log("[IrcManager:handleNoticeMessage] Channel {} not found in channel manager", + trimmedChannelName); + return; + } + + std::shared_ptr msg(Message::createSystemMessage(message->content())); + + c->addMessage(msg); +} + +void IrcManager::handleWriteConnectionNoticeMessage(Communi::IrcNoticeMessage *message) +{ + auto rawChannelName = message->target(); + + assert(rawChannelName.length() >= 2); + + auto trimmedChannelName = rawChannelName.mid(1); + + auto c = this->channelManager.getTwitchChannel(trimmedChannelName); + + if (!c) { + debug::Log("[IrcManager:handleNoticeMessage] Channel {} not found in channel manager", + trimmedChannelName); + return; + } + + QVariant v = message->tag("msg-id"); + if (!v.isValid()) { + return; + } + QString msg_id = v.toString(); + + static QList idsToSkip = {"timeout_success", "ban_success"}; + + if (idsToSkip.contains(msg_id)) { + // Already handled in the read-connection + return; + } + + std::shared_ptr msg(Message::createSystemMessage(message->content())); + + c->addMessage(msg); +} + +void IrcManager::onConnected() +{ + std::shared_ptr msg(Message::createSystemMessage("connected to chat")); + + this->channelManager.doOnAll([msg](std::shared_ptr channel) { + assert(channel); + channel->addMessage(msg); + }); +} + +void IrcManager::onDisconnected() +{ + std::shared_ptr msg(Message::createSystemMessage("disconnected from chat")); + + this->channelManager.doOnAll([msg](std::shared_ptr channel) { + assert(channel); + channel->addMessage(msg); + }); +} + } // namespace chatterino diff --git a/src/ircmanager.hpp b/src/ircmanager.hpp index 94ad534ca..ac143a04f 100644 --- a/src/ircmanager.hpp +++ b/src/ircmanager.hpp @@ -5,6 +5,7 @@ #include "messages/message.hpp" #include "twitch/twitchuser.hpp" +#include #include #include #include @@ -44,8 +45,7 @@ public: void joinChannel(const QString &channelName); void partChannel(const QString &channelName); - const twitch::TwitchUser &getUser() const; - void setUser(const twitch::TwitchUser &account); + void setUser(std::shared_ptr newAccount); pajlada::Signals::Signal onPrivateMessage; @@ -56,26 +56,20 @@ public: private: // variables - twitch::TwitchUser account; + std::shared_ptr account = nullptr; - pajlada::Settings::Setting currentUser; + std::unique_ptr writeConnection = nullptr; + std::unique_ptr readConnection = nullptr; - std::shared_ptr writeConnection = nullptr; - -public: - std::shared_ptr readConnection = nullptr; - -private: std::mutex connectionMutex; - uint32_t connectionGeneration = 0; QMap twitchBlockedUsers; QMutex twitchBlockedUsersMutex; QNetworkAccessManager networkAccessManager; - // methods - Communi::IrcConnection *createConnection(bool doRead); + void initializeConnection(const std::unique_ptr &connection, + bool isReadConnection); void refreshIgnoredUsers(const QString &username, const QString &oauthClient, const QString &oauthToken); @@ -85,12 +79,19 @@ private: void privateMessageReceived(Communi::IrcPrivateMessage *message); void messageReceived(Communi::IrcMessage *message); + void writeConnectionMessageReceived(Communi::IrcMessage *message); + void handleRoomStateMessage(Communi::IrcMessage *message); void handleClearChatMessage(Communi::IrcMessage *message); void handleUserStateMessage(Communi::IrcMessage *message); void handleWhisperMessage(Communi::IrcMessage *message); void handleUserNoticeMessage(Communi::IrcMessage *message); void handleModeMessage(Communi::IrcMessage *message); + void handleNoticeMessage(Communi::IrcNoticeMessage *message); + void handleWriteConnectionNoticeMessage(Communi::IrcNoticeMessage *message); + + void onConnected(); + void onDisconnected(); }; } // namespace chatterino diff --git a/src/messages/message.cpp b/src/messages/message.cpp index 0635e8639..0e675b1b4 100644 --- a/src/messages/message.cpp +++ b/src/messages/message.cpp @@ -7,6 +7,7 @@ #include "ircmanager.hpp" #include "messages/link.hpp" #include "resources.hpp" +#include "util/irchelpers.hpp" #include #include @@ -70,5 +71,83 @@ const QString &Message::getId() const return this->id; } +namespace { + +void AddCurrentTimestamp(Message *message) +{ + std::time_t t; + time(&t); + char timeStampBuffer[69]; + + // Add word for timestamp with no seconds + strftime(timeStampBuffer, 69, "%H:%M", localtime(&t)); + QString timestampNoSeconds(timeStampBuffer); + message->getWords().push_back(Word(timestampNoSeconds, Word::TimestampNoSeconds, + MessageColor(MessageColor::System), QString(), QString())); + + // Add word for timestamp with seconds + strftime(timeStampBuffer, 69, "%H:%M:%S", localtime(&t)); + QString timestampWithSeconds(timeStampBuffer); + message->getWords().push_back(Word(timestampWithSeconds, Word::TimestampWithSeconds, + MessageColor(MessageColor::System), QString(), QString())); +} + +} // namespace + +/// Static +Message *Message::createSystemMessage(const QString &text) +{ + Message *message = new Message; + + AddCurrentTimestamp(message); + + Word word(text, Word::Type::Default, MessageColor(MessageColor::Type::System), text, text); + + message->getWords().push_back(word); + + return message; +} + +Message *Message::createTimeoutMessage(const QString &username, const QString &durationInSeconds, + const QString &reason) +{ + Message *message = new Message; + + AddCurrentTimestamp(message); + + QString text; + + text.append(username); + if (!durationInSeconds.isEmpty()) { + text.append(" has been timed out"); + + // TODO: Implement who timed the user out + + text.append(" for "); + text.append(durationInSeconds); + bool ok = true; + int timeoutDuration = durationInSeconds.toInt(&ok); + text.append(" second"); + if (ok && timeoutDuration > 1) { + text.append("s"); + } + } else { + text.append(" has been permanently banned"); + } + + if (reason.length() > 0) { + text.append(": \""); + text.append(ParseTagString(reason)); + text.append("\""); + } + text.append("."); + + Word word(text, Word::Type::Default, MessageColor(MessageColor::Type::System), text, text); + + message->getWords().push_back(word); + + return message; +} + } // namespace messages } // namespace chatterino diff --git a/src/messages/message.hpp b/src/messages/message.hpp index 349ee3cb3..cb49366f3 100644 --- a/src/messages/message.hpp +++ b/src/messages/message.hpp @@ -33,6 +33,11 @@ public: const QString text; bool centered = false; + static Message *createSystemMessage(const QString &text); + + static Message *createTimeoutMessage(const QString &username, const QString &durationInSeconds, + const QString &reason); + private: static LazyLoadedImage *badgeStaff; static LazyLoadedImage *badgeAdmin; diff --git a/src/messages/messagecolor.cpp b/src/messages/messagecolor.cpp index 387c1da64..135d0298a 100644 --- a/src/messages/messagecolor.cpp +++ b/src/messages/messagecolor.cpp @@ -2,6 +2,7 @@ namespace chatterino { namespace messages { + MessageColor::MessageColor(const QColor &_color) : type(Type::Custom) , color(_color) @@ -34,5 +35,6 @@ const QColor &MessageColor::getColor(ColorScheme &colorScheme) const static QColor _default; return _default; } -} -} + +} // namespace messages +} // namespace chatterino diff --git a/src/messages/messagecolor.hpp b/src/messages/messagecolor.hpp index 3ea078861..48079f9c7 100644 --- a/src/messages/messagecolor.hpp +++ b/src/messages/messagecolor.hpp @@ -6,6 +6,7 @@ namespace chatterino { namespace messages { + class MessageColor { public: @@ -21,5 +22,6 @@ private: Type type; QColor color; }; -} -} + +} // namespace messages +} // namespace chatterino diff --git a/src/util/irchelpers.hpp b/src/util/irchelpers.hpp new file mode 100644 index 000000000..c8ba28488 --- /dev/null +++ b/src/util/irchelpers.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace chatterino { + +QString ParseTagString(const QString &input) +{ + QString output = input; + + // code goes here + + return output; +} + +} // namespace chatterino diff --git a/src/util/urlfetch.hpp b/src/util/urlfetch.hpp index a7ebe4c1e..f322a2382 100644 --- a/src/util/urlfetch.hpp +++ b/src/util/urlfetch.hpp @@ -87,11 +87,18 @@ static void put(QUrl url, std::function successCallback) auto manager = new QNetworkAccessManager(); QNetworkRequest request(url); + auto &accountManager = AccountManager::getInstance(); + auto currentTwitchUser = accountManager.Twitch.getCurrent(); + QByteArray oauthToken; + if (currentTwitchUser) { + oauthToken = currentTwitchUser->getOAuthToken().toUtf8(); + } else { + // XXX(pajlada): Bail out? + } + request.setRawHeader("Client-ID", getDefaultClientID()); request.setRawHeader("Accept", "application/vnd.twitchtv.v5+json"); - request.setRawHeader( - "Authorization", - "OAuth " + AccountManager::getInstance().getTwitchUser().getOAuthToken().toUtf8()); + request.setRawHeader("Authorization", "OAuth " + oauthToken); NetworkManager::urlPut(std::move(request), [=](QNetworkReply *reply) { if (reply->error() == QNetworkReply::NetworkError::NoError) { diff --git a/src/widgets/accountpopup.cpp b/src/widgets/accountpopup.cpp index d87f987ba..bb0df02ee 100644 --- a/src/widgets/accountpopup.cpp +++ b/src/widgets/accountpopup.cpp @@ -1,10 +1,10 @@ #include "widgets/accountpopup.hpp" -#include "util/urlfetch.hpp" #include "accountmanager.hpp" #include "channel.hpp" #include "credentials.hpp" #include "settingsmanager.hpp" #include "ui_accountpopupform.h" +#include "util/urlfetch.hpp" #include #include @@ -32,20 +32,16 @@ AccountPopupWidget::AccountPopupWidget(std::shared_ptr channel) SettingsManager &settings = SettingsManager::getInstance(); permission = permissions::User; - for(auto button : this->_ui->profileLayout->findChildren()) - { + for (auto button : this->_ui->profileLayout->findChildren()) { button->setFocusProxy(this); } - for(auto button: this->_ui->userLayout->findChildren()) - { + for (auto button : this->_ui->userLayout->findChildren()) { button->setFocusProxy(this); } - for(auto button: this->_ui->modLayout->findChildren()) - { + for (auto button : this->_ui->modLayout->findChildren()) { button->setFocusProxy(this); } - for(auto button: this->_ui->ownerLayout->findChildren()) - { + for (auto button : this->_ui->ownerLayout->findChildren()) { button->setFocusProxy(this); } @@ -60,41 +56,42 @@ AccountPopupWidget::AccountPopupWidget(std::shared_ptr channel) sendCommand(this->_ui->mod, "/mod "); sendCommand(this->_ui->unMod, "/unmod "); - QObject::connect(this->_ui->profile, &QPushButton::clicked, this, [=](){ - QDesktopServices::openUrl(QUrl("https://twitch.tv/" + - this->_ui->lblUsername->text())); + auto &accountManager = AccountManager::getInstance(); + QString userId; + QString userNickname; + auto currentTwitchUser = accountManager.Twitch.getCurrent(); + if (currentTwitchUser) { + userId = currentTwitchUser->getUserId(); + userNickname = currentTwitchUser->getNickName(); + } + + QObject::connect(this->_ui->profile, &QPushButton::clicked, this, [=]() { + QDesktopServices::openUrl(QUrl("https://twitch.tv/" + this->_ui->lblUsername->text())); }); - QObject::connect(this->_ui->sendMessage, &QPushButton::clicked, this, [=](){ - QDesktopServices::openUrl(QUrl("https://www.twitch.tv/message/compose?to=" + - this->_ui->lblUsername->text())); + QObject::connect(this->_ui->sendMessage, &QPushButton::clicked, this, [=]() { + QDesktopServices::openUrl( + QUrl("https://www.twitch.tv/message/compose?to=" + this->_ui->lblUsername->text())); }); - QObject::connect(this->_ui->copy, &QPushButton::clicked, this, [=](){ - QApplication::clipboard()->setText(this->_ui->lblUsername->text()); + QObject::connect(this->_ui->copy, &QPushButton::clicked, this, + [=]() { QApplication::clipboard()->setText(this->_ui->lblUsername->text()); }); + + QObject::connect(this->_ui->follow, &QPushButton::clicked, this, [=]() { + QUrl requestUrl("https://api.twitch.tv/kraken/users/" + userId + "/follows/channels/" + + this->userID); + + util::twitch::put(requestUrl, + [](QJsonObject obj) { qDebug() << "follows channel: " << obj; }); }); - QObject::connect(this->_ui->follow, &QPushButton::clicked, this, [=](){ - QUrl requestUrl("https://api.twitch.tv/kraken/users/" + - AccountManager::getInstance().getTwitchUser().getUserId() + - "/follows/channels/" + this->userID); + QObject::connect(this->_ui->ignore, &QPushButton::clicked, this, [=]() { + QUrl requestUrl("https://api.twitch.tv/kraken/users/" + userId + "/blocks/" + this->userID); - util::twitch::put(requestUrl,[](QJsonObject obj){ - qDebug() << "follows channel: " << obj; - }); + util::twitch::put(requestUrl, [](QJsonObject obj) { qDebug() << "blocks user: " << obj; }); }); - QObject::connect(this->_ui->ignore, &QPushButton::clicked, this, [=](){ - QUrl requestUrl("https://api.twitch.tv/kraken/users/" + - AccountManager::getInstance().getTwitchUser().getUserId() + - "/blocks/" + this->userID); - - util::twitch::put(requestUrl,[](QJsonObject obj){ - qDebug() << "blocks user: " << obj; - }); - }); - - QObject::connect(this->_ui->disableHighlights, &QPushButton::clicked, this, [=, &settings](){ + QObject::connect(this->_ui->disableHighlights, &QPushButton::clicked, this, [=, &settings]() { QString str = settings.highlightUserBlacklist.getnonConst(); str.append(this->_ui->lblUsername->text() + "\n"); settings.highlightUserBlacklist.set(str); @@ -102,7 +99,7 @@ AccountPopupWidget::AccountPopupWidget(std::shared_ptr channel) this->_ui->enableHighlights->show(); }); - QObject::connect(this->_ui->enableHighlights, &QPushButton::clicked, this, [=, &settings](){ + QObject::connect(this->_ui->enableHighlights, &QPushButton::clicked, this, [=, &settings]() { QString str = settings.highlightUserBlacklist.getnonConst(); QStringList list = str.split("\n"); list.removeAll(this->_ui->lblUsername->text()); @@ -111,20 +108,17 @@ AccountPopupWidget::AccountPopupWidget(std::shared_ptr channel) this->_ui->disableHighlights->show(); }); - - updateButtons(this->_ui->userLayout,false); - updateButtons(this->_ui->modLayout,false); - updateButtons(this->_ui->ownerLayout,false); + updateButtons(this->_ui->userLayout, false); + updateButtons(this->_ui->modLayout, false); + updateButtons(this->_ui->ownerLayout, false); // Close button connect(_ui->btnClose, &QPushButton::clicked, [=]() { hide(); // }); - util::twitch::getUserID(AccountManager::getInstance().getTwitchUser().getNickName(), this, - [=](const QString &id){ - AccountManager::getInstance().getTwitchUser().setUserId(id); - }); + util::twitch::getUserID(userNickname, this, + [=](const QString &id) { currentTwitchUser->setUserId(id); }); } void AccountPopupWidget::setName(const QString &name) @@ -140,7 +134,7 @@ void AccountPopupWidget::setChannel(std::shared_ptr channel) void AccountPopupWidget::getUserId() { - util::twitch::getUserID(this->_ui->lblUsername->text(), this, [=](const QString &id){ + util::twitch::getUserID(this->_ui->lblUsername->text(), this, [=](const QString &id) { userID = id; getUserData(); }); @@ -148,13 +142,14 @@ void AccountPopupWidget::getUserId() void AccountPopupWidget::getUserData() { - util::twitch::get("https://api.twitch.tv/kraken/channels/" + userID, this, [=](const QJsonObject &obj){ - _ui->lblFollowers->setText(QString::number(obj.value("followers").toInt())); - _ui->lblViews->setText(QString::number(obj.value("views").toInt())); - _ui->lblAccountAge->setText(obj.value("created_at").toString().section("T", 0, 0)); + util::twitch::get( + "https://api.twitch.tv/kraken/channels/" + userID, this, [=](const QJsonObject &obj) { + _ui->lblFollowers->setText(QString::number(obj.value("followers").toInt())); + _ui->lblViews->setText(QString::number(obj.value("views").toInt())); + _ui->lblAccountAge->setText(obj.value("created_at").toString().section("T", 0, 0)); - loadAvatar(QUrl(obj.value("logo").toString())); - }); + loadAvatar(QUrl(obj.value("logo").toString())); + }); } void AccountPopupWidget::loadAvatar(const QUrl &avatarUrl) @@ -185,35 +180,40 @@ void AccountPopupWidget::loadAvatar(const QUrl &avatarUrl) void AccountPopupWidget::updatePermissions() { - if(this->_channel.get()->name == AccountManager::getInstance().getTwitchUser().getNickName()) - { - permission = permissions::Owner; + AccountManager &accountManager = AccountManager::getInstance(); + auto currentTwitchUser = accountManager.Twitch.getCurrent(); + if (!currentTwitchUser) { + // No twitch user set (should never happen) + return; } - else if(this->_channel->modList.contains(AccountManager::getInstance().getTwitchUser().getNickName())) - { + + if (this->_channel.get()->name == currentTwitchUser->getNickName()) { + permission = permissions::Owner; + } else if (this->_channel->modList.contains(currentTwitchUser->getNickName())) { + // XXX(pajlada): This might always trigger if user is anonymous (if nickName is empty?) permission = permissions::Mod; } } -void AccountPopupWidget::updateButtons(QWidget* layout, bool state) +void AccountPopupWidget::updateButtons(QWidget *layout, bool state) { - for(auto button : layout->findChildren()) - { + for (auto button : layout->findChildren()) { button->setVisible(state); } } void AccountPopupWidget::timeout(QPushButton *button, int time) { - QObject::connect(button, &QPushButton::clicked, this, [=](){ - this->_channel->sendMessage("/timeout " + this->_ui->lblUsername->text() + " " + QString::number(time)); + QObject::connect(button, &QPushButton::clicked, this, [=]() { + this->_channel->sendMessage("/timeout " + this->_ui->lblUsername->text() + " " + + QString::number(time)); }); } void AccountPopupWidget::sendCommand(QPushButton *button, QString command) { - QObject::connect(button, &QPushButton::clicked, this, [=](){ - this->_channel->sendMessage(command + this->_ui->lblUsername->text()); + QObject::connect(button, &QPushButton::clicked, this, [=]() { + this->_channel->sendMessage(command + this->_ui->lblUsername->text()); }); } @@ -229,42 +229,39 @@ void AccountPopupWidget::focusOutEvent(QFocusEvent *event) void AccountPopupWidget::showEvent(QShowEvent *event) { - if(this->_ui->lblUsername->text() != AccountManager::getInstance().getTwitchUser().getNickName()) - { + AccountManager &accountManager = AccountManager::getInstance(); + auto currentTwitchUser = accountManager.Twitch.getCurrent(); + if (!currentTwitchUser) { + // No twitch user set (should never happen) + return; + } + + if (this->_ui->lblUsername->text() != currentTwitchUser->getNickName()) { updateButtons(this->_ui->userLayout, true); - if(permission != permissions::User) - { - if(!this->_channel->modList.contains(this->_ui->lblUsername->text())) - { + if (permission != permissions::User) { + if (!this->_channel->modList.contains(this->_ui->lblUsername->text())) { updateButtons(this->_ui->modLayout, true); } - if(permission == permissions::Owner) - { + if (permission == permissions::Owner) { updateButtons(this->_ui->ownerLayout, true); updateButtons(this->_ui->modLayout, true); } } - } - else - { + } else { updateButtons(this->_ui->modLayout, false); updateButtons(this->_ui->userLayout, false); updateButtons(this->_ui->ownerLayout, false); } QString blacklisted = SettingsManager::getInstance().highlightUserBlacklist.getnonConst(); - QStringList list = blacklisted.split("\n",QString::SkipEmptyParts); - if(list.contains(this->_ui->lblUsername->text(),Qt::CaseInsensitive)) - { + QStringList list = blacklisted.split("\n", QString::SkipEmptyParts); + if (list.contains(this->_ui->lblUsername->text(), Qt::CaseInsensitive)) { this->_ui->disableHighlights->hide(); this->_ui->enableHighlights->show(); - } - else - { + } else { this->_ui->disableHighlights->show(); this->_ui->enableHighlights->hide(); } - } } // namespace widgets diff --git a/src/widgets/accountpopup.hpp b/src/widgets/accountpopup.hpp index 8b89ab184..e5eee9cb8 100644 --- a/src/widgets/accountpopup.hpp +++ b/src/widgets/accountpopup.hpp @@ -1,4 +1,5 @@ #pragma once + #include "concurrentmap.hpp" #include "twitch/twitchchannel.hpp" @@ -35,9 +36,9 @@ private: void getUserData(); void loadAvatar(const QUrl &avatarUrl); - void updateButtons(QWidget* layout, bool state); - void timeout(QPushButton* button, int time); - void sendCommand(QPushButton* button, QString command); + void updateButtons(QWidget *layout, bool state); + void timeout(QPushButton *button, int time); + void sendCommand(QPushButton *button, QString command); enum class permissions { User, Mod, Owner }; permissions permission; diff --git a/src/widgets/helper/channelview.cpp b/src/widgets/helper/channelview.cpp index e93fc703d..4e7d94fe0 100644 --- a/src/widgets/helper/channelview.cpp +++ b/src/widgets/helper/channelview.cpp @@ -802,7 +802,7 @@ void ChannelView::mouseReleaseEvent(QMouseEvent *event) float distance = util::distanceBetweenPoints(this->lastPressPosition, event->screenPos()); - qDebug() << "Distance: " << distance; + // qDebug() << "Distance: " << distance; if (fabsf(distance) > 15.f) { // It wasn't a proper click, so we don't care about that here diff --git a/src/widgets/settingsdialog.cpp b/src/widgets/settingsdialog.cpp index 583d39ae5..75e234b67 100644 --- a/src/widgets/settingsdialog.cpp +++ b/src/widgets/settingsdialog.cpp @@ -129,13 +129,14 @@ QVBoxLayout *SettingsDialog::createAccountsTab() // listview auto listWidget = new QListWidget(this); - for (auto &user : AccountManager::getInstance().getTwitchUsers()) { - listWidget->addItem(user.getUserName()); + for (const auto &userName : AccountManager::getInstance().Twitch.getUsernames()) { + listWidget->addItem(userName); } + // Select the currently logged in user if (listWidget->count() > 0) { - const auto ¤tUser = AccountManager::getInstance().getTwitchUser(); - QString currentUsername = currentUser.getUserName(); + const QString ¤tUsername = + AccountManager::getInstance().Twitch.getCurrent()->getUserName(); for (int i = 0; i < listWidget->count(); ++i) { QString itemText = listWidget->item(i)->text(); if (itemText.compare(currentUsername, Qt::CaseInsensitive) == 0) { @@ -147,7 +148,8 @@ QVBoxLayout *SettingsDialog::createAccountsTab() QObject::connect(listWidget, &QListWidget::clicked, this, [&, listWidget] { if (!listWidget->selectedItems().isEmpty()) { - AccountManager::getInstance().setCurrentTwitchUser(listWidget->currentItem()->text()); + QString newUsername = listWidget->currentItem()->text(); + AccountManager::getInstance().Twitch.currentUsername = newUsername.toStdString(); } }); diff --git a/src/widgets/split.cpp b/src/widgets/split.cpp index 627079653..252c00e80 100644 --- a/src/widgets/split.cpp +++ b/src/widgets/split.cpp @@ -79,15 +79,10 @@ Split::Split(ChannelManager &_channelManager, SplitContainer *parent) ezShortcut(this, "CTRL+R", &Split::doChangeChannel); // xd - //ezShortcut(this, "ALT+SHIFT+RIGHT", &Split::doIncFlexX); - //ezShortcut(this, "ALT+SHIFT+LEFT", &Split::doDecFlexX); - //ezShortcut(this, "ALT+SHIFT+UP", &Split::doIncFlexY); - //ezShortcut(this, "ALT+SHIFT+DOWN", &Split::doDecFlexY); - -#ifndef NDEBUG - // F12: Toggle message spawning - ezShortcut(this, "ALT+Q", &Split::doToggleMessageSpawning); -#endif + // ezShortcut(this, "ALT+SHIFT+RIGHT", &Split::doIncFlexX); + // ezShortcut(this, "ALT+SHIFT+LEFT", &Split::doDecFlexX); + // ezShortcut(this, "ALT+SHIFT+UP", &Split::doIncFlexY); + // ezShortcut(this, "ALT+SHIFT+DOWN", &Split::doDecFlexY); this->channelName.getValueChangedSignal().connect( std::bind(&Split::channelNameUpdated, this, std::placeholders::_1)); @@ -102,10 +97,6 @@ Split::Split(ChannelManager &_channelManager, SplitContainer *parent) this->input.clearSelection(); } }); - - QTimer *timer = new QTimer(this); - connect(timer, &QTimer::timeout, this, &Split::test); - timer->start(1000); } Split::~Split() @@ -462,30 +453,6 @@ void Split::doCopy() QApplication::clipboard()->setText(this->view.getSelectedText()); } -static std::vector usernameVariants = { - "pajlada", // - "trump", // - "Chancu", // - "pajaWoman", // - "fourtf", // - "weneedmoreautisticbots", // - "fourtfbot", // - "pajbot", // - "snusbot", // -}; - -static std::vector messageVariants = { - "hehe", // - "lol pajlada", // - "hehe BANNEDWORD", // - "someone ordered pizza", // - "for ice poseidon", // - "and delivery guy said it is for enza denino", // - "!gn", // - "for my laptop", // - "should I buy a Herschel backpack?", // -}; - template static Iter select_randomly(Iter start, Iter end, RandomGenerator &g) { @@ -502,41 +469,6 @@ static Iter select_randomly(Iter start, Iter end) return select_randomly(start, end, gen); } -void Split::test() -{ - if (this->testEnabled) { - messages::MessageParseArgs args; - - auto message = - new Communi::IrcPrivateMessage(this->channelManager.ircManager.readConnection.get()); - - std::string text = *(select_randomly(messageVariants.begin(), messageVariants.end())); - std::string username = *(select_randomly(usernameVariants.begin(), usernameVariants.end())); - std::string usernameString = username + "!" + username + "@" + username; - - QStringList params{"#pajlada", text.c_str()}; - - qDebug() << params; - - message->setParameters(params); - - message->setPrefix(usernameString.c_str()); - - auto twitchChannel = std::dynamic_pointer_cast(this->channel); - - twitch::TwitchMessageBuilder builder( - twitchChannel.get(), this->channelManager.ircManager.resources, - this->channelManager.emoteManager, this->channelManager.windowManager, message, args); - - twitchChannel->addMessage(builder.parse()); - } -} - -void Split::doToggleMessageSpawning() -{ - this->testEnabled = !this->testEnabled; -} - void Split::doIncFlexX() { this->setFlexSizeX(this->getFlexSizeX() * 1.2); diff --git a/src/widgets/split.hpp b/src/widgets/split.hpp index 8987ce54d..31b0eef35 100644 --- a/src/widgets/split.hpp +++ b/src/widgets/split.hpp @@ -52,7 +52,6 @@ public: CompletionManager &completionManager; pajlada::Settings::Setting channelName; boost::signals2::signal channelChanged; - bool testEnabled = false; std::shared_ptr getChannel() const; std::shared_ptr &getChannelRef(); @@ -122,8 +121,6 @@ public slots: // Open viewer list of the channel void doOpenViewerList(); - void doToggleMessageSpawning(); - void test(); void doIncFlexX(); void doDecFlexX(); void doIncFlexY();