From 3cb1e5158ab360776a98954aff9e79b2b2f5d6d7 Mon Sep 17 00:00:00 2001 From: apa420 <17131426+apa420@users.noreply.github.com> Date: Sat, 31 Jul 2021 16:15:43 +0200 Subject: [PATCH] Added the ability to add nicknames for users (#2981) Co-authored-by: Mm2PL Co-authored-by: Rasmus Karlsson --- CHANGELOG.md | 1 + chatterino.pro | 4 + src/CMakeLists.txt | 6 ++ src/controllers/nicknames/Nickname.hpp | 77 +++++++++++++++++++ src/controllers/nicknames/NicknamesModel.cpp | 31 ++++++++ src/controllers/nicknames/NicknamesModel.hpp | 25 ++++++ src/providers/twitch/TwitchMessageBuilder.cpp | 12 +++ src/singletons/Settings.cpp | 2 + src/singletons/Settings.hpp | 3 + src/widgets/dialogs/SettingsDialog.cpp | 2 + src/widgets/settingspages/NicknamesPage.cpp | 48 ++++++++++++ src/widgets/settingspages/NicknamesPage.hpp | 18 +++++ 12 files changed, 229 insertions(+) create mode 100644 src/controllers/nicknames/Nickname.hpp create mode 100644 src/controllers/nicknames/NicknamesModel.cpp create mode 100644 src/controllers/nicknames/NicknamesModel.hpp create mode 100644 src/widgets/settingspages/NicknamesPage.cpp create mode 100644 src/widgets/settingspages/NicknamesPage.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 30ee83b3..b4f66984 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unversioned - Major: Newly uploaded Twitch emotes are once again present in emote picker and can be autocompleted with Tab as well. (#2992) +- Major: Added the ability to add nicknames for users. (#137, #2981) - Minor: Added autocompletion in /whispers for Twitch emotes, Global Bttv/Ffz emotes and emojis. (#2999, #3033) - Minor: Received Twitch messages now use the exact same timestamp (obtained from Twitch's server) for every Chatterino user instead of assuming message timestamp on client's side. (#3021) - Minor: Received IRC messages use `time` message tag for timestamp if it's available. (#3021) diff --git a/chatterino.pro b/chatterino.pro index 032423d6..b858cec9 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -162,6 +162,7 @@ SOURCES += \ src/controllers/ignores/IgnoreModel.cpp \ src/controllers/moderationactions/ModerationAction.cpp \ src/controllers/moderationactions/ModerationActionModel.cpp \ + src/controllers/nicknames/NicknamesModel.cpp \ src/controllers/notifications/NotificationController.cpp \ src/controllers/notifications/NotificationModel.cpp \ src/controllers/pings/MutedChannelModel.cpp \ @@ -315,6 +316,7 @@ SOURCES += \ src/widgets/settingspages/IgnoresPage.cpp \ src/widgets/settingspages/KeyboardSettingsPage.cpp \ src/widgets/settingspages/ModerationPage.cpp \ + src/widgets/settingspages/NicknamesPage.cpp \ src/widgets/settingspages/NotificationPage.cpp \ src/widgets/settingspages/SettingsPage.cpp \ src/widgets/splits/ClosedSplits.cpp \ @@ -391,6 +393,8 @@ HEADERS += \ src/controllers/ignores/IgnorePhrase.hpp \ src/controllers/moderationactions/ModerationAction.hpp \ src/controllers/moderationactions/ModerationActionModel.hpp \ + src/controllers/nicknames/Nickname.hpp \ + src/controllers/nicknames/NicknamesModel.hpp \ src/controllers/notifications/NotificationController.hpp \ src/controllers/notifications/NotificationModel.hpp \ src/controllers/pings/MutedChannelModel.hpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 207f8c10..e935e736 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,6 +96,10 @@ set(SOURCE_FILES controllers/moderationactions/ModerationActionModel.cpp controllers/moderationactions/ModerationActionModel.hpp + controllers/nicknames/NicknamesModel.cpp + controllers/nicknames/NicknamesModel.hpp + controllers/nicknames/Nickname.hpp + controllers/notifications/NotificationController.cpp controllers/notifications/NotificationController.hpp controllers/notifications/NotificationModel.cpp @@ -428,6 +432,8 @@ set(SOURCE_FILES widgets/settingspages/KeyboardSettingsPage.hpp widgets/settingspages/ModerationPage.cpp widgets/settingspages/ModerationPage.hpp + widgets/settingspages/NicknamesPage.cpp + widgets/settingspages/NicknamesPage.hpp widgets/settingspages/NotificationPage.cpp widgets/settingspages/NotificationPage.hpp widgets/settingspages/SettingsPage.cpp diff --git a/src/controllers/nicknames/Nickname.hpp b/src/controllers/nicknames/Nickname.hpp new file mode 100644 index 00000000..67e7d3f4 --- /dev/null +++ b/src/controllers/nicknames/Nickname.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include "controllers/accounts/AccountController.hpp" + +#include "util/RapidJsonSerializeQString.hpp" +#include "util/RapidjsonHelpers.hpp" + +#include +#include + +#include + +namespace chatterino { + +class Nickname +{ +public: + Nickname(const QString &name, const QString &replace) + : name_(name) + , replace_(replace) + { + } + + const QString &name() const + { + return this->name_; + } + const QString &replace() const + { + return this->replace_; + } + +private: + QString name_; + QString replace_; +}; + +} // namespace chatterino + +namespace pajlada { + +template <> +struct Serialize { + static rapidjson::Value get(const chatterino::Nickname &value, + rapidjson::Document::AllocatorType &a) + { + rapidjson::Value ret(rapidjson::kObjectType); + + chatterino::rj::set(ret, "name", value.name(), a); + chatterino::rj::set(ret, "replace", value.replace(), a); + + return ret; + } +}; + +template <> +struct Deserialize { + static chatterino::Nickname get(const rapidjson::Value &value, + bool *error = nullptr) + { + if (!value.IsObject()) + { + PAJLADA_REPORT_ERROR(error) + return chatterino::Nickname(QString(), QString()); + } + + QString _name; + QString _replace; + + chatterino::rj::getSafe(value, "name", _name); + chatterino::rj::getSafe(value, "replace", _replace); + + return chatterino::Nickname(_name, _replace); + } +}; + +} // namespace pajlada diff --git a/src/controllers/nicknames/NicknamesModel.cpp b/src/controllers/nicknames/NicknamesModel.cpp new file mode 100644 index 00000000..703c6661 --- /dev/null +++ b/src/controllers/nicknames/NicknamesModel.cpp @@ -0,0 +1,31 @@ +#include "NicknamesModel.hpp" + +#include "Application.hpp" +#include "providers/twitch/api/Helix.hpp" +#include "singletons/Settings.hpp" +#include "util/StandardItemHelper.hpp" + +namespace chatterino { + +NicknamesModel::NicknamesModel(QObject *parent) + : SignalVectorModel(2, parent) +{ +} + +// turn a vector item into a model row +Nickname NicknamesModel::getItemFromRow(std::vector &row, + const Nickname &original) +{ + return Nickname{row[0]->data(Qt::DisplayRole).toString(), + row[1]->data(Qt::DisplayRole).toString()}; +} + +// turns a row in the model into a vector item +void NicknamesModel::getRowFromItem(const Nickname &item, + std::vector &row) +{ + setStringItem(row[0], item.name()); + setStringItem(row[1], item.replace()); +} + +} // namespace chatterino diff --git a/src/controllers/nicknames/NicknamesModel.hpp b/src/controllers/nicknames/NicknamesModel.hpp new file mode 100644 index 00000000..f7947a7f --- /dev/null +++ b/src/controllers/nicknames/NicknamesModel.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "common/SignalVectorModel.hpp" +#include "controllers/nicknames/Nickname.hpp" + +namespace chatterino { + +class NicknamesModel : public SignalVectorModel +{ +public: + explicit NicknamesModel(QObject *parent); + +protected: + // turn a vector item into a model row + virtual Nickname getItemFromRow(std::vector &row, + const Nickname &original) override; + + // turns a row in the model into a vector item + virtual void getRowFromItem(const Nickname &item, + std::vector &row) override; +}; + +} // namespace chatterino diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index ed862ca4..f7910479 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -690,6 +690,18 @@ void TwitchMessageBuilder::appendUsername() break; } + auto nicknames = getCSettings().nicknames.readOnly(); + auto loginLower = this->message().loginName.toLower(); + + for (const auto &nickname : *nicknames) + { + if (nickname.name().toLower() == loginLower) + { + usernameText = nickname.replace(); + break; + } + } + if (this->args.isSentWhisper) { // TODO(pajlada): Re-implement diff --git a/src/singletons/Settings.cpp b/src/singletons/Settings.cpp index c7acb331..f8162091 100644 --- a/src/singletons/Settings.cpp +++ b/src/singletons/Settings.cpp @@ -23,6 +23,7 @@ ConcurrentSettings::ConcurrentSettings() , ignoredMessages(*new SignalVector()) , mutedChannels(*new SignalVector()) , filterRecords(*new SignalVector()) + , nicknames(*new SignalVector()) , moderationActions(*new SignalVector) { persist(this->highlightedMessages, "/highlighting/highlights"); @@ -32,6 +33,7 @@ ConcurrentSettings::ConcurrentSettings() persist(this->ignoredMessages, "/ignore/phrases"); persist(this->mutedChannels, "/pings/muted"); persist(this->filterRecords, "/filtering/filters"); + persist(this->nicknames, "/nicknames"); // tagged users? persist(this->moderationActions, "/moderation/actions"); } diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 808e7656..703fefbd 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -10,6 +10,7 @@ #include "controllers/highlights/HighlightBadge.hpp" #include "controllers/highlights/HighlightPhrase.hpp" #include "controllers/moderationactions/ModerationAction.hpp" +#include "controllers/nicknames/Nickname.hpp" #include "singletons/Toasts.hpp" #include "util/StreamerMode.hpp" #include "widgets/Notebook.hpp" @@ -23,6 +24,7 @@ class HighlightBlacklistUser; class IgnorePhrase; class TaggedUser; class FilterRecord; +class Nickname; /// Settings which are availlable for reading on all threads. class ConcurrentSettings @@ -37,6 +39,7 @@ public: SignalVector &ignoredMessages; SignalVector &mutedChannels; SignalVector &filterRecords; + SignalVector &nicknames; //SignalVector &taggedUsers; SignalVector &moderationActions; diff --git a/src/widgets/dialogs/SettingsDialog.cpp b/src/widgets/dialogs/SettingsDialog.cpp index ccd5fbee..47db42b4 100644 --- a/src/widgets/dialogs/SettingsDialog.cpp +++ b/src/widgets/dialogs/SettingsDialog.cpp @@ -17,6 +17,7 @@ #include "widgets/settingspages/IgnoresPage.hpp" #include "widgets/settingspages/KeyboardSettingsPage.hpp" #include "widgets/settingspages/ModerationPage.hpp" +#include "widgets/settingspages/NicknamesPage.hpp" #include "widgets/settingspages/NotificationPage.hpp" #include @@ -164,6 +165,7 @@ void SettingsDialog::addTabs() this->addTab([]{return new GeneralPage;}, "General", ":/settings/about.svg"); this->ui_.tabContainer->addSpacing(16); this->addTab([]{return new AccountsPage;}, "Accounts", ":/settings/accounts.svg", SettingsTabId::Accounts); + this->addTab([]{return new NicknamesPage;}, "Nicknames", ":/settings/accounts.svg"); this->ui_.tabContainer->addSpacing(16); this->addTab([]{return new CommandPage;}, "Commands", ":/settings/commands.svg"); this->addTab([]{return new HighlightingPage;}, "Highlights", ":/settings/notifications.svg"); diff --git a/src/widgets/settingspages/NicknamesPage.cpp b/src/widgets/settingspages/NicknamesPage.cpp new file mode 100644 index 00000000..2a464d7c --- /dev/null +++ b/src/widgets/settingspages/NicknamesPage.cpp @@ -0,0 +1,48 @@ +#include "NicknamesPage.hpp" + +#include "controllers/nicknames/NicknamesModel.hpp" +#include "singletons/Settings.hpp" +#include "singletons/WindowManager.hpp" +#include "util/LayoutCreator.hpp" +#include "widgets/Window.hpp" +#include "widgets/helper/EditableModelView.hpp" + +#include + +#include + +namespace chatterino { + +NicknamesPage::NicknamesPage() +{ + LayoutCreator layoutCreator(this); + auto layout = layoutCreator.setLayoutType(); + + layout.emplace( + "Nicknames do not work with features such as search or user highlights." + "\nWith those features you will still need to use the user's original " + "name."); + EditableModelView *view = + layout + .emplace( + (new NicknamesModel(nullptr)) + ->initialized(&getSettings()->nicknames)) + .getElement(); + + view->setTitles({"Username", "Nickname"}); + view->getTableView()->horizontalHeader()->setSectionResizeMode( + QHeaderView::Interactive); + view->getTableView()->horizontalHeader()->setSectionResizeMode( + 1, QHeaderView::Stretch); + + view->addButtonPressed.connect([] { + getSettings()->nicknames.append(Nickname{"Username", "Nickname"}); + }); + + QTimer::singleShot(1, [view] { + view->getTableView()->resizeColumnsToContents(); + view->getTableView()->setColumnWidth(0, 250); + }); +} + +} // namespace chatterino diff --git a/src/widgets/settingspages/NicknamesPage.hpp b/src/widgets/settingspages/NicknamesPage.hpp new file mode 100644 index 00000000..59b2f710 --- /dev/null +++ b/src/widgets/settingspages/NicknamesPage.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "widgets/helper/EditableModelView.hpp" +#include "widgets/settingspages/SettingsPage.hpp" + +#include + +class QVBoxLayout; + +namespace chatterino { + +class NicknamesPage : public SettingsPage +{ +public: + NicknamesPage(); +}; + +} // namespace chatterino