Added the ability to add nicknames for users (#2981)

Co-authored-by: Mm2PL <mm2pl+gh@kotmisia.pl>
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
apa420 2021-07-31 16:15:43 +02:00 committed by GitHub
parent 3238d1f801
commit 3cb1e5158a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 229 additions and 0 deletions

View file

@ -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)

View file

@ -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 \

View file

@ -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

View file

@ -0,0 +1,77 @@
#pragma once
#include "controllers/accounts/AccountController.hpp"
#include "util/RapidJsonSerializeQString.hpp"
#include "util/RapidjsonHelpers.hpp"
#include <QString>
#include <pajlada/serialize.hpp>
#include <memory>
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<chatterino::Nickname> {
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<chatterino::Nickname> {
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

View file

@ -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<Nickname>(2, parent)
{
}
// turn a vector item into a model row
Nickname NicknamesModel::getItemFromRow(std::vector<QStandardItem *> &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<QStandardItem *> &row)
{
setStringItem(row[0], item.name());
setStringItem(row[1], item.replace());
}
} // namespace chatterino

View file

@ -0,0 +1,25 @@
#pragma once
#include <QObject>
#include "common/SignalVectorModel.hpp"
#include "controllers/nicknames/Nickname.hpp"
namespace chatterino {
class NicknamesModel : public SignalVectorModel<Nickname>
{
public:
explicit NicknamesModel(QObject *parent);
protected:
// turn a vector item into a model row
virtual Nickname getItemFromRow(std::vector<QStandardItem *> &row,
const Nickname &original) override;
// turns a row in the model into a vector item
virtual void getRowFromItem(const Nickname &item,
std::vector<QStandardItem *> &row) override;
};
} // namespace chatterino

View file

@ -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

View file

@ -23,6 +23,7 @@ ConcurrentSettings::ConcurrentSettings()
, ignoredMessages(*new SignalVector<IgnorePhrase>())
, mutedChannels(*new SignalVector<QString>())
, filterRecords(*new SignalVector<FilterRecordPtr>())
, nicknames(*new SignalVector<Nickname>())
, moderationActions(*new SignalVector<ModerationAction>)
{
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");
}

View file

@ -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<IgnorePhrase> &ignoredMessages;
SignalVector<QString> &mutedChannels;
SignalVector<FilterRecordPtr> &filterRecords;
SignalVector<Nickname> &nicknames;
//SignalVector<TaggedUser> &taggedUsers;
SignalVector<ModerationAction> &moderationActions;

View file

@ -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 <QDialogButtonBox>
@ -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");

View file

@ -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 <QTableView>
#include <QHeaderView>
namespace chatterino {
NicknamesPage::NicknamesPage()
{
LayoutCreator<NicknamesPage> layoutCreator(this);
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
layout.emplace<QLabel>(
"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<EditableModelView>(
(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

View file

@ -0,0 +1,18 @@
#pragma once
#include "widgets/helper/EditableModelView.hpp"
#include "widgets/settingspages/SettingsPage.hpp"
#include <QStringListModel>
class QVBoxLayout;
namespace chatterino {
class NicknamesPage : public SettingsPage
{
public:
NicknamesPage();
};
} // namespace chatterino