From d3000ba5975d8823c04f1b223711088cf49388e8 Mon Sep 17 00:00:00 2001 From: nerix Date: Sun, 3 Nov 2024 13:29:57 +0100 Subject: [PATCH] feat: show warning before blocking followed channel (#5615) --- CHANGELOG.md | 1 + mocks/include/mocks/Helix.hpp | 2 +- src/providers/twitch/TwitchChannel.cpp | 2 +- src/providers/twitch/api/Helix.cpp | 3 +- src/providers/twitch/api/Helix.hpp | 4 +- src/widgets/DraggablePopup.cpp | 11 +++ src/widgets/DraggablePopup.hpp | 8 ++ src/widgets/dialogs/UserInfoPopup.cpp | 114 +++++++++++++++---------- 8 files changed, 93 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ceaf7551..1eea64131 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ - Minor: Moderators can now see which mods start and cancel raids. (#5563) - Minor: The emote popup now reloads when Twitch emotes are reloaded. (#5580) - Minor: Added `--login ` CLI argument to specify which account to start logged in as. (#5626) +- Minor: When blocking a channel, Chatterino will now warn you about that action. (#5615) - Minor: Indicate when subscriptions and resubscriptions are for multiple months. (#5642) - Minor: Proxy URL information is now included in the `/debug-env` command. (#5648) - Minor: Make raid entry message usernames clickable. (#5651) diff --git a/mocks/include/mocks/Helix.hpp b/mocks/include/mocks/Helix.hpp index cfb2d71b6..02913efed 100644 --- a/mocks/include/mocks/Helix.hpp +++ b/mocks/include/mocks/Helix.hpp @@ -422,7 +422,7 @@ public: // get followed channel MOCK_METHOD( void, getFollowedChannel, - (QString userID, QString broadcasterID, + (QString userID, QString broadcasterID, const QObject *caller, ResultCallback> successCallback, FailureCallback failureCallback), (override)); diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 7c7cc1304..0371fd295 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -274,7 +274,7 @@ void TwitchChannel::refreshTwitchChannelEmotes(bool manualRefresh) getHelix()->getFollowedChannel( getApp()->getAccounts()->twitch.getCurrent()->getUserId(), - this->roomId(), + this->roomId(), nullptr, [weak{this->weak_from_this()}, makeEmotes](const auto &chan) { auto self = std::dynamic_pointer_cast(weak.lock()); if (!self || !chan) diff --git a/src/providers/twitch/api/Helix.cpp b/src/providers/twitch/api/Helix.cpp index 593c6837f..977cbd5f6 100644 --- a/src/providers/twitch/api/Helix.cpp +++ b/src/providers/twitch/api/Helix.cpp @@ -3138,7 +3138,7 @@ void Helix::getUserEmotes( } void Helix::getFollowedChannel( - QString userID, QString broadcasterID, + QString userID, QString broadcasterID, const QObject *caller, ResultCallback> successCallback, FailureCallback failureCallback) { @@ -3147,6 +3147,7 @@ void Helix::getFollowedChannel( {u"user_id"_s, userID}, {u"broadcaster_id"_s, broadcasterID}, }) + .caller(caller) .onSuccess([successCallback](auto result) { if (result.status() != 200) { diff --git a/src/providers/twitch/api/Helix.hpp b/src/providers/twitch/api/Helix.hpp index 3a81a9908..e62920682 100644 --- a/src/providers/twitch/api/Helix.hpp +++ b/src/providers/twitch/api/Helix.hpp @@ -1143,7 +1143,7 @@ public: /// https://dev.twitch.tv/docs/api/reference/#get-followed-channels /// (non paginated) virtual void getFollowedChannel( - QString userID, QString broadcasterID, + QString userID, QString broadcasterID, const QObject *caller, ResultCallback> successCallback, FailureCallback failureCallback) = 0; @@ -1486,7 +1486,7 @@ public: /// https://dev.twitch.tv/docs/api/reference/#get-followed-channels /// (non paginated) void getFollowedChannel( - QString userID, QString broadcasterID, + QString userID, QString broadcasterID, const QObject *caller, ResultCallback> successCallback, FailureCallback failureCallback) final; diff --git a/src/widgets/DraggablePopup.cpp b/src/widgets/DraggablePopup.cpp index 6b7e9eaf9..b680e35bf 100644 --- a/src/widgets/DraggablePopup.cpp +++ b/src/widgets/DraggablePopup.cpp @@ -41,6 +41,7 @@ DraggablePopup::DraggablePopup(bool closeAutomatically, QWidget *parent) BaseWindow::ClearBuffersOnDpiChange, parent) , lifetimeHack_(std::make_shared(false)) + , closeAutomatically_(closeAutomatically) , dragTimer_(this) { @@ -128,4 +129,14 @@ Button *DraggablePopup::createPinButton() return this->pinButton_; } +bool DraggablePopup::ensurePinned() +{ + if (this->closeAutomatically_ && !this->isPinned_) + { + this->togglePinned(); + return true; + } + return false; +} + } // namespace chatterino diff --git a/src/widgets/DraggablePopup.hpp b/src/widgets/DraggablePopup.hpp index bf82af008..97217c0df 100644 --- a/src/widgets/DraggablePopup.hpp +++ b/src/widgets/DraggablePopup.hpp @@ -38,10 +38,18 @@ protected: // button pixmap void togglePinned(); + /// Ensures that this popup is pinned (if it's expected to close automatically) + /// + /// @returns `true` if the popup was pinned as a result (i.e. if the popup + /// was unpinned and said to automatically close before) + bool ensurePinned(); + private: // isMoving_ is set to true if the user is holding the left mouse button down and has moved the mouse a small amount away from the original click point (startPosDrag_) bool isMoving_ = false; + bool closeAutomatically_ = false; + // startPosDrag_ is the coordinates where the user originally pressed the mouse button down to start dragging QPoint startPosDrag_; diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index f8bec9b1b..3087da586 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -2,6 +2,7 @@ #include "Application.hpp" #include "common/Channel.hpp" +#include "common/Literals.hpp" #include "common/network/NetworkRequest.hpp" #include "common/QLogging.hpp" #include "controllers/accounts/AccountController.hpp" @@ -37,6 +38,8 @@ #include #include +#include +#include #include #include #include @@ -141,6 +144,8 @@ int calculateTimeoutDuration(TimeoutButton timeout) namespace chatterino { +using namespace literals; + UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) : DraggablePopup(closeAutomatically, split) , split_(split) @@ -623,57 +628,72 @@ void UserInfoPopup::installEvents() return; } - switch (newState) + if (newState == Qt::Unchecked) { - case Qt::CheckState::Unchecked: { - this->ui_.block->setEnabled(false); + this->ui_.block->setEnabled(false); - getApp()->getAccounts()->twitch.getCurrent()->unblockUser( - this->userId_, this, - [this, reenableBlockCheckbox, currentUser] { - this->channel_->addSystemMessage( - QString("You successfully unblocked user %1") - .arg(this->userName_)); - reenableBlockCheckbox(); - }, - [this, reenableBlockCheckbox] { - this->channel_->addSystemMessage( - QString( - "User %1 couldn't be unblocked, an unknown " + getApp()->getAccounts()->twitch.getCurrent()->unblockUser( + this->userId_, this, + [this, reenableBlockCheckbox, currentUser] { + this->channel_->addSystemMessage( + QString("You successfully unblocked user %1") + .arg(this->userName_)); + reenableBlockCheckbox(); + }, + [this, reenableBlockCheckbox] { + this->channel_->addSystemMessage( + QString("User %1 couldn't be unblocked, an unknown " "error occurred!") - .arg(this->userName_)); - reenableBlockCheckbox(); - }); - } - break; - - case Qt::CheckState::PartiallyChecked: { - // We deliberately ignore this state - } - break; - - case Qt::CheckState::Checked: { - this->ui_.block->setEnabled(false); - - getApp()->getAccounts()->twitch.getCurrent()->blockUser( - this->userId_, this, - [this, reenableBlockCheckbox, currentUser] { - this->channel_->addSystemMessage( - QString("You successfully blocked user %1") - .arg(this->userName_)); - reenableBlockCheckbox(); - }, - [this, reenableBlockCheckbox] { - this->channel_->addSystemMessage( - QString( - "User %1 couldn't be blocked, an unknown " - "error occurred!") - .arg(this->userName_)); - reenableBlockCheckbox(); - }); - } - break; + .arg(this->userName_)); + reenableBlockCheckbox(); + }); + return; } + + if (newState == Qt::Checked) + { + this->ui_.block->setEnabled(false); + + bool wasPinned = this->ensurePinned(); + auto btn = QMessageBox::warning( + this, u"Blocking " % this->userName_, + u"Blocking %1 can cause unintended side-effects like unfollowing.\n\n"_s + "Are you sure you want to block %1?".arg(this->userName_), + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel); + if (wasPinned) + { + this->togglePinned(); + } + if (btn != QMessageBox::Yes) + { + reenableBlockCheckbox(); + QSignalBlocker blocker(this->ui_.block); + this->ui_.block->setCheckState(Qt::Unchecked); + return; + } + + getApp()->getAccounts()->twitch.getCurrent()->blockUser( + this->userId_, this, + [this, reenableBlockCheckbox, currentUser] { + this->channel_->addSystemMessage( + QString("You successfully blocked user %1") + .arg(this->userName_)); + reenableBlockCheckbox(); + }, + [this, reenableBlockCheckbox] { + this->channel_->addSystemMessage( + QString("User %1 couldn't be blocked, an " + "unknown error occurred!") + .arg(this->userName_)); + reenableBlockCheckbox(); + }); + return; + } + + qCWarning(chatterinoWidget) + << "Unexpected check-state when blocking" << this->userName_ + << QMetaEnum::fromType().valueToKey(newState); }); // ignore highlights