mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Deprecated /(un)follow commands and respective usercard action (#3078)
/(un)follow commands are marked as deprecated and link to the issue this PR is closing. follow button on the usercard is removed completely Co-authored-by: pajlada <rasmus.karlsson@pajlada.com> Co-authored-by: Felanbird <41973452+Felanbird@users.noreply.github.com>
This commit is contained in:
parent
28dcdb238b
commit
0c5abb8149
9 changed files with 17 additions and 270 deletions
|
@ -3,6 +3,7 @@
|
||||||
## Unversioned
|
## Unversioned
|
||||||
|
|
||||||
- Major: Newly uploaded Twitch emotes are once again present in emote picker and can be autocompleted with Tab as well. (#2992)
|
- Major: Newly uploaded Twitch emotes are once again present in emote picker and can be autocompleted with Tab as well. (#2992)
|
||||||
|
- Major: Deprecated `/(un)follow` commands and (un)following in the usercards as Twitch has removed this feature for 3rd party applications. (#3076, #3078)
|
||||||
- Major: Added the ability to add nicknames for users. (#137, #2981)
|
- Major: Added the ability to add nicknames for users. (#137, #2981)
|
||||||
- Major: Work on rate-limiting JOINs and PARTs. (#3112)
|
- Major: Work on rate-limiting JOINs and PARTs. (#3112)
|
||||||
- Minor: Added autocompletion in /whispers for Twitch emotes, Global Bttv/Ffz emotes and emojis. (#2999, #3033)
|
- Minor: Added autocompletion in /whispers for Twitch emotes, Global Bttv/Ffz emotes and emojis. (#2999, #3033)
|
||||||
|
|
|
@ -373,6 +373,22 @@ void CommandController::initialize(Settings &, Paths &paths)
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this->registerCommand("/follow", [](const auto &words, auto channel) {
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
"Twitch has removed the ability to follow users through "
|
||||||
|
"third-party applications. For more information, see "
|
||||||
|
"https://github.com/Chatterino/chatterino2/issues/3076"));
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
this->registerCommand("/unfollow", [](const auto &words, auto channel) {
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
"Twitch has removed the ability to unfollow users through "
|
||||||
|
"third-party applications. For more information, see "
|
||||||
|
"https://github.com/Chatterino/chatterino2/issues/3076"));
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
/// Supported commands
|
/// Supported commands
|
||||||
|
|
||||||
this->registerCommand(
|
this->registerCommand(
|
||||||
|
@ -407,90 +423,6 @@ void CommandController::initialize(Settings &, Paths &paths)
|
||||||
|
|
||||||
this->registerCommand("/unblock", unblockLambda);
|
this->registerCommand("/unblock", unblockLambda);
|
||||||
|
|
||||||
this->registerCommand("/follow", [](const auto &words, auto channel) {
|
|
||||||
if (words.size() < 2)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage("Usage: /follow [user]"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage("You must be logged in to follow someone!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto target = words.at(1);
|
|
||||||
|
|
||||||
getHelix()->getUserByName(
|
|
||||||
target,
|
|
||||||
[currentUser, channel, target](const auto &targetUser) {
|
|
||||||
getHelix()->followUser(
|
|
||||||
currentUser->getUserId(), targetUser.id,
|
|
||||||
[channel, target]() {
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You successfully followed " + target));
|
|
||||||
},
|
|
||||||
[channel, target]() {
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
QString("User %1 could not be followed, an unknown "
|
|
||||||
"error occurred!")
|
|
||||||
.arg(target)));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[channel, target] {
|
|
||||||
channel->addMessage(
|
|
||||||
makeSystemMessage(QString("User %1 could not be followed, "
|
|
||||||
"no user with that name found!")
|
|
||||||
.arg(target)));
|
|
||||||
});
|
|
||||||
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand("/unfollow", [](const auto &words, auto channel) {
|
|
||||||
if (words.size() < 2)
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage("Usage: /unfollow [user]"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
|
|
||||||
if (currentUser->isAnon())
|
|
||||||
{
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You must be logged in to unfollow someone!"));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto target = words.at(1);
|
|
||||||
|
|
||||||
getHelix()->getUserByName(
|
|
||||||
target,
|
|
||||||
[currentUser, channel, target](const auto &targetUser) {
|
|
||||||
getHelix()->unfollowUser(
|
|
||||||
currentUser->getUserId(), targetUser.id,
|
|
||||||
[channel, target]() {
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"You successfully unfollowed " + target));
|
|
||||||
},
|
|
||||||
[channel, target]() {
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
"An error occurred while unfollowing " + target));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[channel, target] {
|
|
||||||
channel->addMessage(makeSystemMessage(
|
|
||||||
QString("User %1 could not be followed!").arg(target)));
|
|
||||||
});
|
|
||||||
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this->registerCommand("/user", [](const auto &words, auto channel) {
|
this->registerCommand("/user", [](const auto &words, auto channel) {
|
||||||
if (words.size() < 2)
|
if (words.size() < 2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -186,23 +186,6 @@ void TwitchAccount::unblockUser(QString userId, std::function<void()> onSuccess,
|
||||||
std::move(onFailure));
|
std::move(onFailure));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchAccount::checkFollow(const QString targetUserID,
|
|
||||||
std::function<void(FollowResult)> onFinished)
|
|
||||||
{
|
|
||||||
const auto onResponse = [onFinished](bool following, const auto &record) {
|
|
||||||
if (!following)
|
|
||||||
{
|
|
||||||
onFinished(FollowResult_NotFollowing);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
onFinished(FollowResult_Following);
|
|
||||||
};
|
|
||||||
|
|
||||||
getHelix()->getUserFollow(this->getUserId(), targetUserID, onResponse,
|
|
||||||
[] {});
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedAccessGuard<const std::set<TwitchUser>> TwitchAccount::accessBlocks()
|
SharedAccessGuard<const std::set<TwitchUser>> TwitchAccount::accessBlocks()
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
|
|
|
@ -108,9 +108,6 @@ public:
|
||||||
void unblockUser(QString userId, std::function<void()> onSuccess,
|
void unblockUser(QString userId, std::function<void()> onSuccess,
|
||||||
std::function<void()> onFailure);
|
std::function<void()> onFailure);
|
||||||
|
|
||||||
void checkFollow(const QString targetUserID,
|
|
||||||
std::function<void(FollowResult)> onFinished);
|
|
||||||
|
|
||||||
SharedAccessGuard<const std::set<QString>> accessBlockedUserIds() const;
|
SharedAccessGuard<const std::set<QString>> accessBlockedUserIds() const;
|
||||||
SharedAccessGuard<const std::set<TwitchUser>> accessBlocks() const;
|
SharedAccessGuard<const std::set<TwitchUser>> accessBlocks() const;
|
||||||
|
|
||||||
|
|
|
@ -142,25 +142,6 @@ void Helix::getUserFollowers(
|
||||||
std::move(failureCallback));
|
std::move(failureCallback));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Helix::getUserFollow(
|
|
||||||
QString userId, QString targetId,
|
|
||||||
ResultCallback<bool, HelixUsersFollowsRecord> successCallback,
|
|
||||||
HelixFailureCallback failureCallback)
|
|
||||||
{
|
|
||||||
this->fetchUsersFollows(
|
|
||||||
std::move(userId), std::move(targetId),
|
|
||||||
[successCallback](const auto &response) {
|
|
||||||
if (response.data.empty())
|
|
||||||
{
|
|
||||||
successCallback(false, HelixUsersFollowsRecord());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
successCallback(true, response.data[0]);
|
|
||||||
},
|
|
||||||
std::move(failureCallback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Helix::fetchStreams(
|
void Helix::fetchStreams(
|
||||||
QStringList userIds, QStringList userLogins,
|
QStringList userIds, QStringList userLogins,
|
||||||
ResultCallback<std::vector<HelixStream>> successCallback,
|
ResultCallback<std::vector<HelixStream>> successCallback,
|
||||||
|
@ -354,50 +335,6 @@ void Helix::getGameById(QString gameId,
|
||||||
failureCallback);
|
failureCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Helix::followUser(QString userId, QString targetId,
|
|
||||||
std::function<void()> successCallback,
|
|
||||||
HelixFailureCallback failureCallback)
|
|
||||||
{
|
|
||||||
QUrlQuery urlQuery;
|
|
||||||
|
|
||||||
urlQuery.addQueryItem("from_id", userId);
|
|
||||||
urlQuery.addQueryItem("to_id", targetId);
|
|
||||||
|
|
||||||
this->makeRequest("users/follows", urlQuery)
|
|
||||||
.type(NetworkRequestType::Post)
|
|
||||||
.onSuccess([successCallback](auto /*result*/) -> Outcome {
|
|
||||||
successCallback();
|
|
||||||
return Success;
|
|
||||||
})
|
|
||||||
.onError([failureCallback](auto /*result*/) {
|
|
||||||
// TODO: make better xd
|
|
||||||
failureCallback();
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Helix::unfollowUser(QString userId, QString targetId,
|
|
||||||
std::function<void()> successCallback,
|
|
||||||
HelixFailureCallback failureCallback)
|
|
||||||
{
|
|
||||||
QUrlQuery urlQuery;
|
|
||||||
|
|
||||||
urlQuery.addQueryItem("from_id", userId);
|
|
||||||
urlQuery.addQueryItem("to_id", targetId);
|
|
||||||
|
|
||||||
this->makeRequest("users/follows", urlQuery)
|
|
||||||
.type(NetworkRequestType::Delete)
|
|
||||||
.onSuccess([successCallback](auto /*result*/) -> Outcome {
|
|
||||||
successCallback();
|
|
||||||
return Success;
|
|
||||||
})
|
|
||||||
.onError([failureCallback](auto /*result*/) {
|
|
||||||
// TODO: make better xd
|
|
||||||
failureCallback();
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Helix::createClip(QString channelId,
|
void Helix::createClip(QString channelId,
|
||||||
ResultCallback<HelixClip> successCallback,
|
ResultCallback<HelixClip> successCallback,
|
||||||
std::function<void(HelixClipError)> failureCallback,
|
std::function<void(HelixClipError)> failureCallback,
|
||||||
|
|
|
@ -341,11 +341,6 @@ public:
|
||||||
ResultCallback<HelixUsersFollowsResponse> successCallback,
|
ResultCallback<HelixUsersFollowsResponse> successCallback,
|
||||||
HelixFailureCallback failureCallback);
|
HelixFailureCallback failureCallback);
|
||||||
|
|
||||||
void getUserFollow(
|
|
||||||
QString userId, QString targetId,
|
|
||||||
ResultCallback<bool, HelixUsersFollowsRecord> successCallback,
|
|
||||||
HelixFailureCallback failureCallback);
|
|
||||||
|
|
||||||
// https://dev.twitch.tv/docs/api/reference#get-streams
|
// https://dev.twitch.tv/docs/api/reference#get-streams
|
||||||
void fetchStreams(QStringList userIds, QStringList userLogins,
|
void fetchStreams(QStringList userIds, QStringList userLogins,
|
||||||
ResultCallback<std::vector<HelixStream>> successCallback,
|
ResultCallback<std::vector<HelixStream>> successCallback,
|
||||||
|
@ -372,16 +367,6 @@ public:
|
||||||
void getGameById(QString gameId, ResultCallback<HelixGame> successCallback,
|
void getGameById(QString gameId, ResultCallback<HelixGame> successCallback,
|
||||||
HelixFailureCallback failureCallback);
|
HelixFailureCallback failureCallback);
|
||||||
|
|
||||||
// https://dev.twitch.tv/docs/api/reference#create-user-follows
|
|
||||||
void followUser(QString userId, QString targetId,
|
|
||||||
std::function<void()> successCallback,
|
|
||||||
HelixFailureCallback failureCallback);
|
|
||||||
|
|
||||||
// https://dev.twitch.tv/docs/api/reference#delete-user-follows
|
|
||||||
void unfollowUser(QString userId, QString targetlId,
|
|
||||||
std::function<void()> successCallback,
|
|
||||||
HelixFailureCallback failureCallback);
|
|
||||||
|
|
||||||
// https://dev.twitch.tv/docs/api/reference#create-clip
|
// https://dev.twitch.tv/docs/api/reference#create-clip
|
||||||
void createClip(QString channelId,
|
void createClip(QString channelId,
|
||||||
ResultCallback<HelixClip> successCallback,
|
ResultCallback<HelixClip> successCallback,
|
||||||
|
|
|
@ -47,26 +47,6 @@ URL: https://dev.twitch.tv/docs/api/reference#get-streams
|
||||||
- `TwitchChannel` to get live status, game, title, and viewer count of a channel
|
- `TwitchChannel` to get live status, game, title, and viewer count of a channel
|
||||||
- `NotificationController` to provide notifications for channels you might not have open in Chatterino, but are still interested in getting notifications for
|
- `NotificationController` to provide notifications for channels you might not have open in Chatterino, but are still interested in getting notifications for
|
||||||
|
|
||||||
### Follow User
|
|
||||||
|
|
||||||
URL: https://dev.twitch.tv/docs/api/reference#create-user-follows
|
|
||||||
Requires `user:edit:follows` scope
|
|
||||||
|
|
||||||
- We implement this in `providers/twitch/api/Helix.cpp followUser`
|
|
||||||
Used in:
|
|
||||||
- `widgets/dialogs/UserInfoPopup.cpp` to follow a user by ticking follow checkbox in usercard
|
|
||||||
- `controllers/commands/CommandController.cpp` in /follow command
|
|
||||||
|
|
||||||
### Unfollow User
|
|
||||||
|
|
||||||
URL: https://dev.twitch.tv/docs/api/reference#delete-user-follows
|
|
||||||
Requires `user:edit:follows` scope
|
|
||||||
|
|
||||||
- We implement this in `providers/twitch/api/Helix.cpp unfollowUser`
|
|
||||||
Used in:
|
|
||||||
- `widgets/dialogs/UserInfoPopup.cpp` to unfollow a user by unticking follow checkbox in usercard
|
|
||||||
- `controllers/commands/CommandController.cpp` in /unfollow command
|
|
||||||
|
|
||||||
### Create Clip
|
### Create Clip
|
||||||
|
|
||||||
URL: https://dev.twitch.tv/docs/api/reference#create-clip
|
URL: https://dev.twitch.tv/docs/api/reference#create-clip
|
||||||
|
|
|
@ -233,7 +233,6 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent)
|
||||||
{
|
{
|
||||||
user->addStretch(1);
|
user->addStretch(1);
|
||||||
|
|
||||||
user.emplace<QCheckBox>("Follow").assign(&this->ui_.follow);
|
|
||||||
user.emplace<QCheckBox>("Block").assign(&this->ui_.block);
|
user.emplace<QCheckBox>("Block").assign(&this->ui_.block);
|
||||||
user.emplace<QCheckBox>("Ignore highlights")
|
user.emplace<QCheckBox>("Ignore highlights")
|
||||||
.assign(&this->ui_.ignoreHighlights);
|
.assign(&this->ui_.ignoreHighlights);
|
||||||
|
@ -403,56 +402,6 @@ void UserInfoPopup::scaleChangedEvent(float /*scale*/)
|
||||||
|
|
||||||
void UserInfoPopup::installEvents()
|
void UserInfoPopup::installEvents()
|
||||||
{
|
{
|
||||||
std::weak_ptr<bool> hack = this->hack_;
|
|
||||||
|
|
||||||
// follow
|
|
||||||
QObject::connect(
|
|
||||||
this->ui_.follow, &QCheckBox::stateChanged,
|
|
||||||
[this](int newState) mutable {
|
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
|
||||||
|
|
||||||
const auto reenableFollowCheckbox = [this] {
|
|
||||||
this->ui_.follow->setEnabled(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!this->ui_.follow->isEnabled())
|
|
||||||
{
|
|
||||||
// We received a state update while the checkbox was disabled
|
|
||||||
// This can only happen from the "check current follow state" call
|
|
||||||
// The state has been updated to properly reflect the users current follow state
|
|
||||||
reenableFollowCheckbox();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (newState)
|
|
||||||
{
|
|
||||||
case Qt::CheckState::Unchecked: {
|
|
||||||
this->ui_.follow->setEnabled(false);
|
|
||||||
getHelix()->unfollowUser(currentUser->getUserId(),
|
|
||||||
this->userId_,
|
|
||||||
reenableFollowCheckbox, [] {
|
|
||||||
//
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Qt::CheckState::PartiallyChecked: {
|
|
||||||
// We deliberately ignore this state
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Qt::CheckState::Checked: {
|
|
||||||
this->ui_.follow->setEnabled(false);
|
|
||||||
getHelix()->followUser(currentUser->getUserId(),
|
|
||||||
this->userId_,
|
|
||||||
reenableFollowCheckbox, [] {
|
|
||||||
//
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
std::shared_ptr<bool> ignoreNext = std::make_shared<bool>(false);
|
std::shared_ptr<bool> ignoreNext = std::make_shared<bool>(false);
|
||||||
|
|
||||||
// block
|
// block
|
||||||
|
@ -616,8 +565,6 @@ void UserInfoPopup::updateLatestMessages()
|
||||||
|
|
||||||
void UserInfoPopup::updateUserData()
|
void UserInfoPopup::updateUserData()
|
||||||
{
|
{
|
||||||
this->ui_.follow->setEnabled(false);
|
|
||||||
|
|
||||||
std::weak_ptr<bool> hack = this->hack_;
|
std::weak_ptr<bool> hack = this->hack_;
|
||||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||||
|
|
||||||
|
@ -683,19 +630,6 @@ void UserInfoPopup::updateUserData()
|
||||||
// on failure
|
// on failure
|
||||||
});
|
});
|
||||||
|
|
||||||
// get follow state
|
|
||||||
currentUser->checkFollow(user.id, [this, hack](auto result) {
|
|
||||||
if (!hack.lock())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (result != FollowResult_Failed)
|
|
||||||
{
|
|
||||||
this->ui_.follow->setChecked(result == FollowResult_Following);
|
|
||||||
this->ui_.follow->setEnabled(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// get ignore state
|
// get ignore state
|
||||||
bool isIgnoring = false;
|
bool isIgnoring = false;
|
||||||
|
|
||||||
|
@ -772,7 +706,6 @@ void UserInfoPopup::updateUserData()
|
||||||
getHelix()->getUserByName(this->userName_, onUserFetched,
|
getHelix()->getUserByName(this->userName_, onUserFetched,
|
||||||
onUserFetchFailed);
|
onUserFetchFailed);
|
||||||
|
|
||||||
this->ui_.follow->setEnabled(false);
|
|
||||||
this->ui_.block->setEnabled(false);
|
this->ui_.block->setEnabled(false);
|
||||||
this->ui_.ignoreHighlights->setEnabled(false);
|
this->ui_.ignoreHighlights->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,6 @@ private:
|
||||||
Label *followageLabel = nullptr;
|
Label *followageLabel = nullptr;
|
||||||
Label *subageLabel = nullptr;
|
Label *subageLabel = nullptr;
|
||||||
|
|
||||||
QCheckBox *follow = nullptr;
|
|
||||||
QCheckBox *block = nullptr;
|
QCheckBox *block = nullptr;
|
||||||
QCheckBox *ignoreHighlights = nullptr;
|
QCheckBox *ignoreHighlights = nullptr;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue