feat: show warning before blocking followed channel (#5615)

This commit is contained in:
nerix 2024-11-03 13:29:57 +01:00 committed by GitHub
parent 8220a1fbd4
commit d3000ba597
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 93 additions and 52 deletions

View file

@ -34,6 +34,7 @@
- Minor: Moderators can now see which mods start and cancel raids. (#5563) - 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: The emote popup now reloads when Twitch emotes are reloaded. (#5580)
- Minor: Added `--login <username>` CLI argument to specify which account to start logged in as. (#5626) - Minor: Added `--login <username>` 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: Indicate when subscriptions and resubscriptions are for multiple months. (#5642)
- Minor: Proxy URL information is now included in the `/debug-env` command. (#5648) - Minor: Proxy URL information is now included in the `/debug-env` command. (#5648)
- Minor: Make raid entry message usernames clickable. (#5651) - Minor: Make raid entry message usernames clickable. (#5651)

View file

@ -422,7 +422,7 @@ public:
// get followed channel // get followed channel
MOCK_METHOD( MOCK_METHOD(
void, getFollowedChannel, void, getFollowedChannel,
(QString userID, QString broadcasterID, (QString userID, QString broadcasterID, const QObject *caller,
ResultCallback<std::optional<HelixFollowedChannel>> successCallback, ResultCallback<std::optional<HelixFollowedChannel>> successCallback,
FailureCallback<QString> failureCallback), FailureCallback<QString> failureCallback),
(override)); (override));

View file

@ -274,7 +274,7 @@ void TwitchChannel::refreshTwitchChannelEmotes(bool manualRefresh)
getHelix()->getFollowedChannel( getHelix()->getFollowedChannel(
getApp()->getAccounts()->twitch.getCurrent()->getUserId(), getApp()->getAccounts()->twitch.getCurrent()->getUserId(),
this->roomId(), this->roomId(), nullptr,
[weak{this->weak_from_this()}, makeEmotes](const auto &chan) { [weak{this->weak_from_this()}, makeEmotes](const auto &chan) {
auto self = std::dynamic_pointer_cast<TwitchChannel>(weak.lock()); auto self = std::dynamic_pointer_cast<TwitchChannel>(weak.lock());
if (!self || !chan) if (!self || !chan)

View file

@ -3138,7 +3138,7 @@ void Helix::getUserEmotes(
} }
void Helix::getFollowedChannel( void Helix::getFollowedChannel(
QString userID, QString broadcasterID, QString userID, QString broadcasterID, const QObject *caller,
ResultCallback<std::optional<HelixFollowedChannel>> successCallback, ResultCallback<std::optional<HelixFollowedChannel>> successCallback,
FailureCallback<QString> failureCallback) FailureCallback<QString> failureCallback)
{ {
@ -3147,6 +3147,7 @@ void Helix::getFollowedChannel(
{u"user_id"_s, userID}, {u"user_id"_s, userID},
{u"broadcaster_id"_s, broadcasterID}, {u"broadcaster_id"_s, broadcasterID},
}) })
.caller(caller)
.onSuccess([successCallback](auto result) { .onSuccess([successCallback](auto result) {
if (result.status() != 200) if (result.status() != 200)
{ {

View file

@ -1143,7 +1143,7 @@ public:
/// https://dev.twitch.tv/docs/api/reference/#get-followed-channels /// https://dev.twitch.tv/docs/api/reference/#get-followed-channels
/// (non paginated) /// (non paginated)
virtual void getFollowedChannel( virtual void getFollowedChannel(
QString userID, QString broadcasterID, QString userID, QString broadcasterID, const QObject *caller,
ResultCallback<std::optional<HelixFollowedChannel>> successCallback, ResultCallback<std::optional<HelixFollowedChannel>> successCallback,
FailureCallback<QString> failureCallback) = 0; FailureCallback<QString> failureCallback) = 0;
@ -1486,7 +1486,7 @@ public:
/// https://dev.twitch.tv/docs/api/reference/#get-followed-channels /// https://dev.twitch.tv/docs/api/reference/#get-followed-channels
/// (non paginated) /// (non paginated)
void getFollowedChannel( void getFollowedChannel(
QString userID, QString broadcasterID, QString userID, QString broadcasterID, const QObject *caller,
ResultCallback<std::optional<HelixFollowedChannel>> successCallback, ResultCallback<std::optional<HelixFollowedChannel>> successCallback,
FailureCallback<QString> failureCallback) final; FailureCallback<QString> failureCallback) final;

View file

@ -41,6 +41,7 @@ DraggablePopup::DraggablePopup(bool closeAutomatically, QWidget *parent)
BaseWindow::ClearBuffersOnDpiChange, BaseWindow::ClearBuffersOnDpiChange,
parent) parent)
, lifetimeHack_(std::make_shared<bool>(false)) , lifetimeHack_(std::make_shared<bool>(false))
, closeAutomatically_(closeAutomatically)
, dragTimer_(this) , dragTimer_(this)
{ {
@ -128,4 +129,14 @@ Button *DraggablePopup::createPinButton()
return this->pinButton_; return this->pinButton_;
} }
bool DraggablePopup::ensurePinned()
{
if (this->closeAutomatically_ && !this->isPinned_)
{
this->togglePinned();
return true;
}
return false;
}
} // namespace chatterino } // namespace chatterino

View file

@ -38,10 +38,18 @@ protected:
// button pixmap // button pixmap
void togglePinned(); 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: 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_) // 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 isMoving_ = false;
bool closeAutomatically_ = false;
// startPosDrag_ is the coordinates where the user originally pressed the mouse button down to start dragging // startPosDrag_ is the coordinates where the user originally pressed the mouse button down to start dragging
QPoint startPosDrag_; QPoint startPosDrag_;

View file

@ -2,6 +2,7 @@
#include "Application.hpp" #include "Application.hpp"
#include "common/Channel.hpp" #include "common/Channel.hpp"
#include "common/Literals.hpp"
#include "common/network/NetworkRequest.hpp" #include "common/network/NetworkRequest.hpp"
#include "common/QLogging.hpp" #include "common/QLogging.hpp"
#include "controllers/accounts/AccountController.hpp" #include "controllers/accounts/AccountController.hpp"
@ -37,6 +38,8 @@
#include <QCheckBox> #include <QCheckBox>
#include <QDesktopServices> #include <QDesktopServices>
#include <QMessageBox>
#include <QMetaEnum>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkReply> #include <QNetworkReply>
#include <QPointer> #include <QPointer>
@ -141,6 +144,8 @@ int calculateTimeoutDuration(TimeoutButton timeout)
namespace chatterino { namespace chatterino {
using namespace literals;
UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split)
: DraggablePopup(closeAutomatically, split) : DraggablePopup(closeAutomatically, split)
, split_(split) , split_(split)
@ -623,9 +628,8 @@ void UserInfoPopup::installEvents()
return; 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( getApp()->getAccounts()->twitch.getCurrent()->unblockUser(
@ -638,23 +642,37 @@ void UserInfoPopup::installEvents()
}, },
[this, reenableBlockCheckbox] { [this, reenableBlockCheckbox] {
this->channel_->addSystemMessage( this->channel_->addSystemMessage(
QString( QString("User %1 couldn't be unblocked, an unknown "
"User %1 couldn't be unblocked, an unknown "
"error occurred!") "error occurred!")
.arg(this->userName_)); .arg(this->userName_));
reenableBlockCheckbox(); reenableBlockCheckbox();
}); });
return;
} }
break;
case Qt::CheckState::PartiallyChecked: { if (newState == Qt::Checked)
// We deliberately ignore this state {
}
break;
case Qt::CheckState::Checked: {
this->ui_.block->setEnabled(false); 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( getApp()->getAccounts()->twitch.getCurrent()->blockUser(
this->userId_, this, this->userId_, this,
[this, reenableBlockCheckbox, currentUser] { [this, reenableBlockCheckbox, currentUser] {
@ -665,15 +683,17 @@ void UserInfoPopup::installEvents()
}, },
[this, reenableBlockCheckbox] { [this, reenableBlockCheckbox] {
this->channel_->addSystemMessage( this->channel_->addSystemMessage(
QString( QString("User %1 couldn't be blocked, an "
"User %1 couldn't be blocked, an unknown " "unknown error occurred!")
"error occurred!")
.arg(this->userName_)); .arg(this->userName_));
reenableBlockCheckbox(); reenableBlockCheckbox();
}); });
return;
} }
break;
} qCWarning(chatterinoWidget)
<< "Unexpected check-state when blocking" << this->userName_
<< QMetaEnum::fromType<Qt::CheckState>().valueToKey(newState);
}); });
// ignore highlights // ignore highlights