mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Compare commits
4 commits
718696db53
...
2582e34734
Author | SHA1 | Date | |
---|---|---|---|
2582e34734 | |||
11838c8e16 | |||
7d5967c248 | |||
9eeea8f203 |
4
.github/workflows/clang-tidy.yml
vendored
4
.github/workflows/clang-tidy.yml
vendored
|
@ -119,7 +119,7 @@ jobs:
|
||||||
|
|
||||||
- name: clang-tidy review
|
- name: clang-tidy review
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
uses: ZedThree/clang-tidy-review@v0.15.1
|
uses: ZedThree/clang-tidy-review@v0.16.0
|
||||||
with:
|
with:
|
||||||
build_dir: build-clang-tidy
|
build_dir: build-clang-tidy
|
||||||
config_file: ".clang-tidy"
|
config_file: ".clang-tidy"
|
||||||
|
@ -145,4 +145,4 @@ jobs:
|
||||||
libbenchmark-dev
|
libbenchmark-dev
|
||||||
|
|
||||||
- name: clang-tidy-review upload
|
- name: clang-tidy-review upload
|
||||||
uses: ZedThree/clang-tidy-review/upload@v0.15.1
|
uses: ZedThree/clang-tidy-review/upload@v0.16.0
|
||||||
|
|
2
.github/workflows/post-clang-tidy-review.yml
vendored
2
.github/workflows/post-clang-tidy-review.yml
vendored
|
@ -14,6 +14,6 @@ jobs:
|
||||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: ZedThree/clang-tidy-review/post@v0.15.1
|
- uses: ZedThree/clang-tidy-review/post@v0.16.0
|
||||||
with:
|
with:
|
||||||
lgtm_comment_body: ""
|
lgtm_comment_body: ""
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
- Minor: Added missing periods at various moderator messages and commands. (#5061)
|
- Minor: Added missing periods at various moderator messages and commands. (#5061)
|
||||||
- Minor: Improved color selection and display. (#5057)
|
- Minor: Improved color selection and display. (#5057)
|
||||||
- Minor: Improved Streamlink documentation in the settings dialog. (#5076)
|
- Minor: Improved Streamlink documentation in the settings dialog. (#5076)
|
||||||
|
- Minor: Normalized the input padding between light & dark themes. (#5095)
|
||||||
- Bugfix: Fixed an issue where certain emojis did not send to Twitch chat correctly. (#4840)
|
- Bugfix: Fixed an issue where certain emojis did not send to Twitch chat correctly. (#4840)
|
||||||
- Bugfix: Fixed capitalized channel names in log inclusion list not being logged. (#4848)
|
- Bugfix: Fixed capitalized channel names in log inclusion list not being logged. (#4848)
|
||||||
- Bugfix: Trimmed custom streamlink paths on all platforms making sure you don't accidentally add spaces at the beginning or end of its path. (#4834)
|
- Bugfix: Trimmed custom streamlink paths on all platforms making sure you don't accidentally add spaces at the beginning or end of its path. (#4834)
|
||||||
|
@ -105,6 +106,7 @@
|
||||||
- Dev: Move `clang-tidy` checker to its own CI job. (#4996)
|
- Dev: Move `clang-tidy` checker to its own CI job. (#4996)
|
||||||
- Dev: Refactored the Image Uploader feature. (#4971)
|
- Dev: Refactored the Image Uploader feature. (#4971)
|
||||||
- Dev: Refactored the SplitOverlay code. (#5082)
|
- Dev: Refactored the SplitOverlay code. (#5082)
|
||||||
|
- Dev: Refactored the TwitchBadges structure, making it less of a singleton. (#5096)
|
||||||
- Dev: Moved the Network files to their own folder. (#5089)
|
- Dev: Moved the Network files to their own folder. (#5089)
|
||||||
- Dev: Fixed deadlock and use-after-free in tests. (#4981)
|
- Dev: Fixed deadlock and use-after-free in tests. (#4981)
|
||||||
- Dev: Moved all `.clang-format` files to the root directory. (#5037)
|
- Dev: Moved all `.clang-format` files to the root directory. (#5037)
|
||||||
|
|
|
@ -122,6 +122,12 @@ public:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TwitchBadges *getTwitchBadges() override
|
||||||
|
{
|
||||||
|
assert(false && "getTwitchBadges was called without being initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Logging *getChatLogger() override
|
Logging *getChatLogger() override
|
||||||
{
|
{
|
||||||
assert(!"getChatLogger was called without being initialized");
|
assert(!"getChatLogger was called without being initialized");
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "controllers/notifications/NotificationController.hpp"
|
#include "controllers/notifications/NotificationController.hpp"
|
||||||
#include "controllers/sound/ISoundController.hpp"
|
#include "controllers/sound/ISoundController.hpp"
|
||||||
#include "providers/seventv/SeventvAPI.hpp"
|
#include "providers/seventv/SeventvAPI.hpp"
|
||||||
|
#include "providers/twitch/TwitchBadges.hpp"
|
||||||
#include "singletons/ImageUploader.hpp"
|
#include "singletons/ImageUploader.hpp"
|
||||||
#ifdef CHATTERINO_HAVE_PLUGINS
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||||
# include "controllers/plugins/PluginController.hpp"
|
# include "controllers/plugins/PluginController.hpp"
|
||||||
|
@ -133,6 +134,7 @@ Application::Application(Settings &_settings, const Paths &paths,
|
||||||
, sound(&this->emplace<ISoundController>(makeSoundController(_settings)))
|
, sound(&this->emplace<ISoundController>(makeSoundController(_settings)))
|
||||||
, twitchLiveController(&this->emplace<TwitchLiveController>())
|
, twitchLiveController(&this->emplace<TwitchLiveController>())
|
||||||
, twitchPubSub(new PubSub(TWITCH_PUBSUB_URL))
|
, twitchPubSub(new PubSub(TWITCH_PUBSUB_URL))
|
||||||
|
, twitchBadges(new TwitchBadges)
|
||||||
, logging(new Logging(_settings))
|
, logging(new Logging(_settings))
|
||||||
#ifdef CHATTERINO_HAVE_PLUGINS
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||||
, plugins(&this->emplace(new PluginController(paths)))
|
, plugins(&this->emplace(new PluginController(paths)))
|
||||||
|
@ -153,6 +155,7 @@ Application::~Application() = default;
|
||||||
void Application::fakeDtor()
|
void Application::fakeDtor()
|
||||||
{
|
{
|
||||||
this->twitchPubSub.reset();
|
this->twitchPubSub.reset();
|
||||||
|
this->twitchBadges.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::initialize(Settings &settings, const Paths &paths)
|
void Application::initialize(Settings &settings, const Paths &paths)
|
||||||
|
@ -320,6 +323,13 @@ ITwitchLiveController *Application::getTwitchLiveController()
|
||||||
return this->twitchLiveController;
|
return this->twitchLiveController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TwitchBadges *Application::getTwitchBadges()
|
||||||
|
{
|
||||||
|
assert(this->twitchBadges);
|
||||||
|
|
||||||
|
return this->twitchBadges.get();
|
||||||
|
}
|
||||||
|
|
||||||
ITwitchIrcServer *Application::getTwitch()
|
ITwitchIrcServer *Application::getTwitch()
|
||||||
{
|
{
|
||||||
return this->twitch;
|
return this->twitch;
|
||||||
|
|
|
@ -28,6 +28,7 @@ class ISoundController;
|
||||||
class SoundController;
|
class SoundController;
|
||||||
class ITwitchLiveController;
|
class ITwitchLiveController;
|
||||||
class TwitchLiveController;
|
class TwitchLiveController;
|
||||||
|
class TwitchBadges;
|
||||||
#ifdef CHATTERINO_HAVE_PLUGINS
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||||
class PluginController;
|
class PluginController;
|
||||||
#endif
|
#endif
|
||||||
|
@ -78,6 +79,7 @@ public:
|
||||||
virtual IUserDataController *getUserData() = 0;
|
virtual IUserDataController *getUserData() = 0;
|
||||||
virtual ISoundController *getSound() = 0;
|
virtual ISoundController *getSound() = 0;
|
||||||
virtual ITwitchLiveController *getTwitchLiveController() = 0;
|
virtual ITwitchLiveController *getTwitchLiveController() = 0;
|
||||||
|
virtual TwitchBadges *getTwitchBadges() = 0;
|
||||||
virtual ImageUploader *getImageUploader() = 0;
|
virtual ImageUploader *getImageUploader() = 0;
|
||||||
virtual SeventvAPI *getSeventvAPI() = 0;
|
virtual SeventvAPI *getSeventvAPI() = 0;
|
||||||
virtual Updates &getUpdates() = 0;
|
virtual Updates &getUpdates() = 0;
|
||||||
|
@ -141,6 +143,7 @@ public:
|
||||||
private:
|
private:
|
||||||
TwitchLiveController *const twitchLiveController{};
|
TwitchLiveController *const twitchLiveController{};
|
||||||
std::unique_ptr<PubSub> twitchPubSub;
|
std::unique_ptr<PubSub> twitchPubSub;
|
||||||
|
std::unique_ptr<TwitchBadges> twitchBadges;
|
||||||
const std::unique_ptr<Logging> logging;
|
const std::unique_ptr<Logging> logging;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -215,6 +218,7 @@ public:
|
||||||
IUserDataController *getUserData() override;
|
IUserDataController *getUserData() override;
|
||||||
ISoundController *getSound() override;
|
ISoundController *getSound() override;
|
||||||
ITwitchLiveController *getTwitchLiveController() override;
|
ITwitchLiveController *getTwitchLiveController() override;
|
||||||
|
TwitchBadges *getTwitchBadges() override;
|
||||||
ImageUploader *getImageUploader() override
|
ImageUploader *getImageUploader() override
|
||||||
{
|
{
|
||||||
return this->imageUploader;
|
return this->imageUploader;
|
||||||
|
|
|
@ -53,7 +53,7 @@ void BadgeHighlightModel::getRowFromItem(const HighlightBadge &item,
|
||||||
setFilePathItem(row[Column::SoundPath], item.getSoundUrl());
|
setFilePathItem(row[Column::SoundPath], item.getSoundUrl());
|
||||||
setColorItem(row[Column::Color], *item.getColor());
|
setColorItem(row[Column::Color], *item.getColor());
|
||||||
|
|
||||||
TwitchBadges::instance()->getBadgeIcon(
|
getIApp()->getTwitchBadges()->getBadgeIcon(
|
||||||
item.badgeName(), [item, row](QString /*name*/, const QIconPtr pixmap) {
|
item.badgeName(), [item, row](QString /*name*/, const QIconPtr pixmap) {
|
||||||
row[Column::Badge]->setData(QVariant(*pixmap), Qt::DecorationRole);
|
row[Column::Badge]->setData(QVariant(*pixmap), Qt::DecorationRole);
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@ struct Emote {
|
||||||
ImageSet images;
|
ImageSet images;
|
||||||
Tooltip tooltip;
|
Tooltip tooltip;
|
||||||
Url homePage;
|
Url homePage;
|
||||||
bool zeroWidth;
|
bool zeroWidth{};
|
||||||
EmoteId id;
|
EmoteId id;
|
||||||
EmoteAuthor author;
|
EmoteAuthor author;
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -54,6 +54,7 @@ protected:
|
||||||
|
|
||||||
virtual Outcome tryAppendEmote(const EmoteName &name)
|
virtual Outcome tryAppendEmote(const EmoteName &name)
|
||||||
{
|
{
|
||||||
|
(void)name;
|
||||||
return Failure;
|
return Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,10 @@ public:
|
||||||
enum ConnectionType { Read = 1, Write = 2, Both = 3 };
|
enum ConnectionType { Read = 1, Write = 2, Both = 3 };
|
||||||
|
|
||||||
~AbstractIrcServer() override = default;
|
~AbstractIrcServer() override = default;
|
||||||
|
AbstractIrcServer(const AbstractIrcServer &) = delete;
|
||||||
|
AbstractIrcServer(AbstractIrcServer &&) = delete;
|
||||||
|
AbstractIrcServer &operator=(const AbstractIrcServer &) = delete;
|
||||||
|
AbstractIrcServer &operator=(AbstractIrcServer &&) = delete;
|
||||||
|
|
||||||
// initializeIrc must be called from the derived class
|
// initializeIrc must be called from the derived class
|
||||||
// this allows us to initialize the abstract IRC server based on the derived class's parameters
|
// this allows us to initialize the abstract IRC server based on the derived class's parameters
|
||||||
|
@ -57,7 +61,11 @@ protected:
|
||||||
// initializeConnectionSignals is called on a connection once in its lifetime.
|
// initializeConnectionSignals is called on a connection once in its lifetime.
|
||||||
// it can be used to connect signals to your class
|
// it can be used to connect signals to your class
|
||||||
virtual void initializeConnectionSignals(IrcConnection *connection,
|
virtual void initializeConnectionSignals(IrcConnection *connection,
|
||||||
ConnectionType type){};
|
ConnectionType type)
|
||||||
|
{
|
||||||
|
(void)connection;
|
||||||
|
(void)type;
|
||||||
|
}
|
||||||
|
|
||||||
// initializeConnection is called every time before we try to connect to the IRC server
|
// initializeConnection is called every time before we try to connect to the IRC server
|
||||||
virtual void initializeConnection(IrcConnection *connection,
|
virtual void initializeConnection(IrcConnection *connection,
|
||||||
|
|
|
@ -74,9 +74,9 @@ void PubSubClient::close(const std::string &reason,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PubSubClient::listen(PubSubListenMessage msg)
|
bool PubSubClient::listen(const PubSubListenMessage &msg)
|
||||||
{
|
{
|
||||||
int numRequestedListens = msg.topics.size();
|
auto numRequestedListens = msg.topics.size();
|
||||||
|
|
||||||
if (this->numListens_ + numRequestedListens > PubSubClient::MAX_LISTENS)
|
if (this->numListens_ + numRequestedListens > PubSubClient::MAX_LISTENS)
|
||||||
{
|
{
|
||||||
|
@ -84,11 +84,19 @@ bool PubSubClient::listen(PubSubListenMessage msg)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this->numListens_ += numRequestedListens;
|
this->numListens_ += numRequestedListens;
|
||||||
DebugCount::increase("PubSub topic pending listens", numRequestedListens);
|
DebugCount::increase("PubSub topic pending listens",
|
||||||
|
static_cast<int64_t>(numRequestedListens));
|
||||||
|
|
||||||
for (const auto &topic : msg.topics)
|
for (const auto &topic : msg.topics)
|
||||||
{
|
{
|
||||||
this->listeners_.emplace_back(Listener{topic, false, false, false});
|
this->listeners_.emplace_back(Listener{
|
||||||
|
TopicData{
|
||||||
|
topic,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(chatterinoPubSub)
|
qCDebug(chatterinoPubSub)
|
||||||
|
@ -127,7 +135,7 @@ PubSubClient::UnlistenPrefixResponse PubSubClient::unlistenPrefix(
|
||||||
|
|
||||||
this->numListens_ -= numRequestedUnlistens;
|
this->numListens_ -= numRequestedUnlistens;
|
||||||
DebugCount::increase("PubSub topic pending unlistens",
|
DebugCount::increase("PubSub topic pending unlistens",
|
||||||
numRequestedUnlistens);
|
static_cast<int64_t>(numRequestedUnlistens));
|
||||||
|
|
||||||
PubSubUnlistenMessage message(topics);
|
PubSubUnlistenMessage message(topics);
|
||||||
|
|
||||||
|
@ -192,6 +200,7 @@ void PubSubClient::ping()
|
||||||
|
|
||||||
runAfter(this->heartbeatTimer_, this->clientOptions_.pingInterval_,
|
runAfter(this->heartbeatTimer_, this->clientOptions_.pingInterval_,
|
||||||
[self](auto timer) {
|
[self](auto timer) {
|
||||||
|
(void)timer;
|
||||||
if (!self->started_)
|
if (!self->started_)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
websocketpp::close::status::value code =
|
websocketpp::close::status::value code =
|
||||||
websocketpp::close::status::normal);
|
websocketpp::close::status::normal);
|
||||||
|
|
||||||
bool listen(PubSubListenMessage msg);
|
bool listen(const PubSubListenMessage &msg);
|
||||||
UnlistenPrefixResponse unlistenPrefix(const QString &prefix);
|
UnlistenPrefixResponse unlistenPrefix(const QString &prefix);
|
||||||
|
|
||||||
void handleListenResponse(const PubSubMessage &message);
|
void handleListenResponse(const PubSubMessage &message);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "TwitchBadges.hpp"
|
#include "providers/twitch/TwitchBadges.hpp"
|
||||||
|
|
||||||
#include "common/network/NetworkRequest.hpp"
|
#include "common/network/NetworkRequest.hpp"
|
||||||
#include "common/network/NetworkResult.hpp"
|
#include "common/network/NetworkResult.hpp"
|
||||||
|
@ -45,14 +45,15 @@ void TwitchBadges::loadTwitchBadges()
|
||||||
for (const auto &version : badgeSet.versions)
|
for (const auto &version : badgeSet.versions)
|
||||||
{
|
{
|
||||||
const auto &emote = Emote{
|
const auto &emote = Emote{
|
||||||
EmoteName{},
|
.name = EmoteName{},
|
||||||
ImageSet{
|
.images =
|
||||||
Image::fromUrl(version.imageURL1x, 1),
|
ImageSet{
|
||||||
Image::fromUrl(version.imageURL2x, .5),
|
Image::fromUrl(version.imageURL1x, 1),
|
||||||
Image::fromUrl(version.imageURL4x, .25),
|
Image::fromUrl(version.imageURL2x, .5),
|
||||||
},
|
Image::fromUrl(version.imageURL4x, .25),
|
||||||
Tooltip{version.title},
|
},
|
||||||
version.clickURL,
|
.tooltip = Tooltip{version.title},
|
||||||
|
.homePage = version.clickURL,
|
||||||
};
|
};
|
||||||
(*badgeSets)[setID][version.id] =
|
(*badgeSets)[setID][version.id] =
|
||||||
std::make_shared<Emote>(emote);
|
std::make_shared<Emote>(emote);
|
||||||
|
@ -112,20 +113,19 @@ void TwitchBadges::parseTwitchBadges(QJsonObject root)
|
||||||
auto versionObj = vIt.value().toObject();
|
auto versionObj = vIt.value().toObject();
|
||||||
|
|
||||||
auto emote = Emote{
|
auto emote = Emote{
|
||||||
{""},
|
.name = {""},
|
||||||
ImageSet{
|
.images =
|
||||||
Image::fromUrl(
|
ImageSet{
|
||||||
{versionObj.value("image_url_1x").toString()}, 1),
|
Image::fromUrl(
|
||||||
Image::fromUrl(
|
{versionObj.value("image_url_1x").toString()}, 1),
|
||||||
{versionObj.value("image_url_2x").toString()}, .5),
|
Image::fromUrl(
|
||||||
Image::fromUrl(
|
{versionObj.value("image_url_2x").toString()}, .5),
|
||||||
{versionObj.value("image_url_4x").toString()}, .25),
|
Image::fromUrl(
|
||||||
},
|
{versionObj.value("image_url_4x").toString()}, .25),
|
||||||
Tooltip{versionObj.value("title").toString()},
|
},
|
||||||
Url{versionObj.value("click_url").toString()},
|
.tooltip = Tooltip{versionObj.value("title").toString()},
|
||||||
|
.homePage = Url{versionObj.value("click_url").toString()},
|
||||||
};
|
};
|
||||||
// "title"
|
|
||||||
// "clickAction"
|
|
||||||
|
|
||||||
(*badgeSets)[key][vIt.key()] = std::make_shared<Emote>(emote);
|
(*badgeSets)[key][vIt.key()] = std::make_shared<Emote>(emote);
|
||||||
}
|
}
|
||||||
|
@ -176,9 +176,10 @@ std::optional<EmotePtr> TwitchBadges::badge(const QString &set) const
|
||||||
auto it = badgeSets->find(set);
|
auto it = badgeSets->find(set);
|
||||||
if (it != badgeSets->end())
|
if (it != badgeSets->end())
|
||||||
{
|
{
|
||||||
if (it->second.size() > 0)
|
const auto &badges = it->second;
|
||||||
|
if (!badges.empty())
|
||||||
{
|
{
|
||||||
return it->second.begin()->second;
|
return badges.begin()->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
@ -193,7 +194,7 @@ void TwitchBadges::getBadgeIcon(const QString &name, BadgeIconCallback callback)
|
||||||
{
|
{
|
||||||
// Badges have not been loaded yet, store callback in a queue
|
// Badges have not been loaded yet, store callback in a queue
|
||||||
std::unique_lock queueLock(this->queueMutex_);
|
std::unique_lock queueLock(this->queueMutex_);
|
||||||
this->callbackQueue_.push({name, std::move(callback)});
|
this->callbackQueue_.emplace(name, std::move(callback));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,16 +280,4 @@ void TwitchBadges::loadEmoteImage(const QString &name, ImagePtr image,
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
TwitchBadges *TwitchBadges::instance_;
|
|
||||||
|
|
||||||
TwitchBadges *TwitchBadges::instance()
|
|
||||||
{
|
|
||||||
if (TwitchBadges::instance_ == nullptr)
|
|
||||||
{
|
|
||||||
TwitchBadges::instance_ = new TwitchBadges();
|
|
||||||
}
|
|
||||||
|
|
||||||
return TwitchBadges::instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -32,7 +32,7 @@ class TwitchBadges
|
||||||
using BadgeIconCallback = std::function<void(QString, const QIconPtr)>;
|
using BadgeIconCallback = std::function<void(QString, const QIconPtr)>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static TwitchBadges *instance();
|
TwitchBadges();
|
||||||
|
|
||||||
// Get badge from name and version
|
// Get badge from name and version
|
||||||
std::optional<EmotePtr> badge(const QString &set,
|
std::optional<EmotePtr> badge(const QString &set,
|
||||||
|
@ -46,9 +46,6 @@ public:
|
||||||
BadgeIconCallback callback);
|
BadgeIconCallback callback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static TwitchBadges *instance_;
|
|
||||||
|
|
||||||
TwitchBadges();
|
|
||||||
void loadTwitchBadges();
|
void loadTwitchBadges();
|
||||||
void parseTwitchBadges(QJsonObject root);
|
void parseTwitchBadges(QJsonObject root);
|
||||||
void loaded();
|
void loaded();
|
||||||
|
|
|
@ -83,7 +83,6 @@ TwitchChannel::TwitchChannel(const QString &name)
|
||||||
, bttvEmotes_(std::make_shared<EmoteMap>())
|
, bttvEmotes_(std::make_shared<EmoteMap>())
|
||||||
, ffzEmotes_(std::make_shared<EmoteMap>())
|
, ffzEmotes_(std::make_shared<EmoteMap>())
|
||||||
, seventvEmotes_(std::make_shared<EmoteMap>())
|
, seventvEmotes_(std::make_shared<EmoteMap>())
|
||||||
, mod_(false)
|
|
||||||
{
|
{
|
||||||
qCDebug(chatterinoTwitch) << "[TwitchChannel" << name << "] Opened";
|
qCDebug(chatterinoTwitch) << "[TwitchChannel" << name << "] Opened";
|
||||||
|
|
||||||
|
@ -322,13 +321,15 @@ void TwitchChannel::refreshFFZChannelEmotes(bool manualRefresh)
|
||||||
[this, weak = weakOf<Channel>(this)](auto &&modBadge) {
|
[this, weak = weakOf<Channel>(this)](auto &&modBadge) {
|
||||||
if (auto shared = weak.lock())
|
if (auto shared = weak.lock())
|
||||||
{
|
{
|
||||||
this->ffzCustomModBadge_.set(std::move(modBadge));
|
this->ffzCustomModBadge_.set(
|
||||||
|
std::forward<decltype(modBadge)>(modBadge));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[this, weak = weakOf<Channel>(this)](auto &&vipBadge) {
|
[this, weak = weakOf<Channel>(this)](auto &&vipBadge) {
|
||||||
if (auto shared = weak.lock())
|
if (auto shared = weak.lock())
|
||||||
{
|
{
|
||||||
this->ffzCustomVipBadge_.set(std::move(vipBadge));
|
this->ffzCustomVipBadge_.set(
|
||||||
|
std::forward<decltype(vipBadge)>(vipBadge));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
manualRefresh);
|
manualRefresh);
|
||||||
|
@ -778,12 +779,12 @@ void TwitchChannel::setRoomId(const QString &id)
|
||||||
SharedAccessGuard<const TwitchChannel::RoomModes>
|
SharedAccessGuard<const TwitchChannel::RoomModes>
|
||||||
TwitchChannel::accessRoomModes() const
|
TwitchChannel::accessRoomModes() const
|
||||||
{
|
{
|
||||||
return this->roomModes_.accessConst();
|
return this->roomModes.accessConst();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchChannel::setRoomModes(const RoomModes &_roomModes)
|
void TwitchChannel::setRoomModes(const RoomModes &newRoomModes)
|
||||||
{
|
{
|
||||||
this->roomModes_ = _roomModes;
|
this->roomModes = newRoomModes;
|
||||||
|
|
||||||
this->roomModesChanged.invoke();
|
this->roomModesChanged.invoke();
|
||||||
}
|
}
|
||||||
|
@ -1133,7 +1134,7 @@ const QString &TwitchChannel::popoutPlayerUrl()
|
||||||
return this->popoutPlayerUrl_;
|
return this->popoutPlayerUrl_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TwitchChannel::chatterCount()
|
int TwitchChannel::chatterCount() const
|
||||||
{
|
{
|
||||||
return this->chatterCount_;
|
return this->chatterCount_;
|
||||||
}
|
}
|
||||||
|
@ -1201,7 +1202,7 @@ void TwitchChannel::loadRecentMessages()
|
||||||
tc->loadingRecentMessages_.clear();
|
tc->loadingRecentMessages_.clear();
|
||||||
|
|
||||||
std::vector<MessagePtr> msgs;
|
std::vector<MessagePtr> msgs;
|
||||||
for (MessagePtr msg : messages)
|
for (const auto &msg : messages)
|
||||||
{
|
{
|
||||||
const auto highlighted =
|
const auto highlighted =
|
||||||
msg->flags.has(MessageFlag::Highlighted);
|
msg->flags.has(MessageFlag::Highlighted);
|
||||||
|
@ -1351,7 +1352,10 @@ void TwitchChannel::refreshChatters()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Refresh chatters should only be used when failing silently is an option
|
// Refresh chatters should only be used when failing silently is an option
|
||||||
[](auto error, auto message) {});
|
[](auto error, auto message) {
|
||||||
|
(void)error;
|
||||||
|
(void)message;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchChannel::addReplyThread(const std::shared_ptr<MessageThread> &thread)
|
void TwitchChannel::addReplyThread(const std::shared_ptr<MessageThread> &thread)
|
||||||
|
@ -1429,14 +1433,15 @@ void TwitchChannel::refreshBadges()
|
||||||
for (const auto &version : badgeSet.versions)
|
for (const auto &version : badgeSet.versions)
|
||||||
{
|
{
|
||||||
auto emote = Emote{
|
auto emote = Emote{
|
||||||
EmoteName{},
|
.name = EmoteName{},
|
||||||
ImageSet{
|
.images =
|
||||||
Image::fromUrl(version.imageURL1x, 1),
|
ImageSet{
|
||||||
Image::fromUrl(version.imageURL2x, .5),
|
Image::fromUrl(version.imageURL1x, 1),
|
||||||
Image::fromUrl(version.imageURL4x, .25),
|
Image::fromUrl(version.imageURL2x, .5),
|
||||||
},
|
Image::fromUrl(version.imageURL4x, .25),
|
||||||
Tooltip{version.title},
|
},
|
||||||
version.clickURL,
|
.tooltip = Tooltip{version.title},
|
||||||
|
.homePage = version.clickURL,
|
||||||
};
|
};
|
||||||
(*badgeSets)[setID][version.id] =
|
(*badgeSets)[setID][version.id] =
|
||||||
std::make_shared<Emote>(emote);
|
std::make_shared<Emote>(emote);
|
||||||
|
@ -1508,22 +1513,28 @@ void TwitchChannel::refreshCheerEmotes()
|
||||||
// Combine the prefix (e.g. BibleThump) with the tier (1, 100 etc.)
|
// Combine the prefix (e.g. BibleThump) with the tier (1, 100 etc.)
|
||||||
auto emoteTooltip =
|
auto emoteTooltip =
|
||||||
set.prefix + tier.id + "<br>Twitch Cheer Emote";
|
set.prefix + tier.id + "<br>Twitch Cheer Emote";
|
||||||
cheerEmote.animatedEmote = std::make_shared<Emote>(
|
cheerEmote.animatedEmote = std::make_shared<Emote>(Emote{
|
||||||
Emote{EmoteName{"cheer emote"},
|
.name = EmoteName{"cheer emote"},
|
||||||
ImageSet{
|
.images =
|
||||||
tier.darkAnimated.imageURL1x,
|
ImageSet{
|
||||||
tier.darkAnimated.imageURL2x,
|
tier.darkAnimated.imageURL1x,
|
||||||
tier.darkAnimated.imageURL4x,
|
tier.darkAnimated.imageURL2x,
|
||||||
},
|
tier.darkAnimated.imageURL4x,
|
||||||
Tooltip{emoteTooltip}, Url{}});
|
},
|
||||||
cheerEmote.staticEmote = std::make_shared<Emote>(
|
.tooltip = Tooltip{emoteTooltip},
|
||||||
Emote{EmoteName{"cheer emote"},
|
.homePage = Url{},
|
||||||
ImageSet{
|
});
|
||||||
tier.darkStatic.imageURL1x,
|
cheerEmote.staticEmote = std::make_shared<Emote>(Emote{
|
||||||
tier.darkStatic.imageURL2x,
|
.name = EmoteName{"cheer emote"},
|
||||||
tier.darkStatic.imageURL4x,
|
.images =
|
||||||
},
|
ImageSet{
|
||||||
Tooltip{emoteTooltip}, Url{}});
|
tier.darkStatic.imageURL1x,
|
||||||
|
tier.darkStatic.imageURL2x,
|
||||||
|
tier.darkStatic.imageURL4x,
|
||||||
|
},
|
||||||
|
.tooltip = Tooltip{emoteTooltip},
|
||||||
|
.homePage = Url{},
|
||||||
|
});
|
||||||
|
|
||||||
cheerEmoteSet.cheerEmotes.emplace_back(
|
cheerEmoteSet.cheerEmotes.emplace_back(
|
||||||
std::move(cheerEmote));
|
std::move(cheerEmote));
|
||||||
|
@ -1760,7 +1771,7 @@ void TwitchChannel::updateSevenTVActivity()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchChannel::listenSevenTVCosmetics()
|
void TwitchChannel::listenSevenTVCosmetics() const
|
||||||
{
|
{
|
||||||
if (getApp()->twitch->seventvEventAPI)
|
if (getApp()->twitch->seventvEventAPI)
|
||||||
{
|
{
|
||||||
|
|
|
@ -110,6 +110,11 @@ public:
|
||||||
explicit TwitchChannel(const QString &channelName);
|
explicit TwitchChannel(const QString &channelName);
|
||||||
~TwitchChannel() override;
|
~TwitchChannel() override;
|
||||||
|
|
||||||
|
TwitchChannel(const TwitchChannel &) = delete;
|
||||||
|
TwitchChannel(TwitchChannel &&) = delete;
|
||||||
|
TwitchChannel &operator=(const TwitchChannel &) = delete;
|
||||||
|
TwitchChannel &operator=(TwitchChannel &&) = delete;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
// Channel methods
|
// Channel methods
|
||||||
|
@ -130,7 +135,7 @@ public:
|
||||||
const QString &subscriptionUrl();
|
const QString &subscriptionUrl();
|
||||||
const QString &channelUrl();
|
const QString &channelUrl();
|
||||||
const QString &popoutPlayerUrl();
|
const QString &popoutPlayerUrl();
|
||||||
int chatterCount();
|
int chatterCount() const;
|
||||||
bool isLive() const override;
|
bool isLive() const override;
|
||||||
QString roomId() const;
|
QString roomId() const;
|
||||||
SharedAccessGuard<const RoomModes> accessRoomModes() const;
|
SharedAccessGuard<const RoomModes> accessRoomModes() const;
|
||||||
|
@ -300,7 +305,7 @@ private:
|
||||||
* This is done at most once every 60s.
|
* This is done at most once every 60s.
|
||||||
*/
|
*/
|
||||||
void updateSevenTVActivity();
|
void updateSevenTVActivity();
|
||||||
void listenSevenTVCosmetics();
|
void listenSevenTVCosmetics() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the live status of this Twitch channel
|
* @brief Sets the live status of this Twitch channel
|
||||||
|
@ -312,7 +317,7 @@ private:
|
||||||
void setVIP(bool value);
|
void setVIP(bool value);
|
||||||
void setStaff(bool value);
|
void setStaff(bool value);
|
||||||
void setRoomId(const QString &id);
|
void setRoomId(const QString &id);
|
||||||
void setRoomModes(const RoomModes &roomModes_);
|
void setRoomModes(const RoomModes &newRoomModes);
|
||||||
void setDisplayName(const QString &name);
|
void setDisplayName(const QString &name);
|
||||||
void setLocalizedName(const QString &name);
|
void setLocalizedName(const QString &name);
|
||||||
|
|
||||||
|
@ -371,7 +376,7 @@ private:
|
||||||
const QString popoutPlayerUrl_;
|
const QString popoutPlayerUrl_;
|
||||||
int chatterCount_{};
|
int chatterCount_{};
|
||||||
UniqueAccess<StreamStatus> streamStatus_;
|
UniqueAccess<StreamStatus> streamStatus_;
|
||||||
UniqueAccess<RoomModes> roomModes_;
|
UniqueAccess<RoomModes> roomModes;
|
||||||
bool disconnected_{};
|
bool disconnected_{};
|
||||||
std::optional<std::chrono::time_point<std::chrono::system_clock>>
|
std::optional<std::chrono::time_point<std::chrono::system_clock>>
|
||||||
lastConnectedAt_{};
|
lastConnectedAt_{};
|
||||||
|
|
|
@ -163,7 +163,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto globalBadge =
|
if (auto globalBadge =
|
||||||
TwitchBadges::instance()->badge(badge.key_, badge.value_))
|
getIApp()->getTwitchBadges()->badge(badge.key_, badge.value_))
|
||||||
{
|
{
|
||||||
return globalBadge;
|
return globalBadge;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "BadgePickerDialog.hpp"
|
#include "BadgePickerDialog.hpp"
|
||||||
|
|
||||||
|
#include "Application.hpp"
|
||||||
#include "providers/twitch/TwitchBadges.hpp"
|
#include "providers/twitch/TwitchBadges.hpp"
|
||||||
#include "singletons/Resources.hpp"
|
#include "singletons/Resources.hpp"
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ BadgePickerDialog::BadgePickerDialog(QList<DisplayBadge> badges,
|
||||||
updateBadge(0);
|
updateBadge(0);
|
||||||
|
|
||||||
// Set icons.
|
// Set icons.
|
||||||
TwitchBadges::instance()->getBadgeIcons(
|
getIApp()->getTwitchBadges()->getBadgeIcons(
|
||||||
badges,
|
badges,
|
||||||
[&dropdown = this->dropdown_](QString identifier, const QIconPtr icon) {
|
[&dropdown = this->dropdown_](QString identifier, const QIconPtr icon) {
|
||||||
if (!dropdown)
|
if (!dropdown)
|
||||||
|
|
|
@ -78,6 +78,7 @@ class ComboBox : public QComboBox
|
||||||
|
|
||||||
void wheelEvent(QWheelEvent *event) override
|
void wheelEvent(QWheelEvent *event) override
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -311,8 +312,9 @@ public:
|
||||||
bool filterElements(const QString &query);
|
bool filterElements(const QString &query);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *ev) override
|
void resizeEvent(QResizeEvent *event) override
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -959,17 +959,23 @@ void Split::paintEvent(QPaintEvent *)
|
||||||
|
|
||||||
void Split::mouseMoveEvent(QMouseEvent *event)
|
void Split::mouseMoveEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
|
|
||||||
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Split::keyPressEvent(QKeyEvent *event)
|
void Split::keyPressEvent(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
|
|
||||||
this->view_->unsetCursor();
|
this->view_->unsetCursor();
|
||||||
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Split::keyReleaseEvent(QKeyEvent *event)
|
void Split::keyReleaseEvent(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
|
|
||||||
this->view_->unsetCursor();
|
this->view_->unsetCursor();
|
||||||
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
||||||
}
|
}
|
||||||
|
@ -1005,6 +1011,8 @@ void Split::enterEvent(QEvent * /*event*/)
|
||||||
|
|
||||||
void Split::leaveEvent(QEvent *event)
|
void Split::leaveEvent(QEvent *event)
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
|
|
||||||
this->isMouseOver_ = false;
|
this->isMouseOver_ = false;
|
||||||
|
|
||||||
this->overlay_->hide();
|
this->overlay_->hide();
|
||||||
|
|
|
@ -213,16 +213,17 @@ void SplitInput::scaleChangedEvent(float scale)
|
||||||
this->setMaximumHeight(this->scaledMaxHeight());
|
this->setMaximumHeight(this->scaledMaxHeight());
|
||||||
}
|
}
|
||||||
this->ui_.textEdit->setFont(
|
this->ui_.textEdit->setFont(
|
||||||
app->fonts->getFont(FontStyle::ChatMedium, this->scale()));
|
app->fonts->getFont(FontStyle::ChatMedium, scale));
|
||||||
this->ui_.textEditLength->setFont(
|
this->ui_.textEditLength->setFont(
|
||||||
app->fonts->getFont(FontStyle::ChatMedium, this->scale()));
|
app->fonts->getFont(FontStyle::ChatMedium, scale));
|
||||||
this->ui_.replyLabel->setFont(
|
this->ui_.replyLabel->setFont(
|
||||||
app->fonts->getFont(FontStyle::ChatMediumBold, this->scale()));
|
app->fonts->getFont(FontStyle::ChatMediumBold, scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitInput::themeChangedEvent()
|
void SplitInput::themeChangedEvent()
|
||||||
{
|
{
|
||||||
QPalette palette, placeholderPalette;
|
QPalette palette;
|
||||||
|
QPalette placeholderPalette;
|
||||||
|
|
||||||
palette.setColor(QPalette::WindowText, this->theme->splits.input.text);
|
palette.setColor(QPalette::WindowText, this->theme->splits.input.text);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||||
|
@ -239,7 +240,7 @@ void SplitInput::themeChangedEvent()
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||||
this->ui_.textEdit->setPalette(placeholderPalette);
|
this->ui_.textEdit->setPalette(placeholderPalette);
|
||||||
#endif
|
#endif
|
||||||
auto marginPx = (this->theme->isLightTheme() ? 4 : 2) * this->scale();
|
auto marginPx = static_cast<int>(2.F * this->scale());
|
||||||
this->ui_.vbox->setContentsMargins(marginPx, marginPx, marginPx, marginPx);
|
this->ui_.vbox->setContentsMargins(marginPx, marginPx, marginPx, marginPx);
|
||||||
|
|
||||||
this->ui_.emoteButton->getLabel().setStyleSheet("color: #000");
|
this->ui_.emoteButton->getLabel().setStyleSheet("color: #000");
|
||||||
|
@ -256,15 +257,12 @@ void SplitInput::themeChangedEvent()
|
||||||
|
|
||||||
void SplitInput::updateEmoteButton()
|
void SplitInput::updateEmoteButton()
|
||||||
{
|
{
|
||||||
float scale = this->scale();
|
auto scale = this->scale();
|
||||||
|
|
||||||
QString text = "<img src=':/buttons/emote.svg' width='xD' height='xD' />";
|
auto text =
|
||||||
text.replace("xD", QString::number(int(12 * scale)));
|
QStringLiteral("<img src=':/buttons/%1.svg' width='%2' height='%2' />")
|
||||||
|
.arg(this->theme->isLightTheme() ? "emoteDark" : "emote")
|
||||||
if (this->theme->isLightTheme())
|
.arg(int(12 * scale));
|
||||||
{
|
|
||||||
text.replace("emote", "emoteDark");
|
|
||||||
}
|
|
||||||
|
|
||||||
this->ui_.emoteButton->getLabel().setText(text);
|
this->ui_.emoteButton->getLabel().setText(text);
|
||||||
this->ui_.emoteButton->setFixedHeight(int(18 * scale));
|
this->ui_.emoteButton->setFixedHeight(int(18 * scale));
|
||||||
|
@ -274,15 +272,10 @@ void SplitInput::updateCancelReplyButton()
|
||||||
{
|
{
|
||||||
float scale = this->scale();
|
float scale = this->scale();
|
||||||
|
|
||||||
QString text =
|
auto text =
|
||||||
QStringLiteral(
|
QStringLiteral("<img src=':/buttons/%1.svg' width='%2' height='%2' />")
|
||||||
"<img src=':/buttons/cancel.svg' width='%1' height='%1' />")
|
.arg(this->theme->isLightTheme() ? "cancelDark" : "cancel")
|
||||||
.arg(QString::number(int(12 * scale)));
|
.arg(int(12 * scale));
|
||||||
|
|
||||||
if (this->theme->isLightTheme())
|
|
||||||
{
|
|
||||||
text.replace("cancel", "cancelDark");
|
|
||||||
}
|
|
||||||
|
|
||||||
this->ui_.cancelReplyButton->getLabel().setText(text);
|
this->ui_.cancelReplyButton->getLabel().setText(text);
|
||||||
this->ui_.cancelReplyButton->setFixedHeight(int(12 * scale));
|
this->ui_.cancelReplyButton->setFixedHeight(int(12 * scale));
|
||||||
|
@ -324,7 +317,7 @@ void SplitInput::openEmotePopup()
|
||||||
this->emotePopup_->activateWindow();
|
this->emotePopup_->activateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SplitInput::handleSendMessage(std::vector<QString> &arguments)
|
QString SplitInput::handleSendMessage(const std::vector<QString> &arguments)
|
||||||
{
|
{
|
||||||
auto c = this->split_->getChannel();
|
auto c = this->split_->getChannel();
|
||||||
if (c == nullptr)
|
if (c == nullptr)
|
||||||
|
@ -346,40 +339,37 @@ QString SplitInput::handleSendMessage(std::vector<QString> &arguments)
|
||||||
this->postMessageSend(message, arguments);
|
this->postMessageSend(message, arguments);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Reply to message
|
||||||
|
auto *tc = dynamic_cast<TwitchChannel *>(c.get());
|
||||||
|
if (!tc)
|
||||||
{
|
{
|
||||||
// Reply to message
|
// this should not fail
|
||||||
auto *tc = dynamic_cast<TwitchChannel *>(c.get());
|
|
||||||
if (!tc)
|
|
||||||
{
|
|
||||||
// this should not fail
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString message = this->ui_.textEdit->toPlainText();
|
|
||||||
|
|
||||||
if (this->enableInlineReplying_)
|
|
||||||
{
|
|
||||||
// Remove @username prefix that is inserted when doing inline replies
|
|
||||||
message.remove(0, this->replyThread_->displayName.length() +
|
|
||||||
1); // remove "@username"
|
|
||||||
|
|
||||||
if (!message.isEmpty() && message.at(0) == ' ')
|
|
||||||
{
|
|
||||||
message.remove(0, 1); // remove possible space
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message = message.replace('\n', ' ');
|
|
||||||
QString sendMessage =
|
|
||||||
getApp()->commands->execCommand(message, c, false);
|
|
||||||
|
|
||||||
// Reply within TwitchChannel
|
|
||||||
tc->sendReply(sendMessage, this->replyThread_->id);
|
|
||||||
|
|
||||||
this->postMessageSend(message, arguments);
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString message = this->ui_.textEdit->toPlainText();
|
||||||
|
|
||||||
|
if (this->enableInlineReplying_)
|
||||||
|
{
|
||||||
|
// Remove @username prefix that is inserted when doing inline replies
|
||||||
|
message.remove(0, this->replyThread_->displayName.length() +
|
||||||
|
1); // remove "@username"
|
||||||
|
|
||||||
|
if (!message.isEmpty() && message.at(0) == ' ')
|
||||||
|
{
|
||||||
|
message.remove(0, 1); // remove possible space
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message = message.replace('\n', ' ');
|
||||||
|
QString sendMessage = getApp()->commands->execCommand(message, c, false);
|
||||||
|
|
||||||
|
// Reply within TwitchChannel
|
||||||
|
tc->sendReply(sendMessage, this->replyThread_->id);
|
||||||
|
|
||||||
|
this->postMessageSend(message, arguments);
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitInput::postMessageSend(const QString &message,
|
void SplitInput::postMessageSend(const QString &message,
|
||||||
|
@ -408,7 +398,7 @@ void SplitInput::addShortcuts()
|
||||||
{
|
{
|
||||||
HotkeyController::HotkeyMap actions{
|
HotkeyController::HotkeyMap actions{
|
||||||
{"cursorToStart",
|
{"cursorToStart",
|
||||||
[this](std::vector<QString> arguments) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
if (arguments.size() != 1)
|
if (arguments.size() != 1)
|
||||||
{
|
{
|
||||||
qCWarning(chatterinoHotkeys)
|
qCWarning(chatterinoHotkeys)
|
||||||
|
@ -419,8 +409,8 @@ void SplitInput::addShortcuts()
|
||||||
}
|
}
|
||||||
QTextCursor cursor = this->ui_.textEdit->textCursor();
|
QTextCursor cursor = this->ui_.textEdit->textCursor();
|
||||||
auto place = QTextCursor::Start;
|
auto place = QTextCursor::Start;
|
||||||
auto stringTakeSelection = arguments.at(0);
|
const auto &stringTakeSelection = arguments.at(0);
|
||||||
bool select;
|
bool select{};
|
||||||
if (stringTakeSelection == "withSelection")
|
if (stringTakeSelection == "withSelection")
|
||||||
{
|
{
|
||||||
select = true;
|
select = true;
|
||||||
|
@ -443,7 +433,7 @@ void SplitInput::addShortcuts()
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"cursorToEnd",
|
{"cursorToEnd",
|
||||||
[this](std::vector<QString> arguments) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
if (arguments.size() != 1)
|
if (arguments.size() != 1)
|
||||||
{
|
{
|
||||||
qCWarning(chatterinoHotkeys)
|
qCWarning(chatterinoHotkeys)
|
||||||
|
@ -454,8 +444,8 @@ void SplitInput::addShortcuts()
|
||||||
}
|
}
|
||||||
QTextCursor cursor = this->ui_.textEdit->textCursor();
|
QTextCursor cursor = this->ui_.textEdit->textCursor();
|
||||||
auto place = QTextCursor::End;
|
auto place = QTextCursor::End;
|
||||||
auto stringTakeSelection = arguments.at(0);
|
const auto &stringTakeSelection = arguments.at(0);
|
||||||
bool select;
|
bool select{};
|
||||||
if (stringTakeSelection == "withSelection")
|
if (stringTakeSelection == "withSelection")
|
||||||
{
|
{
|
||||||
select = true;
|
select = true;
|
||||||
|
@ -478,36 +468,45 @@ void SplitInput::addShortcuts()
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"openEmotesPopup",
|
{"openEmotesPopup",
|
||||||
[this](std::vector<QString>) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
|
(void)arguments;
|
||||||
|
|
||||||
this->openEmotePopup();
|
this->openEmotePopup();
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"sendMessage",
|
{"sendMessage",
|
||||||
[this](std::vector<QString> arguments) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
return this->handleSendMessage(arguments);
|
return this->handleSendMessage(arguments);
|
||||||
}},
|
}},
|
||||||
{"previousMessage",
|
{"previousMessage",
|
||||||
[this](std::vector<QString>) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
if (this->prevMsg_.size() && this->prevIndex_)
|
(void)arguments;
|
||||||
|
|
||||||
|
if (this->prevMsg_.isEmpty() || this->prevIndex_ == 0)
|
||||||
{
|
{
|
||||||
if (this->prevIndex_ == (this->prevMsg_.size()))
|
return "";
|
||||||
{
|
|
||||||
this->currMsg_ = ui_.textEdit->toPlainText();
|
|
||||||
}
|
|
||||||
|
|
||||||
this->prevIndex_--;
|
|
||||||
this->ui_.textEdit->setPlainText(
|
|
||||||
this->prevMsg_.at(this->prevIndex_));
|
|
||||||
this->ui_.textEdit->resetCompletion();
|
|
||||||
|
|
||||||
QTextCursor cursor = this->ui_.textEdit->textCursor();
|
|
||||||
cursor.movePosition(QTextCursor::End);
|
|
||||||
this->ui_.textEdit->setTextCursor(cursor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->prevIndex_ == (this->prevMsg_.size()))
|
||||||
|
{
|
||||||
|
this->currMsg_ = ui_.textEdit->toPlainText();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->prevIndex_--;
|
||||||
|
this->ui_.textEdit->setPlainText(
|
||||||
|
this->prevMsg_.at(this->prevIndex_));
|
||||||
|
this->ui_.textEdit->resetCompletion();
|
||||||
|
|
||||||
|
QTextCursor cursor = this->ui_.textEdit->textCursor();
|
||||||
|
cursor.movePosition(QTextCursor::End);
|
||||||
|
this->ui_.textEdit->setTextCursor(cursor);
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"nextMessage",
|
{"nextMessage",
|
||||||
[this](std::vector<QString>) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
|
(void)arguments;
|
||||||
|
|
||||||
// If user did not write anything before then just do nothing.
|
// If user did not write anything before then just do nothing.
|
||||||
if (this->prevMsg_.isEmpty())
|
if (this->prevMsg_.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -556,19 +555,23 @@ void SplitInput::addShortcuts()
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"undo",
|
{"undo",
|
||||||
[this](std::vector<QString>) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
|
(void)arguments;
|
||||||
|
|
||||||
this->ui_.textEdit->undo();
|
this->ui_.textEdit->undo();
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"redo",
|
{"redo",
|
||||||
[this](std::vector<QString>) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
|
(void)arguments;
|
||||||
|
|
||||||
this->ui_.textEdit->redo();
|
this->ui_.textEdit->redo();
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"copy",
|
{"copy",
|
||||||
[this](std::vector<QString> arguments) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
// XXX: this action is unused at the moment, a qt standard shortcut is used instead
|
// XXX: this action is unused at the moment, a qt standard shortcut is used instead
|
||||||
if (arguments.size() == 0)
|
if (arguments.empty())
|
||||||
{
|
{
|
||||||
return "copy action takes only one argument: the source "
|
return "copy action takes only one argument: the source "
|
||||||
"of the copy \"split\", \"input\" or "
|
"of the copy \"split\", \"input\" or "
|
||||||
|
@ -578,8 +581,9 @@ void SplitInput::addShortcuts()
|
||||||
"copied. Automatic will pick whichever has a "
|
"copied. Automatic will pick whichever has a "
|
||||||
"selection";
|
"selection";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool copyFromSplit = false;
|
bool copyFromSplit = false;
|
||||||
auto mode = arguments.at(0);
|
const auto &mode = arguments.at(0);
|
||||||
if (mode == "split")
|
if (mode == "split")
|
||||||
{
|
{
|
||||||
copyFromSplit = true;
|
copyFromSplit = true;
|
||||||
|
@ -605,22 +609,30 @@ void SplitInput::addShortcuts()
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"paste",
|
{"paste",
|
||||||
[this](std::vector<QString>) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
|
(void)arguments;
|
||||||
|
|
||||||
this->ui_.textEdit->paste();
|
this->ui_.textEdit->paste();
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"clear",
|
{"clear",
|
||||||
[this](std::vector<QString>) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
|
(void)arguments;
|
||||||
|
|
||||||
this->clearInput();
|
this->clearInput();
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"selectAll",
|
{"selectAll",
|
||||||
[this](std::vector<QString>) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
|
(void)arguments;
|
||||||
|
|
||||||
this->ui_.textEdit->selectAll();
|
this->ui_.textEdit->selectAll();
|
||||||
return "";
|
return "";
|
||||||
}},
|
}},
|
||||||
{"selectWord",
|
{"selectWord",
|
||||||
[this](std::vector<QString>) -> QString {
|
[this](const std::vector<QString> &arguments) -> QString {
|
||||||
|
(void)arguments;
|
||||||
|
|
||||||
auto cursor = this->ui_.textEdit->textCursor();
|
auto cursor = this->ui_.textEdit->textCursor();
|
||||||
cursor.select(QTextCursor::WordUnderCursor);
|
cursor.select(QTextCursor::WordUnderCursor);
|
||||||
this->ui_.textEdit->setTextCursor(cursor);
|
this->ui_.textEdit->setTextCursor(cursor);
|
||||||
|
@ -1018,7 +1030,7 @@ void SplitInput::paintEvent(QPaintEvent * /*event*/)
|
||||||
{
|
{
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
|
|
||||||
int s;
|
int s{};
|
||||||
QColor borderColor;
|
QColor borderColor;
|
||||||
|
|
||||||
if (this->theme->isLightTheme())
|
if (this->theme->isLightTheme())
|
||||||
|
@ -1052,8 +1064,10 @@ void SplitInput::paintEvent(QPaintEvent * /*event*/)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitInput::resizeEvent(QResizeEvent *)
|
void SplitInput::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
|
(void)event;
|
||||||
|
|
||||||
if (this->height() == this->maximumHeight())
|
if (this->height() == this->maximumHeight())
|
||||||
{
|
{
|
||||||
this->ui_.textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
this->ui_.textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
|
|
@ -80,14 +80,13 @@ protected:
|
||||||
|
|
||||||
virtual void giveFocus(Qt::FocusReason reason);
|
virtual void giveFocus(Qt::FocusReason reason);
|
||||||
|
|
||||||
QString handleSendMessage(std::vector<QString> &arguments);
|
QString handleSendMessage(const std::vector<QString> &arguments);
|
||||||
void postMessageSend(const QString &message,
|
void postMessageSend(const QString &message,
|
||||||
const std::vector<QString> &arguments);
|
const std::vector<QString> &arguments);
|
||||||
|
|
||||||
/// Clears the input box, clears reply thread if inline replies are enabled
|
/// Clears the input box, clears reply thread if inline replies are enabled
|
||||||
void clearInput();
|
void clearInput();
|
||||||
|
|
||||||
protected:
|
|
||||||
void addShortcuts() override;
|
void addShortcuts() override;
|
||||||
void initLayout();
|
void initLayout();
|
||||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
Loading…
Reference in a new issue