mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Fix signal connection nodiscard warnings (#4818)
This commit is contained in:
parent
2d5f078306
commit
8fe3af3522
40 changed files with 709 additions and 554 deletions
|
@ -17,6 +17,7 @@
|
||||||
- Dev: Fix clang-tidy `cppcoreguidelines-pro-type-member-init` warnings. (#4426)
|
- Dev: Fix clang-tidy `cppcoreguidelines-pro-type-member-init` warnings. (#4426)
|
||||||
- Dev: Immediate layout for invisible `ChannelView`s is skipped. (#4811)
|
- Dev: Immediate layout for invisible `ChannelView`s is skipped. (#4811)
|
||||||
- Dev: Refactor `Image` & Image's `Frames`. (#4773)
|
- Dev: Refactor `Image` & Image's `Frames`. (#4773)
|
||||||
|
- Dev: Clarify signal connection lifetimes where applicable. (#4818)
|
||||||
|
|
||||||
## 2.4.5
|
## 2.4.5
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,9 @@ Application::Application(Settings &_settings, Paths &_paths)
|
||||||
{
|
{
|
||||||
this->instance = this;
|
this->instance = this;
|
||||||
|
|
||||||
this->fonts->fontChanged.connect([this]() {
|
// We can safely ignore this signal's connection since the Application will always
|
||||||
|
// be destroyed after fonts
|
||||||
|
std::ignore = this->fonts->fontChanged.connect([this]() {
|
||||||
this->windows->layoutChannelViews();
|
this->windows->layoutChannelViews();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -188,13 +190,20 @@ int Application::run(QApplication &qtApp)
|
||||||
Updates::instance().checkForUpdates();
|
Updates::instance().checkForUpdates();
|
||||||
},
|
},
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
// We can safely ignore the signal connections since Application will always live longer than
|
||||||
|
// everything else, including settings. right?
|
||||||
|
// NOTE: SETTINGS_LIFETIME
|
||||||
|
std::ignore =
|
||||||
getSettings()->moderationActions.delayedItemsChanged.connect([this] {
|
getSettings()->moderationActions.delayedItemsChanged.connect([this] {
|
||||||
this->windows->forceLayoutChannelViews();
|
this->windows->forceLayoutChannelViews();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::ignore =
|
||||||
getSettings()->highlightedMessages.delayedItemsChanged.connect([this] {
|
getSettings()->highlightedMessages.delayedItemsChanged.connect([this] {
|
||||||
this->windows->forceLayoutChannelViews();
|
this->windows->forceLayoutChannelViews();
|
||||||
});
|
});
|
||||||
|
std::ignore =
|
||||||
getSettings()->highlightedUsers.delayedItemsChanged.connect([this] {
|
getSettings()->highlightedUsers.delayedItemsChanged.connect([this] {
|
||||||
this->windows->forceLayoutChannelViews();
|
this->windows->forceLayoutChannelViews();
|
||||||
});
|
});
|
||||||
|
@ -279,7 +288,9 @@ void Application::initNm(Paths &paths)
|
||||||
|
|
||||||
void Application::initPubSub()
|
void Application::initPubSub()
|
||||||
{
|
{
|
||||||
this->twitch->pubsub->signals_.moderation.chatCleared.connect(
|
// We can safely ignore these signal connections since the twitch object will always
|
||||||
|
// be destroyed before the Application
|
||||||
|
std::ignore = this->twitch->pubsub->signals_.moderation.chatCleared.connect(
|
||||||
[this](const auto &action) {
|
[this](const auto &action) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
||||||
if (chan->isEmpty())
|
if (chan->isEmpty())
|
||||||
|
@ -296,7 +307,7 @@ void Application::initPubSub()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this->twitch->pubsub->signals_.moderation.modeChanged.connect(
|
std::ignore = this->twitch->pubsub->signals_.moderation.modeChanged.connect(
|
||||||
[this](const auto &action) {
|
[this](const auto &action) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
||||||
if (chan->isEmpty())
|
if (chan->isEmpty())
|
||||||
|
@ -322,8 +333,9 @@ void Application::initPubSub()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this->twitch->pubsub->signals_.moderation.moderationStateChanged.connect(
|
std::ignore =
|
||||||
[this](const auto &action) {
|
this->twitch->pubsub->signals_.moderation.moderationStateChanged
|
||||||
|
.connect([this](const auto &action) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
||||||
if (chan->isEmpty())
|
if (chan->isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -343,7 +355,7 @@ void Application::initPubSub()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this->twitch->pubsub->signals_.moderation.userBanned.connect(
|
std::ignore = this->twitch->pubsub->signals_.moderation.userBanned.connect(
|
||||||
[&](const auto &action) {
|
[&](const auto &action) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
||||||
|
|
||||||
|
@ -358,6 +370,7 @@ void Application::initPubSub()
|
||||||
chan->addOrReplaceTimeout(msg.release());
|
chan->addOrReplaceTimeout(msg.release());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
std::ignore =
|
||||||
this->twitch->pubsub->signals_.moderation.messageDeleted.connect(
|
this->twitch->pubsub->signals_.moderation.messageDeleted.connect(
|
||||||
[&](const auto &action) {
|
[&](const auto &action) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
||||||
|
@ -398,6 +411,7 @@ void Application::initPubSub()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::ignore =
|
||||||
this->twitch->pubsub->signals_.moderation.userUnbanned.connect(
|
this->twitch->pubsub->signals_.moderation.userUnbanned.connect(
|
||||||
[&](const auto &action) {
|
[&](const auto &action) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
||||||
|
@ -414,6 +428,7 @@ void Application::initPubSub()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::ignore =
|
||||||
this->twitch->pubsub->signals_.moderation.autoModMessageCaught.connect(
|
this->twitch->pubsub->signals_.moderation.autoModMessageCaught.connect(
|
||||||
[&](const auto &msg, const QString &channelID) {
|
[&](const auto &msg, const QString &channelID) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(channelID);
|
auto chan = this->twitch->getChannelOrEmptyByID(channelID);
|
||||||
|
@ -424,7 +439,8 @@ void Application::initPubSub()
|
||||||
|
|
||||||
switch (msg.type)
|
switch (msg.type)
|
||||||
{
|
{
|
||||||
case PubSubAutoModQueueMessage::Type::AutoModCaughtMessage: {
|
case PubSubAutoModQueueMessage::Type::
|
||||||
|
AutoModCaughtMessage: {
|
||||||
if (msg.status == "PENDING")
|
if (msg.status == "PENDING")
|
||||||
{
|
{
|
||||||
AutomodAction action(msg.data, channelID);
|
AutomodAction action(msg.data, channelID);
|
||||||
|
@ -461,7 +477,8 @@ void Application::initPubSub()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle username style based on prefered setting
|
// handle username style based on prefered setting
|
||||||
switch (getSettings()->usernameDisplayMode.getValue())
|
switch (
|
||||||
|
getSettings()->usernameDisplayMode.getValue())
|
||||||
{
|
{
|
||||||
case UsernameDisplayMode::Username: {
|
case UsernameDisplayMode::Username: {
|
||||||
if (hasLocalizedName)
|
if (hasLocalizedName)
|
||||||
|
@ -477,7 +494,8 @@ void Application::initPubSub()
|
||||||
UsernameAndLocalizedName: {
|
UsernameAndLocalizedName: {
|
||||||
if (hasLocalizedName)
|
if (hasLocalizedName)
|
||||||
{
|
{
|
||||||
senderDisplayName = QString("%1(%2)").arg(
|
senderDisplayName =
|
||||||
|
QString("%1(%2)").arg(
|
||||||
msg.senderUserLogin,
|
msg.senderUserLogin,
|
||||||
msg.senderUserDisplayName);
|
msg.senderUserDisplayName);
|
||||||
}
|
}
|
||||||
|
@ -485,8 +503,8 @@ void Application::initPubSub()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action.target =
|
action.target = ActionUser{
|
||||||
ActionUser{msg.senderUserID, msg.senderUserLogin,
|
msg.senderUserID, msg.senderUserLogin,
|
||||||
senderDisplayName, senderColor};
|
senderDisplayName, senderColor};
|
||||||
postToThread([chan, action] {
|
postToThread([chan, action] {
|
||||||
const auto p = makeAutomodMessage(action);
|
const auto p = makeAutomodMessage(action);
|
||||||
|
@ -506,6 +524,7 @@ void Application::initPubSub()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::ignore =
|
||||||
this->twitch->pubsub->signals_.moderation.autoModMessageBlocked.connect(
|
this->twitch->pubsub->signals_.moderation.autoModMessageBlocked.connect(
|
||||||
[&](const auto &action) {
|
[&](const auto &action) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
||||||
|
@ -521,11 +540,13 @@ void Application::initPubSub()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::ignore =
|
||||||
this->twitch->pubsub->signals_.moderation.automodUserMessage.connect(
|
this->twitch->pubsub->signals_.moderation.automodUserMessage.connect(
|
||||||
[&](const auto &action) {
|
[&](const auto &action) {
|
||||||
// This condition has been set up to execute isInStreamerMode() as the last thing
|
// This condition has been set up to execute isInStreamerMode() as the last thing
|
||||||
// as it could end up being expensive.
|
// as it could end up being expensive.
|
||||||
if (getSettings()->streamerModeHideModActions && isInStreamerMode())
|
if (getSettings()->streamerModeHideModActions &&
|
||||||
|
isInStreamerMode())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -544,6 +565,7 @@ void Application::initPubSub()
|
||||||
chan->deleteMessage(msg->id);
|
chan->deleteMessage(msg->id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::ignore =
|
||||||
this->twitch->pubsub->signals_.moderation.automodInfoMessage.connect(
|
this->twitch->pubsub->signals_.moderation.automodInfoMessage.connect(
|
||||||
[&](const auto &action) {
|
[&](const auto &action) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
auto chan = this->twitch->getChannelOrEmptyByID(action.roomID);
|
||||||
|
@ -559,7 +581,7 @@ void Application::initPubSub()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this->twitch->pubsub->signals_.pointReward.redeemed.connect(
|
std::ignore = this->twitch->pubsub->signals_.pointReward.redeemed.connect(
|
||||||
[&](auto &data) {
|
[&](auto &data) {
|
||||||
QString channelId = data.value("channel_id").toString();
|
QString channelId = data.value("channel_id").toString();
|
||||||
if (channelId.isEmpty())
|
if (channelId.isEmpty())
|
||||||
|
@ -614,7 +636,9 @@ void Application::initBttvLiveUpdates()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->twitch->bttvLiveUpdates->signals_.emoteAdded.connect(
|
// We can safely ignore these signal connections since the twitch object will always
|
||||||
|
// be destroyed before the Application
|
||||||
|
std::ignore = this->twitch->bttvLiveUpdates->signals_.emoteAdded.connect(
|
||||||
[&](const auto &data) {
|
[&](const auto &data) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(data.channelID);
|
auto chan = this->twitch->getChannelOrEmptyByID(data.channelID);
|
||||||
|
|
||||||
|
@ -625,7 +649,7 @@ void Application::initBttvLiveUpdates()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this->twitch->bttvLiveUpdates->signals_.emoteUpdated.connect(
|
std::ignore = this->twitch->bttvLiveUpdates->signals_.emoteUpdated.connect(
|
||||||
[&](const auto &data) {
|
[&](const auto &data) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(data.channelID);
|
auto chan = this->twitch->getChannelOrEmptyByID(data.channelID);
|
||||||
|
|
||||||
|
@ -636,7 +660,7 @@ void Application::initBttvLiveUpdates()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this->twitch->bttvLiveUpdates->signals_.emoteRemoved.connect(
|
std::ignore = this->twitch->bttvLiveUpdates->signals_.emoteRemoved.connect(
|
||||||
[&](const auto &data) {
|
[&](const auto &data) {
|
||||||
auto chan = this->twitch->getChannelOrEmptyByID(data.channelID);
|
auto chan = this->twitch->getChannelOrEmptyByID(data.channelID);
|
||||||
|
|
||||||
|
@ -659,7 +683,9 @@ void Application::initSeventvEventAPI()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->twitch->seventvEventAPI->signals_.emoteAdded.connect(
|
// We can safely ignore these signal connections since the twitch object will always
|
||||||
|
// be destroyed before the Application
|
||||||
|
std::ignore = this->twitch->seventvEventAPI->signals_.emoteAdded.connect(
|
||||||
[&](const auto &data) {
|
[&](const auto &data) {
|
||||||
postToThread([this, data] {
|
postToThread([this, data] {
|
||||||
this->twitch->forEachSeventvEmoteSet(
|
this->twitch->forEachSeventvEmoteSet(
|
||||||
|
@ -668,7 +694,7 @@ void Application::initSeventvEventAPI()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this->twitch->seventvEventAPI->signals_.emoteUpdated.connect(
|
std::ignore = this->twitch->seventvEventAPI->signals_.emoteUpdated.connect(
|
||||||
[&](const auto &data) {
|
[&](const auto &data) {
|
||||||
postToThread([this, data] {
|
postToThread([this, data] {
|
||||||
this->twitch->forEachSeventvEmoteSet(
|
this->twitch->forEachSeventvEmoteSet(
|
||||||
|
@ -677,7 +703,7 @@ void Application::initSeventvEventAPI()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this->twitch->seventvEventAPI->signals_.emoteRemoved.connect(
|
std::ignore = this->twitch->seventvEventAPI->signals_.emoteRemoved.connect(
|
||||||
[&](const auto &data) {
|
[&](const auto &data) {
|
||||||
postToThread([this, data] {
|
postToThread([this, data] {
|
||||||
this->twitch->forEachSeventvEmoteSet(
|
this->twitch->forEachSeventvEmoteSet(
|
||||||
|
@ -686,7 +712,7 @@ void Application::initSeventvEventAPI()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this->twitch->seventvEventAPI->signals_.userUpdated.connect(
|
std::ignore = this->twitch->seventvEventAPI->signals_.userUpdated.connect(
|
||||||
[&](const auto &data) {
|
[&](const auto &data) {
|
||||||
this->twitch->forEachSeventvUser(data.userID,
|
this->twitch->forEachSeventvUser(data.userID,
|
||||||
[data](TwitchChannel &chan) {
|
[data](TwitchChannel &chan) {
|
||||||
|
|
|
@ -106,7 +106,7 @@ void Channel::addMessage(MessagePtr message,
|
||||||
|
|
||||||
if (this->messages_.pushBack(message, deleted))
|
if (this->messages_.pushBack(message, deleted))
|
||||||
{
|
{
|
||||||
this->messageRemovedFromStart.invoke(deleted);
|
this->messageRemovedFromStart(deleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->messageAppended.invoke(message, overridingFlags);
|
this->messageAppended.invoke(message, overridingFlags);
|
||||||
|
@ -353,6 +353,10 @@ void Channel::onConnected()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Channel::messageRemovedFromStart(const MessagePtr &msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Indirect channel
|
// Indirect channel
|
||||||
//
|
//
|
||||||
|
|
|
@ -52,7 +52,6 @@ public:
|
||||||
pajlada::Signals::Signal<const QString &, const QString &, const QString &,
|
pajlada::Signals::Signal<const QString &, const QString &, const QString &,
|
||||||
bool &>
|
bool &>
|
||||||
sendReplySignal;
|
sendReplySignal;
|
||||||
pajlada::Signals::Signal<MessagePtr &> messageRemovedFromStart;
|
|
||||||
pajlada::Signals::Signal<MessagePtr &, boost::optional<MessageFlags>>
|
pajlada::Signals::Signal<MessagePtr &, boost::optional<MessageFlags>>
|
||||||
messageAppended;
|
messageAppended;
|
||||||
pajlada::Signals::Signal<std::vector<MessagePtr> &> messagesAddedAtStart;
|
pajlada::Signals::Signal<std::vector<MessagePtr> &> messagesAddedAtStart;
|
||||||
|
@ -114,6 +113,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void onConnected();
|
virtual void onConnected();
|
||||||
|
virtual void messageRemovedFromStart(const MessagePtr &msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString name_;
|
const QString name_;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "AccountController.hpp"
|
#include "controllers/accounts/AccountController.hpp"
|
||||||
|
|
||||||
#include "controllers/accounts/Account.hpp"
|
#include "controllers/accounts/Account.hpp"
|
||||||
#include "controllers/accounts/AccountModel.hpp"
|
#include "controllers/accounts/AccountModel.hpp"
|
||||||
|
@ -10,10 +10,15 @@ namespace chatterino {
|
||||||
AccountController::AccountController()
|
AccountController::AccountController()
|
||||||
: accounts_(SharedPtrElementLess<Account>{})
|
: accounts_(SharedPtrElementLess<Account>{})
|
||||||
{
|
{
|
||||||
|
// These signal connections can safely be ignored since the twitch object
|
||||||
|
// will always be destroyed before the AccountController
|
||||||
|
std::ignore =
|
||||||
this->twitch.accounts.itemInserted.connect([this](const auto &args) {
|
this->twitch.accounts.itemInserted.connect([this](const auto &args) {
|
||||||
this->accounts_.insert(std::dynamic_pointer_cast<Account>(args.item));
|
this->accounts_.insert(
|
||||||
|
std::dynamic_pointer_cast<Account>(args.item));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::ignore =
|
||||||
this->twitch.accounts.itemRemoved.connect([this](const auto &args) {
|
this->twitch.accounts.itemRemoved.connect([this](const auto &args) {
|
||||||
if (args.caller != this)
|
if (args.caller != this)
|
||||||
{
|
{
|
||||||
|
@ -25,7 +30,7 @@ AccountController::AccountController()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->accounts_.itemRemoved.connect([this](const auto &args) {
|
std::ignore = this->accounts_.itemRemoved.connect([this](const auto &args) {
|
||||||
switch (args.item->getProviderId())
|
switch (args.item->getProviderId())
|
||||||
{
|
{
|
||||||
case ProviderId::Twitch: {
|
case ProviderId::Twitch: {
|
||||||
|
|
|
@ -587,8 +587,10 @@ void CommandController::initialize(Settings &, Paths &paths)
|
||||||
|
|
||||||
this->maxSpaces_ = maxSpaces;
|
this->maxSpaces_ = maxSpaces;
|
||||||
};
|
};
|
||||||
this->items.itemInserted.connect(addFirstMatchToMap);
|
// We can safely ignore these signal connections since items will be destroyed
|
||||||
this->items.itemRemoved.connect(addFirstMatchToMap);
|
// before CommandController
|
||||||
|
std::ignore = this->items.itemInserted.connect(addFirstMatchToMap);
|
||||||
|
std::ignore = this->items.itemRemoved.connect(addFirstMatchToMap);
|
||||||
|
|
||||||
// Initialize setting manager for commands.json
|
// Initialize setting manager for commands.json
|
||||||
auto path = combinePath(paths.settingsDirectory, "commands.json");
|
auto path = combinePath(paths.settingsDirectory, "commands.json");
|
||||||
|
@ -604,7 +606,7 @@ void CommandController::initialize(Settings &, Paths &paths)
|
||||||
|
|
||||||
// Update the setting when the vector of commands has been updated (most
|
// Update the setting when the vector of commands has been updated (most
|
||||||
// likely from the settings dialog)
|
// likely from the settings dialog)
|
||||||
this->items.delayedItemsChanged.connect([this] {
|
std::ignore = this->items.delayedItemsChanged.connect([this] {
|
||||||
this->commandsSetting_->setValue(this->items.raw());
|
this->commandsSetting_->setValue(this->items.raw());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,12 @@ void NotificationController::initialize(Settings &settings, Paths &paths)
|
||||||
this->channelMap[Platform::Twitch].append(channelName);
|
this->channelMap[Platform::Twitch].append(channelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can safely ignore this signal connection since channelMap will always be destroyed
|
||||||
|
// before the NotificationController
|
||||||
|
std::ignore =
|
||||||
this->channelMap[Platform::Twitch].delayedItemsChanged.connect([this] {
|
this->channelMap[Platform::Twitch].delayedItemsChanged.connect([this] {
|
||||||
this->twitchSetting_.setValue(this->channelMap[Platform::Twitch].raw());
|
this->twitchSetting_.setValue(
|
||||||
|
this->channelMap[Platform::Twitch].raw());
|
||||||
});
|
});
|
||||||
|
|
||||||
liveStatusTimer_ = new QTimer();
|
liveStatusTimer_ = new QTimer();
|
||||||
|
|
|
@ -50,7 +50,7 @@ AbstractIrcServer::AbstractIrcServer()
|
||||||
this->writeConnection_->connectionLost, [this](bool timeout) {
|
this->writeConnection_->connectionLost, [this](bool timeout) {
|
||||||
qCDebug(chatterinoIrc)
|
qCDebug(chatterinoIrc)
|
||||||
<< "Write connection reconnect requested. Timeout:" << timeout;
|
<< "Write connection reconnect requested. Timeout:" << timeout;
|
||||||
this->writeConnection_->smartReconnect.invoke();
|
this->writeConnection_->smartReconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen to read connection message signals
|
// Listen to read connection message signals
|
||||||
|
@ -86,7 +86,7 @@ AbstractIrcServer::AbstractIrcServer()
|
||||||
this->addGlobalSystemMessage(
|
this->addGlobalSystemMessage(
|
||||||
"Server connection timed out, reconnecting");
|
"Server connection timed out, reconnecting");
|
||||||
}
|
}
|
||||||
this->readConnection_->smartReconnect.invoke();
|
this->readConnection_->smartReconnect();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,9 @@ void IrcServerData::setPassword(const QString &password)
|
||||||
|
|
||||||
Irc::Irc()
|
Irc::Irc()
|
||||||
{
|
{
|
||||||
this->connections.itemInserted.connect([this](auto &&args) {
|
// We can safely ignore this signal connection since `connections` will always
|
||||||
|
// be destroyed before the Irc object
|
||||||
|
std::ignore = this->connections.itemInserted.connect([this](auto &&args) {
|
||||||
// make sure only one id can only exist for one server
|
// make sure only one id can only exist for one server
|
||||||
assert(this->servers_.find(args.item.id) == this->servers_.end());
|
assert(this->servers_.find(args.item.id) == this->servers_.end());
|
||||||
|
|
||||||
|
@ -117,7 +119,9 @@ Irc::Irc()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->connections.itemRemoved.connect([this](auto &&args) {
|
// We can safely ignore this signal connection since `connections` will always
|
||||||
|
// be destroyed before the Irc object
|
||||||
|
std::ignore = this->connections.itemRemoved.connect([this](auto &&args) {
|
||||||
// restore
|
// restore
|
||||||
if (auto server = this->servers_.find(args.item.id);
|
if (auto server = this->servers_.find(args.item.id);
|
||||||
server != this->servers_.end())
|
server != this->servers_.end())
|
||||||
|
@ -141,7 +145,9 @@ Irc::Irc()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->connections.delayedItemsChanged.connect([this] {
|
// We can safely ignore this signal connection since `connections` will always
|
||||||
|
// be destroyed before the Irc object
|
||||||
|
std::ignore = this->connections.delayedItemsChanged.connect([this] {
|
||||||
this->save();
|
this->save();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,18 +38,6 @@ IrcConnection::IrcConnection(QObject *parent)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Schedule a reconnect that won't violate RECONNECT_MIN_INTERVAL
|
|
||||||
this->smartReconnect.connect([this] {
|
|
||||||
if (this->reconnectTimer_.isActive())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto delay = this->reconnectBackoff_.next();
|
|
||||||
qCDebug(chatterinoIrc) << "Reconnecting in" << delay.count() << "ms";
|
|
||||||
this->reconnectTimer_.start(delay);
|
|
||||||
});
|
|
||||||
|
|
||||||
this->reconnectTimer_.setSingleShot(true);
|
this->reconnectTimer_.setSingleShot(true);
|
||||||
QObject::connect(&this->reconnectTimer_, &QTimer::timeout, [this] {
|
QObject::connect(&this->reconnectTimer_, &QTimer::timeout, [this] {
|
||||||
if (this->isConnected())
|
if (this->isConnected())
|
||||||
|
@ -123,6 +111,19 @@ IrcConnection::~IrcConnection()
|
||||||
this->disconnect();
|
this->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IrcConnection::smartReconnect()
|
||||||
|
{
|
||||||
|
if (this->reconnectTimer_.isActive())
|
||||||
|
{
|
||||||
|
// Ignore this reconnect request, we already have a reconnect request queued up
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto delay = this->reconnectBackoff_.next();
|
||||||
|
qCDebug(chatterinoIrc) << "Reconnecting in" << delay.count() << "ms";
|
||||||
|
this->reconnectTimer_.start(delay);
|
||||||
|
}
|
||||||
|
|
||||||
void IrcConnection::open()
|
void IrcConnection::open()
|
||||||
{
|
{
|
||||||
this->expectConnectionLoss_ = false;
|
this->expectConnectionLoss_ = false;
|
||||||
|
|
|
@ -20,7 +20,8 @@ public:
|
||||||
pajlada::Signals::Signal<bool> connectionLost;
|
pajlada::Signals::Signal<bool> connectionLost;
|
||||||
|
|
||||||
// Request a reconnect with a minimum interval between attempts.
|
// Request a reconnect with a minimum interval between attempts.
|
||||||
pajlada::Signals::NoArgSignal smartReconnect;
|
// This won't violate RECONNECT_MIN_INTERVAL
|
||||||
|
void smartReconnect();
|
||||||
|
|
||||||
virtual void open();
|
virtual void open();
|
||||||
virtual void close();
|
virtual void close();
|
||||||
|
|
|
@ -20,7 +20,9 @@ TwitchAccountManager::TwitchAccountManager()
|
||||||
currentUser->loadSeventvUserID();
|
currentUser->loadSeventvUserID();
|
||||||
});
|
});
|
||||||
|
|
||||||
this->accounts.itemRemoved.connect([this](const auto &acc) {
|
// We can safely ignore this signal connection since accounts will always be removed
|
||||||
|
// before TwitchAccountManager
|
||||||
|
std::ignore = this->accounts.itemRemoved.connect([this](const auto &acc) {
|
||||||
this->removeUser(acc.item.get());
|
this->removeUser(acc.item.get());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,25 +94,15 @@ TwitchChannel::TwitchChannel(const QString &name)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this->refreshPubSub();
|
this->refreshPubSub();
|
||||||
this->userStateChanged.connect([this] {
|
// We can safely ignore this signal connection since it's a private signal, meaning
|
||||||
|
// it will only ever be invoked by TwitchChannel itself
|
||||||
|
std::ignore = this->userStateChanged.connect([this] {
|
||||||
this->refreshPubSub();
|
this->refreshPubSub();
|
||||||
});
|
});
|
||||||
|
|
||||||
// room id loaded -> refresh live status
|
// We can safely ignore this signal connection this has no external dependencies - once the signal
|
||||||
this->roomIdChanged.connect([this]() {
|
// is destroyed, it will no longer be able to fire
|
||||||
this->refreshPubSub();
|
std::ignore = this->connected.connect([this]() {
|
||||||
this->refreshBadges();
|
|
||||||
this->refreshCheerEmotes();
|
|
||||||
this->refreshFFZChannelEmotes(false);
|
|
||||||
this->refreshBTTVChannelEmotes(false);
|
|
||||||
this->refreshSevenTVChannelEmotes(false);
|
|
||||||
this->joinBttvChannel();
|
|
||||||
this->listenSevenTVCosmetics();
|
|
||||||
getIApp()->getTwitchLiveController()->add(
|
|
||||||
std::dynamic_pointer_cast<TwitchChannel>(shared_from_this()));
|
|
||||||
});
|
|
||||||
|
|
||||||
this->connected.connect([this]() {
|
|
||||||
if (this->roomId().isEmpty())
|
if (this->roomId().isEmpty())
|
||||||
{
|
{
|
||||||
// If we get a reconnected event when the room id is not set, we
|
// If we get a reconnected event when the room id is not set, we
|
||||||
|
@ -125,18 +115,7 @@ TwitchChannel::TwitchChannel(const QString &name)
|
||||||
this->loadRecentMessagesReconnect();
|
this->loadRecentMessagesReconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
this->messageRemovedFromStart.connect([this](MessagePtr &msg) {
|
|
||||||
if (msg->replyThread)
|
|
||||||
{
|
|
||||||
if (msg->replyThread->liveCount(msg) == 0)
|
|
||||||
{
|
|
||||||
this->threads_.erase(msg->replyThread->rootId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// timers
|
// timers
|
||||||
|
|
||||||
QObject::connect(&this->chattersListTimer_, &QTimer::timeout, [this] {
|
QObject::connect(&this->chattersListTimer_, &QTimer::timeout, [this] {
|
||||||
this->refreshChatters();
|
this->refreshChatters();
|
||||||
});
|
});
|
||||||
|
@ -538,6 +517,20 @@ void TwitchChannel::showLoginMessage()
|
||||||
this->addMessage(builder.release());
|
this->addMessage(builder.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TwitchChannel::roomIdChanged()
|
||||||
|
{
|
||||||
|
this->refreshPubSub();
|
||||||
|
this->refreshBadges();
|
||||||
|
this->refreshCheerEmotes();
|
||||||
|
this->refreshFFZChannelEmotes(false);
|
||||||
|
this->refreshBTTVChannelEmotes(false);
|
||||||
|
this->refreshSevenTVChannelEmotes(false);
|
||||||
|
this->joinBttvChannel();
|
||||||
|
this->listenSevenTVCosmetics();
|
||||||
|
getIApp()->getTwitchLiveController()->add(
|
||||||
|
std::dynamic_pointer_cast<TwitchChannel>(shared_from_this()));
|
||||||
|
}
|
||||||
|
|
||||||
QString TwitchChannel::prepareMessage(const QString &message) const
|
QString TwitchChannel::prepareMessage(const QString &message) const
|
||||||
{
|
{
|
||||||
auto app = getApp();
|
auto app = getApp();
|
||||||
|
@ -729,7 +722,7 @@ void TwitchChannel::setRoomId(const QString &id)
|
||||||
if (*this->roomID_.accessConst() != id)
|
if (*this->roomID_.accessConst() != id)
|
||||||
{
|
{
|
||||||
*this->roomID_.access() = id;
|
*this->roomID_.access() = id;
|
||||||
this->roomIdChanged.invoke();
|
this->roomIdChanged();
|
||||||
this->loadRecentMessages();
|
this->loadRecentMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1063,6 +1056,17 @@ bool TwitchChannel::tryReplaceLastLiveUpdateAddOrRemove(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TwitchChannel::messageRemovedFromStart(const MessagePtr &msg)
|
||||||
|
{
|
||||||
|
if (msg->replyThread)
|
||||||
|
{
|
||||||
|
if (msg->replyThread->liveCount(msg) == 0)
|
||||||
|
{
|
||||||
|
this->threads_.erase(msg->replyThread->rootId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const QString &TwitchChannel::subscriptionUrl()
|
const QString &TwitchChannel::subscriptionUrl()
|
||||||
{
|
{
|
||||||
return this->subscriptionUrl_;
|
return this->subscriptionUrl_;
|
||||||
|
|
|
@ -191,8 +191,7 @@ public:
|
||||||
const std::unordered_map<QString, std::weak_ptr<MessageThread>> &threads()
|
const std::unordered_map<QString, std::weak_ptr<MessageThread>> &threads()
|
||||||
const;
|
const;
|
||||||
|
|
||||||
// Signals
|
// Only TwitchChannel may invoke this signal
|
||||||
pajlada::Signals::NoArgSignal roomIdChanged;
|
|
||||||
pajlada::Signals::NoArgSignal userStateChanged;
|
pajlada::Signals::NoArgSignal userStateChanged;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -242,8 +241,6 @@ private:
|
||||||
QString actualDisplayName;
|
QString actualDisplayName;
|
||||||
} nameOptions;
|
} nameOptions;
|
||||||
|
|
||||||
private:
|
|
||||||
// Methods
|
|
||||||
void refreshPubSub();
|
void refreshPubSub();
|
||||||
void refreshChatters();
|
void refreshChatters();
|
||||||
void refreshBadges();
|
void refreshBadges();
|
||||||
|
@ -252,6 +249,11 @@ private:
|
||||||
void loadRecentMessagesReconnect();
|
void loadRecentMessagesReconnect();
|
||||||
void cleanUpReplyThreads();
|
void cleanUpReplyThreads();
|
||||||
void showLoginMessage();
|
void showLoginMessage();
|
||||||
|
|
||||||
|
/// roomIdChanged is called whenever this channel's ID has been changed
|
||||||
|
/// This should only happen once per channel, whenever the ID goes from unset to set
|
||||||
|
void roomIdChanged();
|
||||||
|
|
||||||
/** Joins (subscribes to) a Twitch channel for updates on BTTV. */
|
/** Joins (subscribes to) a Twitch channel for updates on BTTV. */
|
||||||
void joinBttvChannel() const;
|
void joinBttvChannel() const;
|
||||||
/**
|
/**
|
||||||
|
@ -335,6 +337,8 @@ private:
|
||||||
std::unordered_map<QString, std::weak_ptr<MessageThread>> threads_;
|
std::unordered_map<QString, std::weak_ptr<MessageThread>> threads_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void messageRemovedFromStart(const MessagePtr &msg) override;
|
||||||
|
|
||||||
Atomic<std::shared_ptr<const EmoteMap>> bttvEmotes_;
|
Atomic<std::shared_ptr<const EmoteMap>> bttvEmotes_;
|
||||||
Atomic<std::shared_ptr<const EmoteMap>> ffzEmotes_;
|
Atomic<std::shared_ptr<const EmoteMap>> ffzEmotes_;
|
||||||
Atomic<std::shared_ptr<const EmoteMap>> seventvEmotes_;
|
Atomic<std::shared_ptr<const EmoteMap>> seventvEmotes_;
|
||||||
|
|
|
@ -133,21 +133,24 @@ void TwitchIrcServer::initializeConnection(IrcConnection *connection,
|
||||||
std::shared_ptr<Channel> TwitchIrcServer::createChannel(
|
std::shared_ptr<Channel> TwitchIrcServer::createChannel(
|
||||||
const QString &channelName)
|
const QString &channelName)
|
||||||
{
|
{
|
||||||
auto channel =
|
auto channel = std::make_shared<TwitchChannel>(channelName);
|
||||||
std::shared_ptr<TwitchChannel>(new TwitchChannel(channelName));
|
|
||||||
channel->initialize();
|
channel->initialize();
|
||||||
|
|
||||||
channel->sendMessageSignal.connect(
|
// We can safely ignore these signal connections since the TwitchIrcServer is only
|
||||||
|
// ever destroyed when the full Application state is about to be destroyed, at which point
|
||||||
|
// no Channel's should live
|
||||||
|
// NOTE: CHANNEL_LIFETIME
|
||||||
|
std::ignore = channel->sendMessageSignal.connect(
|
||||||
[this, channel = channel.get()](auto &chan, auto &msg, bool &sent) {
|
[this, channel = channel.get()](auto &chan, auto &msg, bool &sent) {
|
||||||
this->onMessageSendRequested(channel, msg, sent);
|
this->onMessageSendRequested(channel, msg, sent);
|
||||||
});
|
});
|
||||||
channel->sendReplySignal.connect(
|
std::ignore = channel->sendReplySignal.connect(
|
||||||
[this, channel = channel.get()](auto &chan, auto &msg, auto &replyId,
|
[this, channel = channel.get()](auto &chan, auto &msg, auto &replyId,
|
||||||
bool &sent) {
|
bool &sent) {
|
||||||
this->onReplySendRequested(channel, msg, replyId, sent);
|
this->onReplySendRequested(channel, msg, replyId, sent);
|
||||||
});
|
});
|
||||||
|
|
||||||
return std::shared_ptr<Channel>(channel);
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchIrcServer::privateMessageReceived(
|
void TwitchIrcServer::privateMessageReceived(
|
||||||
|
|
|
@ -14,12 +14,17 @@ namespace chatterino {
|
||||||
|
|
||||||
void Logging::initialize(Settings &settings, Paths & /*paths*/)
|
void Logging::initialize(Settings &settings, Paths & /*paths*/)
|
||||||
{
|
{
|
||||||
settings.loggedChannels.delayedItemsChanged.connect([this, &settings]() {
|
// We can safely ignore this signal connection since settings are only-ever destroyed
|
||||||
|
// on application exit
|
||||||
|
// NOTE: SETTINGS_LIFETIME
|
||||||
|
std::ignore = settings.loggedChannels.delayedItemsChanged.connect(
|
||||||
|
[this, &settings]() {
|
||||||
this->threadGuard.guard();
|
this->threadGuard.guard();
|
||||||
|
|
||||||
this->onlyLogListedChannels.clear();
|
this->onlyLogListedChannels.clear();
|
||||||
|
|
||||||
for (const auto &loggedChannel : *settings.loggedChannels.readOnly())
|
for (const auto &loggedChannel :
|
||||||
|
*settings.loggedChannels.readOnly())
|
||||||
{
|
{
|
||||||
this->onlyLogListedChannels.insert(loggedChannel.channelName());
|
this->onlyLogListedChannels.insert(loggedChannel.channelName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -344,9 +344,13 @@ void WindowManager::setEmotePopupPos(QPoint pos)
|
||||||
|
|
||||||
void WindowManager::initialize(Settings &settings, Paths &paths)
|
void WindowManager::initialize(Settings &settings, Paths &paths)
|
||||||
{
|
{
|
||||||
|
(void)paths;
|
||||||
assertInGuiThread();
|
assertInGuiThread();
|
||||||
|
|
||||||
getApp()->themes->repaintVisibleChatWidgets_.connect([this] {
|
// We can safely ignore this signal connection since both Themes and WindowManager
|
||||||
|
// share the Application state lifetime
|
||||||
|
// NOTE: APPLICATION_LIFETIME
|
||||||
|
std::ignore = getApp()->themes->repaintVisibleChatWidgets_.connect([this] {
|
||||||
this->repaintVisibleChatWidgets();
|
this->repaintVisibleChatWidgets();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "InitUpdateButton.hpp"
|
#include "util/InitUpdateButton.hpp"
|
||||||
|
|
||||||
#include "widgets/dialogs/UpdateDialog.hpp"
|
#include "widgets/dialogs/UpdateDialog.hpp"
|
||||||
#include "widgets/helper/Button.hpp"
|
#include "widgets/helper/Button.hpp"
|
||||||
|
@ -28,7 +28,11 @@ void initUpdateButton(Button &button,
|
||||||
dialog->show();
|
dialog->show();
|
||||||
dialog->raise();
|
dialog->raise();
|
||||||
|
|
||||||
dialog->buttonClicked.connect([&button](auto buttonType) {
|
// We can safely ignore the signal connection because the dialog will always
|
||||||
|
// be destroyed before the button is destroyed, since it is destroyed on focus loss
|
||||||
|
//
|
||||||
|
// The button is either attached to a Notebook, or a Window frame
|
||||||
|
std::ignore = dialog->buttonClicked.connect([&button](auto buttonType) {
|
||||||
switch (buttonType)
|
switch (buttonType)
|
||||||
{
|
{
|
||||||
case UpdateDialog::Dismiss: {
|
case UpdateDialog::Dismiss: {
|
||||||
|
|
|
@ -20,7 +20,8 @@ AccountSwitchWidget::AccountSwitchWidget(QWidget *parent)
|
||||||
this->addItem(userName);
|
this->addItem(userName);
|
||||||
}
|
}
|
||||||
|
|
||||||
app->accounts->twitch.userListUpdated.connect([=, this]() {
|
this->managedConnections_.managedConnect(
|
||||||
|
app->accounts->twitch.userListUpdated, [=, this]() {
|
||||||
this->blockSignals(true);
|
this->blockSignals(true);
|
||||||
|
|
||||||
this->clear();
|
this->clear();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "pajlada/signals/signalholder.hpp"
|
||||||
|
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
@ -15,6 +17,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refreshSelection();
|
void refreshSelection();
|
||||||
|
|
||||||
|
pajlada::Signals::SignalHolder managedConnections_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -246,7 +246,9 @@ EmotePopup::EmotePopup(QWidget *parent)
|
||||||
MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
|
MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
|
||||||
MessageElementFlag::EmoteImages});
|
MessageElementFlag::EmoteImages});
|
||||||
view->setEnableScrollingToBottom(false);
|
view->setEnableScrollingToBottom(false);
|
||||||
view->linkClicked.connect(clicked);
|
// We can safely ignore this signal connection since the ChannelView is deleted
|
||||||
|
// either when the notebook is deleted, or when our main layout is deleted.
|
||||||
|
std::ignore = view->linkClicked.connect(clicked);
|
||||||
|
|
||||||
if (addToNotebook)
|
if (addToNotebook)
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,6 +84,9 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
|
||||||
this->ui_.threadView->setMinimumSize(400, 100);
|
this->ui_.threadView->setMinimumSize(400, 100);
|
||||||
this->ui_.threadView->setSizePolicy(QSizePolicy::Expanding,
|
this->ui_.threadView->setSizePolicy(QSizePolicy::Expanding,
|
||||||
QSizePolicy::Expanding);
|
QSizePolicy::Expanding);
|
||||||
|
// We can safely ignore this signal's connection since threadView will always be deleted before
|
||||||
|
// the ReplyThreadPopup
|
||||||
|
std::ignore =
|
||||||
this->ui_.threadView->mouseDown.connect([this](QMouseEvent *) {
|
this->ui_.threadView->mouseDown.connect([this](QMouseEvent *) {
|
||||||
this->giveFocus(Qt::MouseFocusReason);
|
this->giveFocus(Qt::MouseFocusReason);
|
||||||
});
|
});
|
||||||
|
@ -97,8 +100,10 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
|
||||||
this->updateInputUI();
|
this->updateInputUI();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// We can safely ignore this signal's connection since threadView will always be deleted before
|
||||||
|
// the ReplyThreadPopup
|
||||||
|
std::ignore = this->ui_.threadView->selectionChanged.connect([this]() {
|
||||||
// clear SplitInput selection when selecting in ChannelView
|
// clear SplitInput selection when selecting in ChannelView
|
||||||
this->ui_.threadView->selectionChanged.connect([this]() {
|
|
||||||
if (this->ui_.replyInput->hasSelection())
|
if (this->ui_.replyInput->hasSelection())
|
||||||
{
|
{
|
||||||
this->ui_.replyInput->clearSelection();
|
this->ui_.replyInput->clearSelection();
|
||||||
|
@ -106,7 +111,9 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
|
||||||
});
|
});
|
||||||
|
|
||||||
// clear ChannelView selection when selecting in SplitInput
|
// clear ChannelView selection when selecting in SplitInput
|
||||||
this->ui_.replyInput->selectionChanged.connect([this]() {
|
// We can safely ignore this signal's connection since replyInput will always be deleted before
|
||||||
|
// the ReplyThreadPopup
|
||||||
|
std::ignore = this->ui_.replyInput->selectionChanged.connect([this]() {
|
||||||
if (this->ui_.threadView->hasSelection())
|
if (this->ui_.threadView->hasSelection())
|
||||||
{
|
{
|
||||||
this->ui_.threadView->clearSelection();
|
this->ui_.threadView->clearSelection();
|
||||||
|
|
|
@ -170,7 +170,9 @@ SelectChannelDialog::SelectChannelDialog(QWidget *parent)
|
||||||
view->getTableView()->horizontalHeader()->setSectionHidden(4, true);
|
view->getTableView()->horizontalHeader()->setSectionHidden(4, true);
|
||||||
view->getTableView()->horizontalHeader()->setSectionHidden(5, true);
|
view->getTableView()->horizontalHeader()->setSectionHidden(5, true);
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal's connection since the button won't be
|
||||||
|
// accessible after this dialog is closed
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
auto unique = IrcServerData{};
|
auto unique = IrcServerData{};
|
||||||
unique.id = Irc::instance().uniqueId();
|
unique.id = Irc::instance().uniqueId();
|
||||||
|
|
||||||
|
|
|
@ -438,7 +438,9 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
|
||||||
});
|
});
|
||||||
|
|
||||||
// userstate
|
// userstate
|
||||||
this->userStateChanged_.connect([this, mod, unmod, vip,
|
// We can safely ignore this signal connection since this is a private signal, and
|
||||||
|
// we only connect once
|
||||||
|
std::ignore = this->userStateChanged_.connect([this, mod, unmod, vip,
|
||||||
unvip]() mutable {
|
unvip]() mutable {
|
||||||
TwitchChannel *twitchChannel =
|
TwitchChannel *twitchChannel =
|
||||||
dynamic_cast<TwitchChannel *>(this->underlyingChannel_.get());
|
dynamic_cast<TwitchChannel *>(this->underlyingChannel_.get());
|
||||||
|
@ -469,9 +471,12 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
|
||||||
{
|
{
|
||||||
auto timeout = moderation.emplace<TimeoutWidget>();
|
auto timeout = moderation.emplace<TimeoutWidget>();
|
||||||
|
|
||||||
|
// We can safely ignore this signal connection since this is a private signal, and
|
||||||
|
// we only connect once
|
||||||
|
std::ignore =
|
||||||
this->userStateChanged_.connect([this, lineMod, timeout]() mutable {
|
this->userStateChanged_.connect([this, lineMod, timeout]() mutable {
|
||||||
TwitchChannel *twitchChannel =
|
TwitchChannel *twitchChannel = dynamic_cast<TwitchChannel *>(
|
||||||
dynamic_cast<TwitchChannel *>(this->underlyingChannel_.get());
|
this->underlyingChannel_.get());
|
||||||
|
|
||||||
bool hasModRights =
|
bool hasModRights =
|
||||||
twitchChannel ? twitchChannel->hasModRights() : false;
|
twitchChannel ? twitchChannel->hasModRights() : false;
|
||||||
|
@ -479,7 +484,9 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
|
||||||
timeout->setVisible(hasModRights);
|
timeout->setVisible(hasModRights);
|
||||||
});
|
});
|
||||||
|
|
||||||
timeout->buttonClicked.connect([this](auto item) {
|
// We can safely ignore this signal connection since we own the button, and
|
||||||
|
// the button will always be destroyed before the UserInfoPopup
|
||||||
|
std::ignore = timeout->buttonClicked.connect([this](auto item) {
|
||||||
TimeoutWidget::Action action;
|
TimeoutWidget::Action action;
|
||||||
int arg;
|
int arg;
|
||||||
std::tie(action, arg) = item;
|
std::tie(action, arg) = item;
|
||||||
|
|
|
@ -227,7 +227,9 @@ void ChannelView::initializeLayout()
|
||||||
|
|
||||||
void ChannelView::initializeScrollbar()
|
void ChannelView::initializeScrollbar()
|
||||||
{
|
{
|
||||||
this->scrollBar_->getCurrentValueChanged().connect([this] {
|
// We can safely ignore the scroll bar's signal connection since the scroll bar will
|
||||||
|
// always be destroyed before the ChannelView
|
||||||
|
std::ignore = this->scrollBar_->getCurrentValueChanged().connect([this] {
|
||||||
if (this->isVisible())
|
if (this->isVisible())
|
||||||
{
|
{
|
||||||
this->performLayout(true);
|
this->performLayout(true);
|
||||||
|
|
|
@ -33,7 +33,8 @@ AccountsPage::AccountsPage()
|
||||||
view->getTableView()->horizontalHeader()->setVisible(false);
|
view->getTableView()->horizontalHeader()->setVisible(false);
|
||||||
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
||||||
|
|
||||||
view->addButtonPressed.connect([this] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([this] {
|
||||||
LoginDialog d(this);
|
LoginDialog d(this);
|
||||||
d.exec();
|
d.exec();
|
||||||
});
|
});
|
||||||
|
|
|
@ -45,7 +45,8 @@ CommandPage::CommandPage()
|
||||||
view->setTitles({"Trigger", "Command", "Show In\nMessage Menu"});
|
view->setTitles({"Trigger", "Command", "Show In\nMessage Menu"});
|
||||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||||
1, QHeaderView::Stretch);
|
1, QHeaderView::Stretch);
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
getApp()->commands->items.append(
|
getApp()->commands->items.append(
|
||||||
Command{"/command", "I made a new command HeyGuys"});
|
Command{"/command", "I made a new command HeyGuys"});
|
||||||
});
|
});
|
||||||
|
|
|
@ -44,7 +44,8 @@ FiltersPage::FiltersPage()
|
||||||
view->getTableView()->setColumnWidth(2, 125);
|
view->getTableView()->setColumnWidth(2, 125);
|
||||||
});
|
});
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
ChannelFilterEditorDialog d(
|
ChannelFilterEditorDialog d(
|
||||||
static_cast<QWidget *>(&(getApp()->windows->getMainWindow())));
|
static_cast<QWidget *>(&(getApp()->windows->getMainWindow())));
|
||||||
if (d.exec() == QDialog::Accepted)
|
if (d.exec() == QDialog::Accepted)
|
||||||
|
|
|
@ -195,7 +195,11 @@ ColorButton *GeneralPageView::addColorButton(
|
||||||
auto dialog = new ColorPickerDialog(QColor(setting), this);
|
auto dialog = new ColorPickerDialog(QColor(setting), this);
|
||||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
dialog->show();
|
dialog->show();
|
||||||
dialog->closed.connect([&setting, colorButton](QColor selected) {
|
// We can safely ignore this signal connection, for now, since the
|
||||||
|
// colorButton & setting are never deleted and the signal is deleted
|
||||||
|
// once the dialog is closed
|
||||||
|
std::ignore = dialog->closed.connect(
|
||||||
|
[&setting, colorButton](QColor selected) {
|
||||||
if (selected.isValid())
|
if (selected.isValid())
|
||||||
{
|
{
|
||||||
setting = selected.name(QColor::HexArgb);
|
setting = selected.name(QColor::HexArgb);
|
||||||
|
|
|
@ -90,7 +90,8 @@ HighlightingPage::HighlightingPage()
|
||||||
view->getTableView()->setColumnWidth(0, 400);
|
view->getTableView()->setColumnWidth(0, 400);
|
||||||
});
|
});
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
getSettings()->highlightedMessages.append(HighlightPhrase{
|
getSettings()->highlightedMessages.append(HighlightPhrase{
|
||||||
"my phrase", true, true, false, false, false, "",
|
"my phrase", true, true, false, false, false, "",
|
||||||
*ColorProvider::instance().color(
|
*ColorProvider::instance().color(
|
||||||
|
@ -141,7 +142,8 @@ HighlightingPage::HighlightingPage()
|
||||||
view->getTableView()->setColumnWidth(0, 200);
|
view->getTableView()->setColumnWidth(0, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
getSettings()->highlightedUsers.append(HighlightPhrase{
|
getSettings()->highlightedUsers.append(HighlightPhrase{
|
||||||
"highlighted user", true, true, false, false, false, "",
|
"highlighted user", true, true, false, false, false, "",
|
||||||
*ColorProvider::instance().color(
|
*ColorProvider::instance().color(
|
||||||
|
@ -182,7 +184,8 @@ HighlightingPage::HighlightingPage()
|
||||||
view->getTableView()->setColumnWidth(0, 200);
|
view->getTableView()->setColumnWidth(0, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
view->addButtonPressed.connect([this] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([this] {
|
||||||
auto d = std::make_shared<BadgePickerDialog>(
|
auto d = std::make_shared<BadgePickerDialog>(
|
||||||
availableBadges, this);
|
availableBadges, this);
|
||||||
|
|
||||||
|
@ -236,7 +239,8 @@ HighlightingPage::HighlightingPage()
|
||||||
view->getTableView()->setColumnWidth(0, 200);
|
view->getTableView()->setColumnWidth(0, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
getSettings()->blacklistedUsers.append(
|
getSettings()->blacklistedUsers.append(
|
||||||
HighlightBlacklistUser{"blacklisted user", false});
|
HighlightBlacklistUser{"blacklisted user", false});
|
||||||
});
|
});
|
||||||
|
@ -329,7 +333,10 @@ void HighlightingPage::openColorDialog(const QModelIndex &clicked,
|
||||||
auto dialog = new ColorPickerDialog(initial, this);
|
auto dialog = new ColorPickerDialog(initial, this);
|
||||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
dialog->show();
|
dialog->show();
|
||||||
dialog->closed.connect([=](auto selected) {
|
// We can safely ignore this signal connection since the view and tab are never deleted
|
||||||
|
// TODO: The QModelIndex clicked is technically not safe to persist here since the model
|
||||||
|
// can be changed between the color dialog being created & the color dialog being closed
|
||||||
|
std::ignore = dialog->closed.connect([=](auto selected) {
|
||||||
if (selected.isValid())
|
if (selected.isValid())
|
||||||
{
|
{
|
||||||
view->getModel()->setData(clicked, selected, Qt::DecorationRole);
|
view->getModel()->setData(clicked, selected, Qt::DecorationRole);
|
||||||
|
|
|
@ -63,7 +63,8 @@ void addPhrasesTab(LayoutCreator<QVBoxLayout> layout)
|
||||||
view->getTableView()->setColumnWidth(0, 200);
|
view->getTableView()->setColumnWidth(0, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
getSettings()->ignoredMessages.append(
|
getSettings()->ignoredMessages.append(
|
||||||
IgnorePhrase{"my pattern", false, false,
|
IgnorePhrase{"my pattern", false, false,
|
||||||
getSettings()->ignoredPhraseReplace.getValue(), true});
|
getSettings()->ignoredPhraseReplace.getValue(), true});
|
||||||
|
|
|
@ -34,7 +34,8 @@ KeyboardSettingsPage::KeyboardSettingsPage()
|
||||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||||
1, QHeaderView::Stretch);
|
1, QHeaderView::Stretch);
|
||||||
|
|
||||||
view->addButtonPressed.connect([view, model] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([view, model] {
|
||||||
EditHotkeyDialog dialog(nullptr);
|
EditHotkeyDialog dialog(nullptr);
|
||||||
bool wasAccepted = dialog.exec() == 1;
|
bool wasAccepted = dialog.exec() == 1;
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,8 @@ ModerationPage::ModerationPage()
|
||||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||||
0, QHeaderView::Stretch);
|
0, QHeaderView::Stretch);
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
getSettings()->loggedChannels.append(ChannelLog("channel"));
|
getSettings()->loggedChannels.append(ChannelLog("channel"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -209,7 +210,8 @@ ModerationPage::ModerationPage()
|
||||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||||
0, QHeaderView::Stretch);
|
0, QHeaderView::Stretch);
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
getSettings()->moderationActions.append(
|
getSettings()->moderationActions.append(
|
||||||
ModerationAction("/timeout {user.name} 300"));
|
ModerationAction("/timeout {user.name} 300"));
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,7 +36,8 @@ NicknamesPage::NicknamesPage()
|
||||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||||
1, QHeaderView::Stretch);
|
1, QHeaderView::Stretch);
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
getSettings()->nicknames.append(
|
getSettings()->nicknames.append(
|
||||||
Nickname{"Username", "Nickname", false, false});
|
Nickname{"Username", "Nickname", false, false});
|
||||||
});
|
});
|
||||||
|
|
|
@ -109,7 +109,8 @@ NotificationPage::NotificationPage()
|
||||||
view->getTableView()->setColumnWidth(0, 200);
|
view->getTableView()->setColumnWidth(0, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
// We can safely ignore this signal connection since we own the view
|
||||||
|
std::ignore = view->addButtonPressed.connect([] {
|
||||||
getApp()
|
getApp()
|
||||||
->notifications->channelMap[Platform::Twitch]
|
->notifications->channelMap[Platform::Twitch]
|
||||||
.append("channel");
|
.append("channel");
|
||||||
|
|
|
@ -247,7 +247,8 @@ Split::Split(QWidget *parent)
|
||||||
this->updateInputPlaceholder();
|
this->updateInputPlaceholder();
|
||||||
|
|
||||||
// clear SplitInput selection when selecting in ChannelView
|
// clear SplitInput selection when selecting in ChannelView
|
||||||
this->view_->selectionChanged.connect([this]() {
|
// this connection can be ignored since the ChannelView is owned by this Split
|
||||||
|
std::ignore = this->view_->selectionChanged.connect([this]() {
|
||||||
if (this->input_->hasSelection())
|
if (this->input_->hasSelection())
|
||||||
{
|
{
|
||||||
this->input_->clearSelection();
|
this->input_->clearSelection();
|
||||||
|
@ -255,17 +256,19 @@ Split::Split(QWidget *parent)
|
||||||
});
|
});
|
||||||
|
|
||||||
// clear ChannelView selection when selecting in SplitInput
|
// clear ChannelView selection when selecting in SplitInput
|
||||||
this->input_->selectionChanged.connect([this]() {
|
// this connection can be ignored since the SplitInput is owned by this Split
|
||||||
|
std::ignore = this->input_->selectionChanged.connect([this]() {
|
||||||
if (this->view_->hasSelection())
|
if (this->view_->hasSelection())
|
||||||
{
|
{
|
||||||
this->view_->clearSelection();
|
this->view_->clearSelection();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->view_->openChannelIn.connect([this](
|
// this connection can be ignored since the ChannelView is owned by this Split
|
||||||
QString twitchChannel,
|
std::ignore = this->view_->openChannelIn.connect(
|
||||||
FromTwitchLinkOpenChannelIn openIn) {
|
[this](QString twitchChannel, FromTwitchLinkOpenChannelIn openIn) {
|
||||||
ChannelPtr channel = getApp()->twitch->getOrAddChannel(twitchChannel);
|
ChannelPtr channel =
|
||||||
|
getApp()->twitch->getOrAddChannel(twitchChannel);
|
||||||
switch (openIn)
|
switch (openIn)
|
||||||
{
|
{
|
||||||
case FromTwitchLinkOpenChannelIn::Split:
|
case FromTwitchLinkOpenChannelIn::Split:
|
||||||
|
@ -282,11 +285,14 @@ Split::Split(QWidget *parent)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qCWarning(chatterinoWidget)
|
qCWarning(chatterinoWidget)
|
||||||
<< "Unhandled \"FromTwitchLinkOpenChannelIn\" enum value: "
|
<< "Unhandled \"FromTwitchLinkOpenChannelIn\" enum "
|
||||||
|
"value: "
|
||||||
<< static_cast<int>(openIn);
|
<< static_cast<int>(openIn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// this connection can be ignored since the SplitInput is owned by this Split
|
||||||
|
std::ignore =
|
||||||
this->input_->textChanged.connect([this](const QString &newText) {
|
this->input_->textChanged.connect([this](const QString &newText) {
|
||||||
if (getSettings()->showEmptyInput)
|
if (getSettings()->showEmptyInput)
|
||||||
{
|
{
|
||||||
|
@ -367,7 +373,9 @@ Split::Split(QWidget *parent)
|
||||||
// Forward textEdit's focusLost event
|
// Forward textEdit's focusLost event
|
||||||
this->focusLost.invoke();
|
this->focusLost.invoke();
|
||||||
});
|
});
|
||||||
this->input_->ui_.textEdit->imagePasted.connect(
|
|
||||||
|
// this connection can be ignored since the SplitInput is owned by this Split
|
||||||
|
std::ignore = this->input_->ui_.textEdit->imagePasted.connect(
|
||||||
[this](const QMimeData *source) {
|
[this](const QMimeData *source) {
|
||||||
if (!getSettings()->imageUploaderEnabled)
|
if (!getSettings()->imageUploaderEnabled)
|
||||||
return;
|
return;
|
||||||
|
@ -896,7 +904,9 @@ void Split::showChangeChannelPopup(const char *dialogTitle, bool empty,
|
||||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
dialog->setWindowTitle(dialogTitle);
|
dialog->setWindowTitle(dialogTitle);
|
||||||
dialog->show();
|
dialog->show();
|
||||||
dialog->closed.connect([=, this] {
|
// We can safely ignore this signal connection since the dialog will be closed before
|
||||||
|
// this Split is closed
|
||||||
|
std::ignore = dialog->closed.connect([=, this] {
|
||||||
if (dialog->hasSeletedChannel())
|
if (dialog->hasSeletedChannel())
|
||||||
{
|
{
|
||||||
this->setChannel(dialog->getSelectedChannel());
|
this->setChannel(dialog->getSelectedChannel());
|
||||||
|
|
|
@ -44,13 +44,11 @@ using namespace chatterino;
|
||||||
// 5 minutes
|
// 5 minutes
|
||||||
constexpr const uint64_t THUMBNAIL_MAX_AGE_MS = 5ULL * 60 * 1000;
|
constexpr const uint64_t THUMBNAIL_MAX_AGE_MS = 5ULL * 60 * 1000;
|
||||||
|
|
||||||
auto formatRoomMode(TwitchChannel &channel) -> QString
|
auto formatRoomModeUnclean(
|
||||||
|
const SharedAccessGuard<const TwitchChannel::RoomModes> &modes) -> QString
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
|
|
||||||
{
|
|
||||||
auto modes = channel.accessRoomModes();
|
|
||||||
|
|
||||||
if (modes->r9k)
|
if (modes->r9k)
|
||||||
{
|
{
|
||||||
text += "r9k, ";
|
text += "r9k, ";
|
||||||
|
@ -79,8 +77,12 @@ auto formatRoomMode(TwitchChannel &channel) -> QString
|
||||||
text += QString("follow, ");
|
text += QString("follow, ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanRoomModeText(QString &text, bool hasModRights)
|
||||||
|
{
|
||||||
if (text.length() > 2)
|
if (text.length() > 2)
|
||||||
{
|
{
|
||||||
text = text.mid(0, text.size() - 2);
|
text = text.mid(0, text.size() - 2);
|
||||||
|
@ -97,12 +99,10 @@ auto formatRoomMode(TwitchChannel &channel) -> QString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text.isEmpty() && channel.hasModRights())
|
if (text.isEmpty() && hasModRights)
|
||||||
{
|
{
|
||||||
return "none";
|
text = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto formatTooltip(const TwitchChannel::StreamStatus &s, QString thumbnail)
|
auto formatTooltip(const TwitchChannel::StreamStatus &s, QString thumbnail)
|
||||||
|
@ -231,13 +231,16 @@ SplitHeader::SplitHeader(Split *split)
|
||||||
this->handleChannelChanged();
|
this->handleChannelChanged();
|
||||||
this->updateModerationModeIcon();
|
this->updateModerationModeIcon();
|
||||||
|
|
||||||
this->split_->focused.connect([this]() {
|
// The lifetime of these signals are tied to the lifetime of the Split.
|
||||||
|
// Since the SplitHeader is owned by the Split, they will always be destroyed
|
||||||
|
// at the same time.
|
||||||
|
std::ignore = this->split_->focused.connect([this]() {
|
||||||
this->themeChangedEvent();
|
this->themeChangedEvent();
|
||||||
});
|
});
|
||||||
this->split_->focusLost.connect([this]() {
|
std::ignore = this->split_->focusLost.connect([this]() {
|
||||||
this->themeChangedEvent();
|
this->themeChangedEvent();
|
||||||
});
|
});
|
||||||
this->split_->channelChanged.connect([this]() {
|
std::ignore = this->split_->channelChanged.connect([this]() {
|
||||||
this->handleChannelChanged();
|
this->handleChannelChanged();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -257,6 +260,8 @@ SplitHeader::SplitHeader(Split *split)
|
||||||
|
|
||||||
void SplitHeader::initializeLayout()
|
void SplitHeader::initializeLayout()
|
||||||
{
|
{
|
||||||
|
assert(this->layout() == nullptr);
|
||||||
|
|
||||||
auto *layout = makeLayout<QHBoxLayout>({
|
auto *layout = makeLayout<QHBoxLayout>({
|
||||||
// space
|
// space
|
||||||
makeWidget<BaseWidget>([](auto w) {
|
makeWidget<BaseWidget>([](auto w) {
|
||||||
|
@ -277,7 +282,6 @@ void SplitHeader::initializeLayout()
|
||||||
this->modeButton_ = makeWidget<EffectLabel>([&](auto w) {
|
this->modeButton_ = makeWidget<EffectLabel>([&](auto w) {
|
||||||
w->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
w->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
w->hide();
|
w->hide();
|
||||||
this->initializeModeSignals(*w);
|
|
||||||
w->setMenu(this->createChatModeMenu());
|
w->setMenu(this->createChatModeMenu());
|
||||||
}),
|
}),
|
||||||
// moderator
|
// moderator
|
||||||
|
@ -573,43 +577,23 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||||
{
|
{
|
||||||
auto menu = std::make_unique<QMenu>();
|
auto menu = std::make_unique<QMenu>();
|
||||||
|
|
||||||
auto *setSub = new QAction("Subscriber only", this);
|
this->modeActionSetSub = new QAction("Subscriber only", this);
|
||||||
auto *setEmote = new QAction("Emote only", this);
|
this->modeActionSetEmote = new QAction("Emote only", this);
|
||||||
auto *setSlow = new QAction("Slow", this);
|
this->modeActionSetSlow = new QAction("Slow", this);
|
||||||
auto *setR9k = new QAction("R9K", this);
|
this->modeActionSetR9k = new QAction("R9K", this);
|
||||||
auto *setFollowers = new QAction("Followers only", this);
|
this->modeActionSetFollowers = new QAction("Followers only", this);
|
||||||
|
|
||||||
setFollowers->setCheckable(true);
|
this->modeActionSetFollowers->setCheckable(true);
|
||||||
setSub->setCheckable(true);
|
this->modeActionSetSub->setCheckable(true);
|
||||||
setEmote->setCheckable(true);
|
this->modeActionSetEmote->setCheckable(true);
|
||||||
setSlow->setCheckable(true);
|
this->modeActionSetSlow->setCheckable(true);
|
||||||
setR9k->setCheckable(true);
|
this->modeActionSetR9k->setCheckable(true);
|
||||||
|
|
||||||
menu->addAction(setEmote);
|
menu->addAction(this->modeActionSetEmote);
|
||||||
menu->addAction(setSub);
|
menu->addAction(this->modeActionSetSub);
|
||||||
menu->addAction(setSlow);
|
menu->addAction(this->modeActionSetSlow);
|
||||||
menu->addAction(setR9k);
|
menu->addAction(this->modeActionSetR9k);
|
||||||
menu->addAction(setFollowers);
|
menu->addAction(this->modeActionSetFollowers);
|
||||||
|
|
||||||
this->managedConnections_.managedConnect(
|
|
||||||
this->modeUpdateRequested_,
|
|
||||||
[this, setSub, setEmote, setSlow, setR9k, setFollowers]() {
|
|
||||||
auto *twitchChannel =
|
|
||||||
dynamic_cast<TwitchChannel *>(this->split_->getChannel().get());
|
|
||||||
if (twitchChannel == nullptr)
|
|
||||||
{
|
|
||||||
this->modeButton_->hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto roomModes = twitchChannel->accessRoomModes();
|
|
||||||
|
|
||||||
setR9k->setChecked(roomModes->r9k);
|
|
||||||
setSlow->setChecked(roomModes->slowMode > 0);
|
|
||||||
setEmote->setChecked(roomModes->emoteOnly);
|
|
||||||
setSub->setChecked(roomModes->submode);
|
|
||||||
setFollowers->setChecked(roomModes->followerOnly != -1);
|
|
||||||
});
|
|
||||||
|
|
||||||
auto execCommand = [this](const QString &command) {
|
auto execCommand = [this](const QString &command) {
|
||||||
auto text = getApp()->getCommands()->execCommand(
|
auto text = getApp()->getCommands()->execCommand(
|
||||||
|
@ -622,27 +606,27 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||||
action->setChecked(!action->isChecked());
|
action->setChecked(!action->isChecked());
|
||||||
};
|
};
|
||||||
|
|
||||||
QObject::connect(setSub, &QAction::triggered, this,
|
QObject::connect(this->modeActionSetSub, &QAction::triggered, this,
|
||||||
[setSub, toggle]() mutable {
|
[this, toggle]() mutable {
|
||||||
toggle("/subscribers", setSub);
|
toggle("/subscribers", this->modeActionSetSub);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(setEmote, &QAction::triggered, this,
|
QObject::connect(this->modeActionSetEmote, &QAction::triggered, this,
|
||||||
[setEmote, toggle]() mutable {
|
[this, toggle]() mutable {
|
||||||
toggle("/emoteonly", setEmote);
|
toggle("/emoteonly", this->modeActionSetEmote);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect(this->modeActionSetSlow, &QAction::triggered, this,
|
||||||
setSlow, &QAction::triggered, this, [setSlow, this, execCommand]() {
|
[this, execCommand]() {
|
||||||
if (!setSlow->isChecked())
|
if (!this->modeActionSetSlow->isChecked())
|
||||||
{
|
{
|
||||||
execCommand("/slowoff");
|
execCommand("/slowoff");
|
||||||
setSlow->setChecked(false);
|
this->modeActionSetSlow->setChecked(false);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
auto ok = bool();
|
auto ok = bool();
|
||||||
auto seconds =
|
auto seconds = QInputDialog::getInt(
|
||||||
QInputDialog::getInt(this, "", "Seconds:", 10, 0, 500, 1, &ok,
|
this, "", "Seconds:", 10, 0, 500, 1, &ok,
|
||||||
Qt::FramelessWindowHint);
|
Qt::FramelessWindowHint);
|
||||||
if (ok)
|
if (ok)
|
||||||
{
|
{
|
||||||
|
@ -650,16 +634,16 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setSlow->setChecked(false);
|
this->modeActionSetSlow->setChecked(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(setFollowers, &QAction::triggered, this,
|
QObject::connect(this->modeActionSetFollowers, &QAction::triggered, this,
|
||||||
[setFollowers, this, execCommand]() {
|
[this, execCommand]() {
|
||||||
if (!setFollowers->isChecked())
|
if (!this->modeActionSetFollowers->isChecked())
|
||||||
{
|
{
|
||||||
execCommand("/followersoff");
|
execCommand("/followersoff");
|
||||||
setFollowers->setChecked(false);
|
this->modeActionSetFollowers->setChecked(false);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
auto ok = bool();
|
auto ok = bool();
|
||||||
|
@ -673,13 +657,13 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setFollowers->setChecked(false);
|
this->modeActionSetFollowers->setChecked(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(setR9k, &QAction::triggered, this,
|
QObject::connect(this->modeActionSetR9k, &QAction::triggered, this,
|
||||||
[setR9k, toggle]() mutable {
|
[this, toggle]() mutable {
|
||||||
toggle("/r9kbeta", setR9k);
|
toggle("/r9kbeta", this->modeActionSetR9k);
|
||||||
});
|
});
|
||||||
|
|
||||||
return menu;
|
return menu;
|
||||||
|
@ -687,30 +671,47 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||||
|
|
||||||
void SplitHeader::updateRoomModes()
|
void SplitHeader::updateRoomModes()
|
||||||
{
|
{
|
||||||
this->modeUpdateRequested_.invoke();
|
assert(this->modeButton_ != nullptr);
|
||||||
}
|
|
||||||
|
|
||||||
void SplitHeader::initializeModeSignals(EffectLabel &label)
|
// Update the mode button
|
||||||
{
|
|
||||||
this->modeUpdateRequested_.connect([this, &label] {
|
|
||||||
if (auto *twitchChannel =
|
if (auto *twitchChannel =
|
||||||
dynamic_cast<TwitchChannel *>(this->split_->getChannel().get()))
|
dynamic_cast<TwitchChannel *>(this->split_->getChannel().get()))
|
||||||
{
|
{
|
||||||
label.setEnable(twitchChannel->hasModRights());
|
this->modeButton_->setEnable(twitchChannel->hasModRights());
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
{
|
||||||
|
auto roomModes = twitchChannel->accessRoomModes();
|
||||||
|
text = formatRoomModeUnclean(roomModes);
|
||||||
|
|
||||||
|
// Set menu action
|
||||||
|
this->modeActionSetR9k->setChecked(roomModes->r9k);
|
||||||
|
this->modeActionSetSlow->setChecked(roomModes->slowMode > 0);
|
||||||
|
this->modeActionSetEmote->setChecked(roomModes->emoteOnly);
|
||||||
|
this->modeActionSetSub->setChecked(roomModes->submode);
|
||||||
|
this->modeActionSetFollowers->setChecked(roomModes->followerOnly !=
|
||||||
|
-1);
|
||||||
|
}
|
||||||
|
cleanRoomModeText(text, twitchChannel->hasModRights());
|
||||||
|
|
||||||
// set the label text
|
// set the label text
|
||||||
auto text = formatRoomMode(*twitchChannel);
|
|
||||||
|
|
||||||
if (!text.isEmpty())
|
if (!text.isEmpty())
|
||||||
{
|
{
|
||||||
label.getLabel().setText(text);
|
this->modeButton_->getLabel().setText(text);
|
||||||
label.show();
|
this->modeButton_->show();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->modeButton_->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
label.hide();
|
// Update the mode button menu actions
|
||||||
});
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->modeButton_->hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitHeader::resetThumbnail()
|
void SplitHeader::resetThumbnail()
|
||||||
|
|
|
@ -32,6 +32,8 @@ public:
|
||||||
|
|
||||||
void updateChannelText();
|
void updateChannelText();
|
||||||
void updateModerationModeIcon();
|
void updateModerationModeIcon();
|
||||||
|
// Invoked when SplitHeader should update anything refering to a TwitchChannel's mode
|
||||||
|
// has changed (e.g. sub mode toggled)
|
||||||
void updateRoomModes();
|
void updateRoomModes();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -75,7 +77,14 @@ private:
|
||||||
// ui
|
// ui
|
||||||
Button *dropdownButton_{};
|
Button *dropdownButton_{};
|
||||||
Label *titleLabel_{};
|
Label *titleLabel_{};
|
||||||
|
|
||||||
EffectLabel *modeButton_{};
|
EffectLabel *modeButton_{};
|
||||||
|
QAction *modeActionSetEmote{};
|
||||||
|
QAction *modeActionSetSub{};
|
||||||
|
QAction *modeActionSetSlow{};
|
||||||
|
QAction *modeActionSetR9k{};
|
||||||
|
QAction *modeActionSetFollowers{};
|
||||||
|
|
||||||
Button *moderationButton_{};
|
Button *moderationButton_{};
|
||||||
Button *viewersButton_{};
|
Button *viewersButton_{};
|
||||||
Button *addButton_{};
|
Button *addButton_{};
|
||||||
|
@ -86,8 +95,8 @@ private:
|
||||||
bool doubleClicked_{false};
|
bool doubleClicked_{false};
|
||||||
bool menuVisible_{false};
|
bool menuVisible_{false};
|
||||||
|
|
||||||
// signals
|
// managedConnections_ contains connections for signals that are not managed by us
|
||||||
pajlada::Signals::NoArgSignal modeUpdateRequested_;
|
// and don't change when the parent Split changes its underlying channel
|
||||||
pajlada::Signals::SignalHolder managedConnections_;
|
pajlada::Signals::SignalHolder managedConnections_;
|
||||||
pajlada::Signals::SignalHolder channelConnections_;
|
pajlada::Signals::SignalHolder channelConnections_;
|
||||||
std::vector<boost::signals2::scoped_connection> bSignals_;
|
std::vector<boost::signals2::scoped_connection> bSignals_;
|
||||||
|
|
|
@ -63,7 +63,9 @@ SplitInput::SplitInput(QWidget *parent, Split *_chatWidget,
|
||||||
// misc
|
// misc
|
||||||
this->installKeyPressedEvent();
|
this->installKeyPressedEvent();
|
||||||
this->addShortcuts();
|
this->addShortcuts();
|
||||||
this->ui_.textEdit->focusLost.connect([this] {
|
// The textEdit's signal will be destroyed before this SplitInput is
|
||||||
|
// destroyed, so we can safely ignore this signal's connection.
|
||||||
|
std::ignore = this->ui_.textEdit->focusLost.connect([this] {
|
||||||
this->hideCompletionPopup();
|
this->hideCompletionPopup();
|
||||||
});
|
});
|
||||||
this->scaleChangedEvent(this->scale());
|
this->scaleChangedEvent(this->scale());
|
||||||
|
@ -293,6 +295,8 @@ void SplitInput::openEmotePopup()
|
||||||
this->emotePopup_ = new EmotePopup(this);
|
this->emotePopup_ = new EmotePopup(this);
|
||||||
this->emotePopup_->setAttribute(Qt::WA_DeleteOnClose);
|
this->emotePopup_->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
// The EmotePopup is closed & destroyed when this is destroyed, meaning it's safe to ignore this connection
|
||||||
|
std::ignore =
|
||||||
this->emotePopup_->linkClicked.connect([this](const Link &link) {
|
this->emotePopup_->linkClicked.connect([this](const Link &link) {
|
||||||
if (link.type == Link::InsertText)
|
if (link.type == Link::InsertText)
|
||||||
{
|
{
|
||||||
|
@ -649,7 +653,9 @@ bool SplitInput::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
|
||||||
void SplitInput::installKeyPressedEvent()
|
void SplitInput::installKeyPressedEvent()
|
||||||
{
|
{
|
||||||
this->ui_.textEdit->keyPressed.disconnectAll();
|
// We can safely ignore this signal's connection because SplitInput owns
|
||||||
|
// the textEdit object, so it will always be deleted before SplitInput
|
||||||
|
std::ignore =
|
||||||
this->ui_.textEdit->keyPressed.connect([this](QKeyEvent *event) {
|
this->ui_.textEdit->keyPressed.connect([this](QKeyEvent *event) {
|
||||||
if (auto *popup = this->inputCompletionPopup_.data())
|
if (auto *popup = this->inputCompletionPopup_.data())
|
||||||
{
|
{
|
||||||
|
@ -676,6 +682,11 @@ void SplitInput::installKeyPressedEvent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(this->keyPressedEventInstalled == false);
|
||||||
|
this->keyPressedEventInstalled = true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitInput::mousePressEvent(QMouseEvent *event)
|
void SplitInput::mousePressEvent(QMouseEvent *event)
|
||||||
|
|
|
@ -91,6 +91,9 @@ protected:
|
||||||
void addShortcuts() override;
|
void addShortcuts() override;
|
||||||
void initLayout();
|
void initLayout();
|
||||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
#ifdef DEBUG
|
||||||
|
bool keyPressedEventInstalled{};
|
||||||
|
#endif
|
||||||
void installKeyPressedEvent();
|
void installKeyPressedEvent();
|
||||||
void onCursorPositionChanged();
|
void onCursorPositionChanged();
|
||||||
void onTextChanged();
|
void onTextChanged();
|
||||||
|
|
Loading…
Reference in a new issue