From 0442b7a81bbd839ace038c34fa851d5e26cc0fe3 Mon Sep 17 00:00:00 2001 From: 2547techno <109011672+2547techno@users.noreply.github.com> Date: Fri, 5 Jul 2024 19:25:39 -0400 Subject: [PATCH 01/63] Add `Network` to plugin info schema (#5492) --- CHANGELOG.md | 2 +- docs/plugin-info.schema.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa05a4478..0e902bab6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ - Minor: Added drop indicator line while dragging in tables. (#5256) - Minor: Add channel points indication for new bits power-up redemptions. (#5471) - Minor: Added `/warn ` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474) -- Minor: Introduce HTTP API for plugins. (#5383) +- Minor: Introduce HTTP API for plugins. (#5383, #5492) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) - Bugfix: Fixed restricted users usernames not being clickable. (#5405) diff --git a/docs/plugin-info.schema.json b/docs/plugin-info.schema.json index 464201002..07c1a29f9 100644 --- a/docs/plugin-info.schema.json +++ b/docs/plugin-info.schema.json @@ -51,7 +51,7 @@ "type": "object", "properties": { "type": { - "enum": ["FilesystemRead", "FilesystemWrite"] + "enum": ["FilesystemRead", "FilesystemWrite", "Network"] } } } From 93fbcbbe5f700f7cfb82845d0a8aa61bb8737105 Mon Sep 17 00:00:00 2001 From: 2547techno <109011672+2547techno@users.noreply.github.com> Date: Fri, 5 Jul 2024 20:02:21 -0400 Subject: [PATCH 02/63] fix plugin http types & docs (#5494) --- CHANGELOG.md | 2 +- docs/plugin-meta.lua | 43 +++++++++------------ docs/wip-plugins.md | 16 ++------ src/controllers/plugins/LuaAPI.hpp | 2 +- src/controllers/plugins/api/HTTPRequest.hpp | 7 ---- 5 files changed, 25 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e902bab6..af0cd8545 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ - Minor: Added drop indicator line while dragging in tables. (#5256) - Minor: Add channel points indication for new bits power-up redemptions. (#5471) - Minor: Added `/warn ` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474) -- Minor: Introduce HTTP API for plugins. (#5383, #5492) +- Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) - Bugfix: Fixed restricted users usernames not being clickable. (#5405) diff --git a/docs/plugin-meta.lua b/docs/plugin-meta.lua index 453e4f548..d4b1ac25b 100644 --- a/docs/plugin-meta.lua +++ b/docs/plugin-meta.lua @@ -158,12 +158,27 @@ function c2.Channel.by_twitch_id(id) end -- End src/controllers/plugins/api/ChannelRef.hpp --- Begin src/controllers/plugins/api/HTTPRequest.hpp +-- Begin src/controllers/plugins/api/HTTPResponse.hpp ---@class HTTPResponse ----@field data string Data received from the server ----@field status integer? HTTP Status code returned by the server ----@field error string A somewhat human readable description of an error if such happened +HTTPResponse = {} + +--- Returns the data. This is not guaranteed to be encoded using any +--- particular encoding scheme. It's just the bytes the server returned. +--- +function HTTPResponse:data() end + +--- Returns the status code. +--- +function HTTPResponse:status() end + +--- A somewhat human readable description of an error if such happened +--- +function HTTPResponse:error() end + +-- End src/controllers/plugins/api/HTTPResponse.hpp + +-- Begin src/controllers/plugins/api/HTTPRequest.hpp ---@alias HTTPCallback fun(result: HTTPResponse): nil ---@class HTTPRequest @@ -213,26 +228,6 @@ function HTTPRequest.create(method, url) end -- End src/controllers/plugins/api/HTTPRequest.hpp --- Begin src/controllers/plugins/api/HTTPResponse.hpp - ----@class HTTPResponse -HTTPResponse = {} - ---- Returns the data. This is not guaranteed to be encoded using any ---- particular encoding scheme. It's just the bytes the server returned. ---- -function HTTPResponse:data() end - ---- Returns the status code. ---- -function HTTPResponse:status() end - ---- A somewhat human readable description of an error if such happened ---- -function HTTPResponse:error() end - --- End src/controllers/plugins/api/HTTPResponse.hpp - -- Begin src/common/network/NetworkCommon.hpp ---@alias HTTPMethod integer diff --git a/docs/wip-plugins.md b/docs/wip-plugins.md index bf49e0f4c..cd38fa18c 100644 --- a/docs/wip-plugins.md +++ b/docs/wip-plugins.md @@ -420,14 +420,6 @@ It returns something like: `"ConnectionRefusedError"`, `"401"`. This function returns the HTTP status code of the request or `nil` if there was an error before a status code could be received. -```lua -{ - data = "This is the data received from the server as a string", - status = 200, -- HTTP status code returned by the server or nil if no response was received because of an error - error = "A somewhat human readable description of an error if such happened" -} -``` - #### `HTTPRequest` Allows you to send an HTTP request to a URL. Do not create requests that you @@ -443,7 +435,7 @@ containing a valid URL (ex. `https://example.com/path/to/api`). ```lua local req = c2.HTTPRequest.create(c2.HTTPMethod.Get, "https://example.com") req:on_success(function (res) - print(res.data) + print(res:data()) end) req:execute() ``` @@ -496,12 +488,12 @@ request:set_header("Content-Type", "text/plain") request:on_success(function (res) print('Success!') -- Data is in res.data - print(res.status) + print(res:status()) end) request:on_error(function (res) print('Error!') - print(res.status) - print(res.error) + print(res:status()) + print(res:error()) end) request:finally(function () print('Finally') diff --git a/src/controllers/plugins/LuaAPI.hpp b/src/controllers/plugins/LuaAPI.hpp index dd3ee8306..904c6daa4 100644 --- a/src/controllers/plugins/LuaAPI.hpp +++ b/src/controllers/plugins/LuaAPI.hpp @@ -82,8 +82,8 @@ struct CompletionEvent { /** * @includefile common/Channel.hpp * @includefile controllers/plugins/api/ChannelRef.hpp - * @includefile controllers/plugins/api/HTTPRequest.hpp * @includefile controllers/plugins/api/HTTPResponse.hpp + * @includefile controllers/plugins/api/HTTPRequest.hpp * @includefile common/network/NetworkCommon.hpp */ diff --git a/src/controllers/plugins/api/HTTPRequest.hpp b/src/controllers/plugins/api/HTTPRequest.hpp index c373dcec1..955a3cd2d 100644 --- a/src/controllers/plugins/api/HTTPRequest.hpp +++ b/src/controllers/plugins/api/HTTPRequest.hpp @@ -9,13 +9,6 @@ namespace chatterino::lua::api { // NOLINTBEGIN(readability-identifier-naming) -/** - * @lua@class HTTPResponse - * @lua@field data string Data received from the server - * @lua@field status integer? HTTP Status code returned by the server - * @lua@field error string A somewhat human readable description of an error if such happened - */ - /** * @lua@alias HTTPCallback fun(result: HTTPResponse): nil */ From 8e29f753088d546a0999e57dfa444d8e52776ecf Mon Sep 17 00:00:00 2001 From: Daniel Sage <24928223+dnsge@users.noreply.github.com> Date: Sun, 7 Jul 2024 02:42:49 -0700 Subject: [PATCH 03/63] Enable antialiasing for reply button (#5491) --- CHANGELOG.md | 1 + src/messages/layouts/MessageLayoutContainer.cpp | 2 ++ src/messages/layouts/MessageLayoutElement.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af0cd8545..74acfc0bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Minor: Added drop indicator line while dragging in tables. (#5256) - Minor: Add channel points indication for new bits power-up redemptions. (#5471) - Minor: Added `/warn ` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474) +- Minor: Improve appearance of reply button. (#5491) - Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) diff --git a/src/messages/layouts/MessageLayoutContainer.cpp b/src/messages/layouts/MessageLayoutContainer.cpp index e5e53f360..5c3942763 100644 --- a/src/messages/layouts/MessageLayoutContainer.cpp +++ b/src/messages/layouts/MessageLayoutContainer.cpp @@ -233,7 +233,9 @@ void MessageLayoutContainer::paintElements(QPainter &painter, painter.drawRect(element->getRect()); #endif + painter.save(); element->paint(painter, ctx.messageColors); + painter.restore(); } } diff --git a/src/messages/layouts/MessageLayoutElement.cpp b/src/messages/layouts/MessageLayoutElement.cpp index 31b7d4fe5..3bfe77330 100644 --- a/src/messages/layouts/MessageLayoutElement.cpp +++ b/src/messages/layouts/MessageLayoutElement.cpp @@ -392,6 +392,7 @@ void ImageWithCircleBackgroundLayoutElement::paint( if (pixmap && !this->image_->animated()) { QRectF boxRect(this->getRect()); + painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); painter.setBrush(QBrush(this->color_, Qt::SolidPattern)); painter.drawEllipse(boxRect); From 2d11e79f4d30bc2795e83bea652396cf169dbbc0 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 7 Jul 2024 12:10:08 +0200 Subject: [PATCH 04/63] chore: Update settings library to v0.2.0 (#5496) Most notably, this aims to improve the saving experience on windows with https://github.com/pajlada/settings/pull/87 --- lib/settings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/settings b/lib/settings index f3e9161ee..7011003ea 160000 --- a/lib/settings +++ b/lib/settings @@ -1 +1 @@ -Subproject commit f3e9161ee61b47da71c7858e24efee9b0053357f +Subproject commit 7011003eabf6ac95c19f523968a72771fc177fcd From 4535823ca886a6c53178924ccf70a877e1f63e86 Mon Sep 17 00:00:00 2001 From: nerix Date: Sun, 7 Jul 2024 12:41:21 +0200 Subject: [PATCH 05/63] fix: use selected window for `/clearmessages` (#5489) --- CHANGELOG.md | 1 + src/controllers/commands/builtin/Misc.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74acfc0bb..1f8be9a5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - Bugfix: Fixed message history occasionally not loading after a sleep. (#5457) - Bugfix: Fixed a crash when tab completing while having an invalid plugin loaded. (#5401) - Bugfix: Fixed windows on Windows not saving correctly when snapping them to the edges. (#5478) +- Bugfix: Fixed `/clearmessages` not working with more than one window. (#5489) - Dev: Update Windows build from Qt 6.5.0 to Qt 6.7.1. (#5420) - Dev: Update vcpkg build Qt from 6.5.0 to 6.7.0, boost from 1.83.0 to 1.85.0, openssl from 3.1.3 to 3.3.0. (#5422) - Dev: Unsingletonize `ISoundController`. (#5462) diff --git a/src/controllers/commands/builtin/Misc.cpp b/src/controllers/commands/builtin/Misc.cpp index e1940271a..caf532c62 100644 --- a/src/controllers/commands/builtin/Misc.cpp +++ b/src/controllers/commands/builtin/Misc.cpp @@ -401,11 +401,11 @@ QString clearmessages(const CommandContext &ctx) { (void)ctx; - auto *currentPage = dynamic_cast(getIApp() - ->getWindows() - ->getMainWindow() - .getNotebook() - .getSelectedPage()); + auto *currentPage = getIApp() + ->getWindows() + ->getLastSelectedWindow() + ->getNotebook() + .getSelectedPage(); if (auto *split = currentPage->getSelectedSplit()) { From 354079c74cdfbc15d5512a53ca18691074be3c35 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 7 Jul 2024 22:03:05 +0200 Subject: [PATCH 06/63] refactor: add `Channel::addSystemMessage` function (#5500) --- CHANGELOG.md | 1 + src/Application.cpp | 20 ++-- src/CMakeLists.txt | 2 - src/common/Channel.cpp | 6 + src/common/Channel.hpp | 2 + .../commands/CommandController.cpp | 3 +- src/controllers/commands/builtin/Misc.cpp | 112 +++++++++--------- .../commands/builtin/chatterino/Debugging.cpp | 16 ++- .../commands/builtin/twitch/AddModerator.cpp | 23 ++-- .../commands/builtin/twitch/AddVIP.cpp | 23 ++-- .../commands/builtin/twitch/Announce.cpp | 14 +-- .../commands/builtin/twitch/Ban.cpp | 49 ++++---- .../commands/builtin/twitch/Block.cpp | 59 +++++---- .../commands/builtin/twitch/ChatSettings.cpp | 110 +++++++++-------- .../commands/builtin/twitch/Chatters.cpp | 17 ++- .../builtin/twitch/DeleteMessages.cpp | 27 ++--- .../commands/builtin/twitch/GetModerators.cpp | 10 +- .../commands/builtin/twitch/GetVIPs.cpp | 15 ++- .../commands/builtin/twitch/Raid.cpp | 44 ++++--- .../builtin/twitch/RemoveModerator.cpp | 24 ++-- .../commands/builtin/twitch/RemoveVIP.cpp | 22 ++-- .../commands/builtin/twitch/SendReply.cpp | 12 +- .../commands/builtin/twitch/SendWhisper.cpp | 12 +- .../commands/builtin/twitch/ShieldMode.cpp | 17 ++- .../commands/builtin/twitch/Shoutout.cpp | 23 ++-- .../builtin/twitch/StartCommercial.cpp | 18 ++- .../commands/builtin/twitch/Unban.cpp | 21 ++-- .../commands/builtin/twitch/UpdateChannel.cpp | 32 +++-- .../commands/builtin/twitch/UpdateColor.cpp | 16 +-- .../commands/builtin/twitch/Warn.cpp | 26 ++-- src/providers/bttv/BttvEmotes.cpp | 14 +-- src/providers/ffz/FfzEmotes.cpp | 14 +-- src/providers/irc/IrcChannel2.cpp | 5 +- src/providers/irc/IrcCommands.cpp | 6 +- src/providers/irc/IrcServer.cpp | 8 +- src/providers/recentmessages/Api.cpp | 8 +- src/providers/seventv/SeventvEmotes.cpp | 13 +- src/providers/twitch/IrcMessageHandler.cpp | 11 +- src/providers/twitch/TwitchAccount.cpp | 8 +- src/providers/twitch/TwitchChannel.cpp | 15 ++- src/providers/twitch/TwitchIrcServer.cpp | 37 +++--- src/singletons/ImageUploader.cpp | 11 +- src/util/StreamLink.cpp | 4 +- src/widgets/dialogs/NotificationPopup.cpp | 52 -------- src/widgets/dialogs/NotificationPopup.hpp | 29 ----- src/widgets/dialogs/UserInfoPopup.cpp | 16 +-- src/widgets/splits/Split.cpp | 4 +- 47 files changed, 443 insertions(+), 588 deletions(-) delete mode 100644 src/widgets/dialogs/NotificationPopup.cpp delete mode 100644 src/widgets/dialogs/NotificationPopup.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f8be9a5f..97cf0796f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ - Dev: Refactor `TwitchIrcServer`, making it abstracted. (#5421, #5435) - Dev: Reduced the amount of scale events. (#5404, #5406) - Dev: Removed unused timegate settings. (#5361) +- Dev: Add `Channel::addSystemMessage` helper function, allowing us to avoid the common `channel->addMessage(makeSystemMessage(...));` pattern. (#5500) - Dev: Unsingletonize `Resources2`. (#5460) - Dev: All Lua globals now show in the `c2` global in the LuaLS metadata. (#5385) - Dev: Images are now loaded in worker threads. (#5431) diff --git a/src/Application.cpp b/src/Application.cpp index 529b2481b..cf4e6f07a 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -1,6 +1,7 @@ #include "Application.hpp" #include "common/Args.hpp" +#include "common/Channel.hpp" #include "common/QLogging.hpp" #include "common/Version.hpp" #include "controllers/accounts/AccountController.hpp" @@ -233,10 +234,10 @@ void Application::initialize(Settings &settings, const Paths &paths) { if (auto channel = split->getChannel(); !channel->isEmpty()) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( "Chatterino unexpectedly crashed and restarted. " "You can disable automatic restarts in the " - "settings.")); + "settings."); } } } @@ -584,9 +585,8 @@ void Application::initPubSub() QString text = QString("%1 cleared the chat.").arg(action.source.login); - auto msg = makeSystemMessage(text); - postToThread([chan, msg] { - chan->addMessage(msg); + postToThread([chan, text] { + chan->addSystemMessage(text); }); }); @@ -610,9 +610,8 @@ void Application::initPubSub() text += QString(" (%1 seconds)").arg(action.duration); } - auto msg = makeSystemMessage(text); - postToThread([chan, msg] { - chan->addMessage(msg); + postToThread([chan, text] { + chan->addSystemMessage(text); }); }); @@ -631,9 +630,8 @@ void Application::initPubSub() (action.modded ? "modded" : "unmodded"), action.target.login); - auto msg = makeSystemMessage(text); - postToThread([chan, msg] { - chan->addMessage(msg); + postToThread([chan, text] { + chan->addSystemMessage(text); }); }); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2546d9a94..7728acdf6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -585,8 +585,6 @@ set(SOURCE_FILES widgets/dialogs/LastRunCrashDialog.hpp widgets/dialogs/LoginDialog.cpp widgets/dialogs/LoginDialog.hpp - widgets/dialogs/NotificationPopup.cpp - widgets/dialogs/NotificationPopup.hpp widgets/dialogs/QualityPopup.cpp widgets/dialogs/QualityPopup.hpp widgets/dialogs/ReplyThreadPopup.cpp diff --git a/src/common/Channel.cpp b/src/common/Channel.cpp index 7141dbe7e..38d4014aa 100644 --- a/src/common/Channel.cpp +++ b/src/common/Channel.cpp @@ -120,6 +120,12 @@ void Channel::addMessage(MessagePtr message, this->messageAppended.invoke(message, overridingFlags); } +void Channel::addSystemMessage(const QString &contents) +{ + auto msg = makeSystemMessage(contents); + this->addMessage(msg); +} + void Channel::addOrReplaceTimeout(MessagePtr message) { addOrReplaceChannelTimeout( diff --git a/src/common/Channel.hpp b/src/common/Channel.hpp index 106d6cabc..aaea98621 100644 --- a/src/common/Channel.hpp +++ b/src/common/Channel.hpp @@ -83,6 +83,8 @@ public: std::optional overridingFlags = std::nullopt); void addMessagesAtStart(const std::vector &messages_); + void addSystemMessage(const QString &contents); + /// Inserts the given messages in order by Message::serverReceivedTime. void fillInMissingMessages(const std::vector &messages); diff --git a/src/controllers/commands/CommandController.cpp b/src/controllers/commands/CommandController.cpp index ac4dca9e8..4742088e4 100644 --- a/src/controllers/commands/CommandController.cpp +++ b/src/controllers/commands/CommandController.cpp @@ -554,8 +554,7 @@ QString CommandController::execCommand(const QString &textNoEmoji, if (!dryRun && channel->getType() == Channel::Type::TwitchWhispers) { - channel->addMessage( - makeSystemMessage("Use /w to whisper")); + channel->addSystemMessage("Use /w to whisper"); return ""; } diff --git a/src/controllers/commands/builtin/Misc.cpp b/src/controllers/commands/builtin/Misc.cpp index caf532c62..a7fcc7662 100644 --- a/src/controllers/commands/builtin/Misc.cpp +++ b/src/controllers/commands/builtin/Misc.cpp @@ -5,7 +5,6 @@ #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" #include "controllers/userdata/UserDataController.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -39,10 +38,10 @@ QString follow(const CommandContext &ctx) { return ""; } - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Twitch has removed the ability to follow users through " "third-party applications. For more information, see " - "https://github.com/Chatterino/chatterino2/issues/3076")); + "https://github.com/Chatterino/chatterino2/issues/3076"); return ""; } @@ -52,10 +51,10 @@ QString unfollow(const CommandContext &ctx) { return ""; } - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Twitch has removed the ability to unfollow users through " "third-party applications. For more information, see " - "https://github.com/Chatterino/chatterino2/issues/3076")); + "https://github.com/Chatterino/chatterino2/issues/3076"); return ""; } @@ -68,8 +67,8 @@ QString uptime(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /uptime command only works in Twitch Channels.")); + ctx.channel->addSystemMessage( + "The /uptime command only works in Twitch Channels."); return ""; } @@ -78,7 +77,7 @@ QString uptime(const CommandContext &ctx) QString messageText = streamStatus->live ? streamStatus->uptime : "Channel is not live."; - ctx.channel->addMessage(makeSystemMessage(messageText)); + ctx.channel->addSystemMessage(messageText); return ""; } @@ -92,8 +91,7 @@ QString user(const CommandContext &ctx) if (ctx.words.size() < 2) { - ctx.channel->addMessage( - makeSystemMessage("Usage: /user [channel]")); + ctx.channel->addSystemMessage("Usage: /user [channel]"); return ""; } QString userName = ctx.words[1]; @@ -129,11 +127,11 @@ QString requests(const CommandContext &ctx) } else { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: /requests [channel]. You can also use the command " "without arguments in any Twitch channel to open its " "channel points requests queue. Only the broadcaster and " - "moderators have permission to view the queue.")); + "moderators have permission to view the queue."); return ""; } } @@ -163,11 +161,11 @@ QString lowtrust(const CommandContext &ctx) } else { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: /lowtrust [channel]. You can also use the command " "without arguments in any Twitch channel to open its " "suspicious user activity feed. Only the broadcaster and " - "moderators have permission to view this feed.")); + "moderators have permission to view this feed."); return ""; } } @@ -190,15 +188,15 @@ QString clip(const CommandContext &ctx) if (const auto type = ctx.channel->getType(); type != Channel::Type::Twitch && type != Channel::Type::TwitchWatching) { - ctx.channel->addMessage(makeSystemMessage( - "The /clip command only works in Twitch Channels.")); + ctx.channel->addSystemMessage( + "The /clip command only works in Twitch Channels."); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /clip command only works in Twitch Channels.")); + ctx.channel->addSystemMessage( + "The /clip command only works in Twitch Channels."); return ""; } @@ -216,25 +214,25 @@ QString marker(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /marker command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /marker command only works in Twitch channels."); return ""; } // Avoid Helix calls without Client ID and/or OAuth Token if (getIApp()->getAccounts()->twitch.getCurrent()->isAnon()) { - ctx.channel->addMessage(makeSystemMessage( - "You need to be logged in to create stream markers!")); + ctx.channel->addSystemMessage( + "You need to be logged in to create stream markers!"); return ""; } // Exact same message as in webchat if (!ctx.twitchChannel->isLive()) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "You can only add stream markers during live streams. Try " - "again when the channel is live streaming.")); + "again when the channel is live streaming."); return ""; } @@ -247,13 +245,13 @@ QString marker(const CommandContext &ctx) ctx.twitchChannel->roomId(), arguments.join(" ").left(140), [channel{ctx.channel}, arguments](const HelixStreamMarker &streamMarker) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Successfully added a stream marker at %1%2") .arg(formatTime(streamMarker.positionSeconds)) .arg(streamMarker.description.isEmpty() ? "" : QString(": \"%1\"") - .arg(streamMarker.description)))); + .arg(streamMarker.description))); }, [channel{ctx.channel}](auto error) { QString errorMessage("Failed to create stream marker - "); @@ -279,7 +277,7 @@ QString marker(const CommandContext &ctx) break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; @@ -303,10 +301,10 @@ QString streamlink(const CommandContext &ctx) } else { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "/streamlink [channel]. Open specified Twitch channel in " "streamlink. If no channel argument is specified, open the " - "current Twitch channel instead.")); + "current Twitch channel instead."); return ""; } } @@ -335,10 +333,10 @@ QString popout(const CommandContext &ctx) } else { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: /popout . You can also use the command " "without arguments in any Twitch channel to open its " - "popout chat.")); + "popout chat."); return ""; } } @@ -385,7 +383,7 @@ QString popup(const CommandContext &ctx) } } - ctx.channel->addMessage(makeSystemMessage(usageMessage)); + ctx.channel->addSystemMessage(usageMessage); return ""; } @@ -469,8 +467,8 @@ QString openURL(const CommandContext &ctx) const auto &positionalArguments = parser.positionalArguments(); if (positionalArguments.isEmpty()) { - ctx.channel->addMessage(makeSystemMessage( - "Usage: /openurl [--incognito/--no-incognito]")); + ctx.channel->addSystemMessage( + "Usage: /openurl [--incognito/--no-incognito]"); return ""; } auto urlString = parser.positionalArguments().join(' '); @@ -478,7 +476,7 @@ QString openURL(const CommandContext &ctx) QUrl url = QUrl::fromUserInput(urlString); if (!url.isValid()) { - ctx.channel->addMessage(makeSystemMessage("Invalid URL specified.")); + ctx.channel->addSystemMessage("Invalid URL specified."); return ""; } @@ -488,9 +486,9 @@ QString openURL(const CommandContext &ctx) if (forcePrivateMode && forceNonPrivateMode) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Error: /openurl may only be called with --incognito or " - "--no-incognito, not both at the same time.")); + "--no-incognito, not both at the same time."); return ""; } @@ -518,7 +516,7 @@ QString openURL(const CommandContext &ctx) if (!res) { - ctx.channel->addMessage(makeSystemMessage("Could not open URL.")); + ctx.channel->addSystemMessage("Could not open URL."); } return ""; @@ -553,16 +551,16 @@ QString injectFakeMessage(const CommandContext &ctx) if (!ctx.channel->isTwitchChannel()) { - ctx.channel->addMessage(makeSystemMessage( - "The /fakemsg command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /fakemsg command only works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: /fakemsg (raw irc text) - injects raw irc text as " - "if it was a message received from TMI")); + "if it was a message received from TMI"); return ""; } @@ -583,9 +581,9 @@ QString injectStreamUpdateNoStream(const CommandContext &ctx) } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage( - makeSystemMessage("The /debug-update-to-no-stream command only " - "works in Twitch channels")); + ctx.channel->addSystemMessage( + "The /debug-update-to-no-stream command only " + "works in Twitch channels"); return ""; } @@ -602,9 +600,8 @@ QString copyToClipboard(const CommandContext &ctx) if (ctx.words.size() < 2) { - ctx.channel->addMessage( - makeSystemMessage("Usage: /copy - copies provided " - "text to clipboard.")); + ctx.channel->addSystemMessage("Usage: /copy - copies provided " + "text to clipboard."); return ""; } @@ -621,15 +618,15 @@ QString unstableSetUserClientSideColor(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage( - makeSystemMessage("The /unstable-set-user-color command only " - "works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /unstable-set-user-color command only " + "works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage( - QString("Usage: %1 [color]").arg(ctx.words.at(0)))); + ctx.channel->addSystemMessage( + QString("Usage: %1 [color]").arg(ctx.words.at(0))); return ""; } @@ -653,9 +650,8 @@ QString openUsercard(const CommandContext &ctx) if (ctx.words.size() < 2) { - channel->addMessage( - makeSystemMessage("Usage: /usercard [channel] or " - "/usercard id: [channel]")); + channel->addSystemMessage("Usage: /usercard [channel] or " + "/usercard id: [channel]"); return ""; } @@ -672,9 +668,9 @@ QString openUsercard(const CommandContext &ctx) if (channelTemp->isEmpty()) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( "A usercard can only be displayed for a channel that is " - "currently opened in Chatterino.")); + "currently opened in Chatterino."); return ""; } diff --git a/src/controllers/commands/builtin/chatterino/Debugging.cpp b/src/controllers/commands/builtin/chatterino/Debugging.cpp index c72f0cde0..52ec87967 100644 --- a/src/controllers/commands/builtin/chatterino/Debugging.cpp +++ b/src/controllers/commands/builtin/chatterino/Debugging.cpp @@ -22,12 +22,12 @@ QString setLoggingRules(const CommandContext &ctx) { if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: /c2-set-logging-rules . To enable debug logging " "for all categories from chatterino, use " "'chatterino.*.debug=true'. For the format on the rules, see " "https://doc.qt.io/qt-6/" - "qloggingcategory.html#configuring-categories")); + "qloggingcategory.html#configuring-categories"); return {}; } @@ -47,7 +47,7 @@ QString setLoggingRules(const CommandContext &ctx) "https://doc.qt.io/qt-6/qloggingcategory.html#setFilterRules"); } - ctx.channel->addMessage(makeSystemMessage(message)); + ctx.channel->addSystemMessage(message); return {}; } @@ -56,15 +56,13 @@ QString toggleThemeReload(const CommandContext &ctx) if (getTheme()->isAutoReloading()) { getTheme()->setAutoReload(false); - ctx.channel->addMessage( - makeSystemMessage(u"Disabled theme auto reloading."_s)); + ctx.channel->addSystemMessage(u"Disabled theme auto reloading."_s); return {}; } getTheme()->setAutoReload(true); - ctx.channel->addMessage( - makeSystemMessage(u"Auto reloading theme every %1 ms."_s.arg( - Theme::AUTO_RELOAD_INTERVAL_MS))); + ctx.channel->addSystemMessage(u"Auto reloading theme every %1 ms."_s.arg( + Theme::AUTO_RELOAD_INTERVAL_MS)); return {}; } @@ -107,7 +105,7 @@ QString listArgs(const CommandContext &ctx) QString msg = QApplication::instance()->arguments().join(' '); - channel->addMessage(makeSystemMessage(msg)); + channel->addSystemMessage(msg); return ""; } diff --git a/src/controllers/commands/builtin/twitch/AddModerator.cpp b/src/controllers/commands/builtin/twitch/AddModerator.cpp index 6c88eb024..6d06d9f82 100644 --- a/src/controllers/commands/builtin/twitch/AddModerator.cpp +++ b/src/controllers/commands/builtin/twitch/AddModerator.cpp @@ -1,10 +1,8 @@ #include "controllers/commands/builtin/twitch/AddModerator.hpp" #include "Application.hpp" -#include "common/Channel.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -22,23 +20,22 @@ QString addModerator(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /mod command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /mod command only works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: \"/mod \" - Grant moderator status to a " - "user. Use \"/mods\" to list the moderators of this channel.")); + "user. Use \"/mods\" to list the moderators of this channel."); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to mod someone!")); + ctx.channel->addSystemMessage("You must be logged in to mod someone!"); return ""; } @@ -52,10 +49,10 @@ QString addModerator(const CommandContext &ctx) getHelix()->addChannelModerator( twitchChannel->roomId(), targetUser.id, [channel, targetUser] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("You have added %1 as a moderator of this " "channel.") - .arg(targetUser.displayName))); + .arg(targetUser.displayName)); }, [channel, targetUser](auto error, auto message) { QString errorMessage = @@ -116,13 +113,13 @@ QString addModerator(const CommandContext &ctx) } break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); }, [channel{ctx.channel}, target] { // Equivalent error from IRC - channel->addMessage( - makeSystemMessage(QString("Invalid username: %1").arg(target))); + channel->addSystemMessage( + QString("Invalid username: %1").arg(target)); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/AddVIP.cpp b/src/controllers/commands/builtin/twitch/AddVIP.cpp index ab0ae679e..26d374192 100644 --- a/src/controllers/commands/builtin/twitch/AddVIP.cpp +++ b/src/controllers/commands/builtin/twitch/AddVIP.cpp @@ -1,10 +1,8 @@ #include "controllers/commands/builtin/twitch/AddVIP.hpp" #include "Application.hpp" -#include "common/Channel.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -22,23 +20,22 @@ QString addVIP(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /vip command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /vip command only works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: \"/vip \" - Grant VIP status to a user. Use " - "\"/vips\" to list the VIPs of this channel.")); + "\"/vips\" to list the VIPs of this channel."); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to VIP someone!")); + ctx.channel->addSystemMessage("You must be logged in to VIP someone!"); return ""; } @@ -52,9 +49,9 @@ QString addVIP(const CommandContext &ctx) getHelix()->addChannelVIP( twitchChannel->roomId(), targetUser.id, [channel, targetUser] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("You have added %1 as a VIP of this channel.") - .arg(targetUser.displayName))); + .arg(targetUser.displayName)); }, [channel, targetUser](auto error, auto message) { QString errorMessage = QString("Failed to add VIP - "); @@ -97,13 +94,13 @@ QString addVIP(const CommandContext &ctx) } break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); }, [channel{ctx.channel}, target] { // Equivalent error from IRC - channel->addMessage( - makeSystemMessage(QString("Invalid username: %1").arg(target))); + channel->addSystemMessage( + QString("Invalid username: %1").arg(target)); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/Announce.cpp b/src/controllers/commands/builtin/twitch/Announce.cpp index a86746195..67212858e 100644 --- a/src/controllers/commands/builtin/twitch/Announce.cpp +++ b/src/controllers/commands/builtin/twitch/Announce.cpp @@ -1,10 +1,8 @@ #include "controllers/commands/builtin/twitch/Announce.hpp" #include "Application.hpp" -#include "common/Channel.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -22,8 +20,8 @@ QString sendAnnouncementColor(const CommandContext &ctx, if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "This command can only be used in Twitch channels.")); + ctx.channel->addSystemMessage( + "This command can only be used in Twitch channels."); return ""; } @@ -48,16 +46,16 @@ QString sendAnnouncementColor(const CommandContext &ctx, "message with a %1 highlight.") .arg(colorStr); } - ctx.channel->addMessage(makeSystemMessage(usageMsg)); + ctx.channel->addSystemMessage(usageMsg); return ""; } auto user = getIApp()->getAccounts()->twitch.getCurrent(); if (user->isAnon()) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( QString("You must be logged in to use the /announce%1 command.") - .arg(colorStr))); + .arg(colorStr)); return ""; } @@ -93,7 +91,7 @@ QString sendAnnouncementColor(const CommandContext &ctx, break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; } diff --git a/src/controllers/commands/builtin/twitch/Ban.cpp b/src/controllers/commands/builtin/twitch/Ban.cpp index bce3001f4..d2a77486f 100644 --- a/src/controllers/commands/builtin/twitch/Ban.cpp +++ b/src/controllers/commands/builtin/twitch/Ban.cpp @@ -5,7 +5,6 @@ #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" #include "controllers/commands/common/ChannelAction.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -93,7 +92,7 @@ void banUserByID(const ChannelPtr &channel, const QString &channelID, [channel, displayName](auto error, auto message) { auto errorMessage = formatBanTimeoutError("ban", error, message, displayName); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); } @@ -110,7 +109,7 @@ void timeoutUserByID(const ChannelPtr &channel, const QString &channelID, [channel, displayName](auto error, auto message) { auto errorMessage = formatBanTimeoutError("timeout", error, message, displayName); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); } @@ -129,7 +128,7 @@ QString sendBan(const CommandContext &ctx) { if (ctx.channel != nullptr) { - ctx.channel->addMessage(makeSystemMessage(actions.error())); + ctx.channel->addSystemMessage(actions.error()); } else { @@ -145,8 +144,7 @@ QString sendBan(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to ban someone!")); + ctx.channel->addSystemMessage("You must be logged in to ban someone!"); return ""; } @@ -192,16 +190,16 @@ QString sendBan(const CommandContext &ctx) userLoginsToFetch](const auto &users) mutable { if (!actionChannel.hydrateFrom(users)) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to ban, bad channel name: %1") - .arg(actionChannel.login))); + .arg(actionChannel.login)); return; } if (!actionTarget.hydrateFrom(users)) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to ban, bad target name: %1") - .arg(actionTarget.login))); + .arg(actionTarget.login)); return; } @@ -210,9 +208,9 @@ QString sendBan(const CommandContext &ctx) reason, actionTarget.displayName); }, [channel{ctx.channel}, userLoginsToFetch] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to ban, bad username(s): %1") - .arg(userLoginsToFetch.join(", ")))); + .arg(userLoginsToFetch.join(", "))); }); } else @@ -239,8 +237,8 @@ QString sendBanById(const CommandContext &ctx) } if (twitchChannel == nullptr) { - channel->addMessage(makeSystemMessage( - QString("The /banid command only works in Twitch channels."))); + channel->addSystemMessage( + "The /banid command only works in Twitch channels."); return ""; } @@ -250,15 +248,14 @@ QString sendBanById(const CommandContext &ctx) "shown to the target user and other moderators."; if (words.size() < 2) { - channel->addMessage(makeSystemMessage(usageStr)); + channel->addSystemMessage(usageStr); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - channel->addMessage( - makeSystemMessage("You must be logged in to ban someone!")); + channel->addSystemMessage("You must be logged in to ban someone!"); return ""; } @@ -282,7 +279,7 @@ QString sendTimeout(const CommandContext &ctx) { if (ctx.channel != nullptr) { - ctx.channel->addMessage(makeSystemMessage(actions.error())); + ctx.channel->addSystemMessage(actions.error()); } else { @@ -298,8 +295,8 @@ QString sendTimeout(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to timeout someone!")); + ctx.channel->addSystemMessage( + "You must be logged in to timeout someone!"); return ""; } @@ -346,16 +343,16 @@ QString sendTimeout(const CommandContext &ctx) userLoginsToFetch](const auto &users) mutable { if (!actionChannel.hydrateFrom(users)) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to timeout, bad channel name: %1") - .arg(actionChannel.login))); + .arg(actionChannel.login)); return; } if (!actionTarget.hydrateFrom(users)) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to timeout, bad target name: %1") - .arg(actionTarget.login))); + .arg(actionTarget.login)); return; } @@ -364,9 +361,9 @@ QString sendTimeout(const CommandContext &ctx) duration, reason, actionTarget.displayName); }, [channel{ctx.channel}, userLoginsToFetch] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to timeout, bad username(s): %1") - .arg(userLoginsToFetch.join(", ")))); + .arg(userLoginsToFetch.join(", "))); }); } else diff --git a/src/controllers/commands/builtin/twitch/Block.cpp b/src/controllers/commands/builtin/twitch/Block.cpp index 35bb780d7..3a0419d5a 100644 --- a/src/controllers/commands/builtin/twitch/Block.cpp +++ b/src/controllers/commands/builtin/twitch/Block.cpp @@ -4,7 +4,6 @@ #include "common/Channel.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "util/Twitch.hpp" @@ -26,14 +25,14 @@ QString blockUser(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /block command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /block command only works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage("Usage: /block ")); + ctx.channel->addSystemMessage("Usage: /block "); return ""; } @@ -41,8 +40,8 @@ QString blockUser(const CommandContext &ctx) if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to block someone!")); + ctx.channel->addSystemMessage( + "You must be logged in to block someone!"); return ""; } @@ -56,22 +55,21 @@ QString blockUser(const CommandContext &ctx) getIApp()->getAccounts()->twitch.getCurrent()->blockUser( targetUser.id, nullptr, [channel, target, targetUser] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("You successfully blocked user %1") - .arg(target))); + .arg(target)); }, [channel, target] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("User %1 couldn't be blocked, an unknown " "error occurred!") - .arg(target))); + .arg(target)); }); }, [channel{ctx.channel}, target] { - channel->addMessage( - makeSystemMessage(QString("User %1 couldn't be blocked, no " - "user with that name found!") - .arg(target))); + channel->addSystemMessage(QString("User %1 couldn't be blocked, no " + "user with that name found!") + .arg(target)); }); return ""; @@ -84,9 +82,9 @@ QString ignoreUser(const CommandContext &ctx) return ""; } - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Ignore command has been renamed to /block, please use it from " - "now on as /ignore is going to be removed soon.")); + "now on as /ignore is going to be removed soon."); return blockUser(ctx); } @@ -100,14 +98,14 @@ QString unblockUser(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /unblock command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /unblock command only works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage("Usage: /unblock ")); + ctx.channel->addSystemMessage("Usage: /unblock "); return ""; } @@ -115,8 +113,8 @@ QString unblockUser(const CommandContext &ctx) if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to unblock someone!")); + ctx.channel->addSystemMessage( + "You must be logged in to unblock someone!"); return ""; } @@ -129,22 +127,21 @@ QString unblockUser(const CommandContext &ctx) getIApp()->getAccounts()->twitch.getCurrent()->unblockUser( targetUser.id, nullptr, [channel, target, targetUser] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("You successfully unblocked user %1") - .arg(target))); + .arg(target)); }, [channel, target] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("User %1 couldn't be unblocked, an unknown " "error occurred!") - .arg(target))); + .arg(target)); }); }, [channel{ctx.channel}, target] { - channel->addMessage( - makeSystemMessage(QString("User %1 couldn't be unblocked, " - "no user with that name found!") - .arg(target))); + channel->addSystemMessage(QString("User %1 couldn't be unblocked, " + "no user with that name found!") + .arg(target)); }); return ""; @@ -157,9 +154,9 @@ QString unignoreUser(const CommandContext &ctx) return ""; } - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Unignore command has been renamed to /unblock, please use it " - "from now on as /unignore is going to be removed soon.")); + "from now on as /unignore is going to be removed soon."); return unblockUser(ctx); } diff --git a/src/controllers/commands/builtin/twitch/ChatSettings.cpp b/src/controllers/commands/builtin/twitch/ChatSettings.cpp index 9f4bdfea6..1e166193b 100644 --- a/src/controllers/commands/builtin/twitch/ChatSettings.cpp +++ b/src/controllers/commands/builtin/twitch/ChatSettings.cpp @@ -3,7 +3,6 @@ #include "Application.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -87,8 +86,8 @@ auto successCallback = [](auto result) {}; auto failureCallback = [](ChannelPtr channel, int durationUnitMultiplier = 1) { return [channel, durationUnitMultiplier](const auto &error, const QString &message) { - channel->addMessage(makeSystemMessage( - formatError(error, message, durationUnitMultiplier))); + channel->addSystemMessage( + formatError(error, message, durationUnitMultiplier)); }; }; @@ -104,21 +103,21 @@ QString emoteOnly(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /emoteonly command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /emoteonly command only works in Twitch channels."); return ""; } if (ctx.twitchChannel->accessRoomModes()->emoteOnly) { - ctx.channel->addMessage( - makeSystemMessage("This room is already in emote-only mode.")); + ctx.channel->addSystemMessage( + "This room is already in emote-only mode."); return ""; } @@ -134,20 +133,19 @@ QString emoteOnlyOff(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /emoteonlyoff command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /emoteonlyoff command only works in Twitch channels."); return ""; } if (!ctx.twitchChannel->accessRoomModes()->emoteOnly) { - ctx.channel->addMessage( - makeSystemMessage("This room is not in emote-only mode.")); + ctx.channel->addSystemMessage("This room is not in emote-only mode."); return ""; } @@ -163,21 +161,21 @@ QString subscribers(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /subscribers command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /subscribers command only works in Twitch channels."); return ""; } if (ctx.twitchChannel->accessRoomModes()->submode) { - ctx.channel->addMessage(makeSystemMessage( - "This room is already in subscribers-only mode.")); + ctx.channel->addSystemMessage( + "This room is already in subscribers-only mode."); return ""; } @@ -193,21 +191,21 @@ QString subscribersOff(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /subscribersoff command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /subscribersoff command only works in Twitch channels."); return ""; } if (!ctx.twitchChannel->accessRoomModes()->submode) { - ctx.channel->addMessage( - makeSystemMessage("This room is not in subscribers-only mode.")); + ctx.channel->addSystemMessage( + "This room is not in subscribers-only mode."); return ""; } @@ -223,14 +221,14 @@ QString slow(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /slow command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /slow command only works in Twitch channels."); return ""; } @@ -241,20 +239,20 @@ QString slow(const CommandContext &ctx) duration = ctx.words.at(1).toInt(&ok); if (!ok || duration <= 0) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: \"/slow [duration]\" - Enables slow mode (limit how " "often users may send messages). Duration (optional, " "default=30) must be a positive number of seconds. Use " - "\"slowoff\" to disable.")); + "\"slowoff\" to disable."); return ""; } } if (ctx.twitchChannel->accessRoomModes()->slowMode == duration) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( QString("This room is already in %1-second slow mode.") - .arg(duration))); + .arg(duration)); return ""; } @@ -270,21 +268,20 @@ QString slowOff(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /slowoff command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /slowoff command only works in Twitch channels."); return ""; } if (ctx.twitchChannel->accessRoomModes()->slowMode <= 0) { - ctx.channel->addMessage( - makeSystemMessage("This room is not in slow mode.")); + ctx.channel->addSystemMessage("This room is not in slow mode."); return ""; } @@ -300,14 +297,14 @@ QString followers(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /followers command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /followers command only works in Twitch channels."); return ""; } @@ -319,20 +316,20 @@ QString followers(const CommandContext &ctx) // -1 / 60 == 0 => use parsed if (parsed < 0) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: \"/followers [duration]\" - Enables followers-only " "mode (only users who have followed for 'duration' may chat). " "Examples: \"30m\", \"1 week\", \"5 days 12 hours\". Must be " - "less than 3 months.")); + "less than 3 months."); return ""; } } if (ctx.twitchChannel->accessRoomModes()->followerOnly == duration) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( QString("This room is already in %1 followers-only mode.") - .arg(formatTime(duration * 60)))); + .arg(formatTime(duration * 60))); return ""; } @@ -348,21 +345,21 @@ QString followersOff(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /followersoff command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /followersoff command only works in Twitch channels."); return ""; } if (ctx.twitchChannel->accessRoomModes()->followerOnly < 0) { - ctx.channel->addMessage( - makeSystemMessage("This room is not in followers-only mode. ")); + ctx.channel->addSystemMessage( + "This room is not in followers-only mode. "); return ""; } @@ -378,21 +375,21 @@ QString uniqueChat(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /uniquechat command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /uniquechat command only works in Twitch channels."); return ""; } if (ctx.twitchChannel->accessRoomModes()->r9k) { - ctx.channel->addMessage( - makeSystemMessage("This room is already in unique-chat mode.")); + ctx.channel->addSystemMessage( + "This room is already in unique-chat mode."); return ""; } @@ -408,21 +405,20 @@ QString uniqueChatOff(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage(P_NOT_LOGGED_IN)); + ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /uniquechatoff command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /uniquechatoff command only works in Twitch channels."); return ""; } if (!ctx.twitchChannel->accessRoomModes()->r9k) { - ctx.channel->addMessage( - makeSystemMessage("This room is not in unique-chat mode.")); + ctx.channel->addSystemMessage("This room is not in unique-chat mode."); return ""; } diff --git a/src/controllers/commands/builtin/twitch/Chatters.cpp b/src/controllers/commands/builtin/twitch/Chatters.cpp index 8f3134961..0daa75086 100644 --- a/src/controllers/commands/builtin/twitch/Chatters.cpp +++ b/src/controllers/commands/builtin/twitch/Chatters.cpp @@ -69,8 +69,8 @@ QString chatters(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /chatters command only works in Twitch Channels.")); + ctx.channel->addSystemMessage( + "The /chatters command only works in Twitch Channels."); return ""; } @@ -79,13 +79,12 @@ QString chatters(const CommandContext &ctx) ctx.twitchChannel->roomId(), getIApp()->getAccounts()->twitch.getCurrent()->getUserId(), 1, [channel{ctx.channel}](auto result) { - channel->addMessage( - makeSystemMessage(QString("Chatter count: %1.") - .arg(localizeNumbers(result.total)))); + channel->addSystemMessage(QString("Chatter count: %1.") + .arg(localizeNumbers(result.total))); }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatChattersError(error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; @@ -100,8 +99,8 @@ QString testChatters(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /test-chatters command only works in Twitch Channels.")); + ctx.channel->addSystemMessage( + "The /test-chatters command only works in Twitch Channels."); return ""; } @@ -134,7 +133,7 @@ QString testChatters(const CommandContext &ctx) }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatChattersError(error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/DeleteMessages.cpp b/src/controllers/commands/builtin/twitch/DeleteMessages.cpp index c0947968b..e0fe3e069 100644 --- a/src/controllers/commands/builtin/twitch/DeleteMessages.cpp +++ b/src/controllers/commands/builtin/twitch/DeleteMessages.cpp @@ -26,9 +26,9 @@ QString deleteMessages(TwitchChannel *twitchChannel, const QString &messageID) // Avoid Helix calls without Client ID and/or OAuth Token if (user->isAnon()) { - twitchChannel->addMessage(makeSystemMessage( + twitchChannel->addSystemMessage( QString("You must be logged in to use the %1 command.") - .arg(commandName))); + .arg(commandName)); return ""; } @@ -82,7 +82,7 @@ QString deleteMessages(TwitchChannel *twitchChannel, const QString &messageID) break; } - twitchChannel->addMessage(makeSystemMessage(errorMessage)); + twitchChannel->addSystemMessage(errorMessage); }); return ""; @@ -101,8 +101,8 @@ QString deleteAllMessages(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /clear command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /clear command only works in Twitch channels."); return ""; } @@ -120,16 +120,15 @@ QString deleteOneMessage(const CommandContext &ctx) // We use this to ensure the user gets better error messages for missing or malformed arguments if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /delete command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /delete command only works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage( - makeSystemMessage("Usage: /delete - Deletes the " - "specified message.")); + ctx.channel->addSystemMessage("Usage: /delete - Deletes the " + "specified message."); return ""; } @@ -138,8 +137,8 @@ QString deleteOneMessage(const CommandContext &ctx) if (uuid.isNull()) { // The message id must be a valid UUID - ctx.channel->addMessage(makeSystemMessage( - QString("Invalid msg-id: \"%1\"").arg(messageID))); + ctx.channel->addSystemMessage( + QString("Invalid msg-id: \"%1\"").arg(messageID)); return ""; } @@ -149,9 +148,9 @@ QString deleteOneMessage(const CommandContext &ctx) if (msg->loginName == ctx.channel->getName() && !ctx.channel->isBroadcaster()) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "You cannot delete the broadcaster's messages unless " - "you are the broadcaster.")); + "you are the broadcaster."); return ""; } } diff --git a/src/controllers/commands/builtin/twitch/GetModerators.cpp b/src/controllers/commands/builtin/twitch/GetModerators.cpp index 6f1908f03..b3a1bbe18 100644 --- a/src/controllers/commands/builtin/twitch/GetModerators.cpp +++ b/src/controllers/commands/builtin/twitch/GetModerators.cpp @@ -60,8 +60,8 @@ QString getModerators(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /mods command only works in Twitch Channels.")); + ctx.channel->addSystemMessage( + "The /mods command only works in Twitch Channels."); return ""; } @@ -70,8 +70,8 @@ QString getModerators(const CommandContext &ctx) [channel{ctx.channel}, twitchChannel{ctx.twitchChannel}](auto result) { if (result.empty()) { - channel->addMessage(makeSystemMessage( - "This channel does not have any moderators.")); + channel->addSystemMessage( + "This channel does not have any moderators."); return; } @@ -85,7 +85,7 @@ QString getModerators(const CommandContext &ctx) }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatModsError(error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/GetVIPs.cpp b/src/controllers/commands/builtin/twitch/GetVIPs.cpp index 5db9d2eff..94f7d82bb 100644 --- a/src/controllers/commands/builtin/twitch/GetVIPs.cpp +++ b/src/controllers/commands/builtin/twitch/GetVIPs.cpp @@ -8,7 +8,6 @@ #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchMessageBuilder.hpp" -#include "util/Twitch.hpp" namespace { @@ -77,19 +76,19 @@ QString getVIPs(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /vips command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /vips command only works in Twitch channels."); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Due to Twitch restrictions, " // "this command can only be used by the broadcaster. " "To see the list of VIPs you must use the " - "Twitch website.")); + "Twitch website."); return ""; } @@ -99,8 +98,8 @@ QString getVIPs(const CommandContext &ctx) const std::vector &vipList) { if (vipList.empty()) { - channel->addMessage( - makeSystemMessage("This channel does not have any VIPs.")); + channel->addSystemMessage( + "This channel does not have any VIPs."); return; } @@ -115,7 +114,7 @@ QString getVIPs(const CommandContext &ctx) }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatGetVIPsError(error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/Raid.cpp b/src/controllers/commands/builtin/twitch/Raid.cpp index 421ab22f4..3f01f153e 100644 --- a/src/controllers/commands/builtin/twitch/Raid.cpp +++ b/src/controllers/commands/builtin/twitch/Raid.cpp @@ -3,7 +3,6 @@ #include "Application.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -124,24 +123,23 @@ QString startRaid(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /raid command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /raid command only works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage( - makeSystemMessage("Usage: \"/raid \" - Raid a user. " - "Only the broadcaster can start a raid.")); + ctx.channel->addSystemMessage( + "Usage: \"/raid \" - Raid a user. " + "Only the broadcaster can start a raid."); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to start a raid!")); + ctx.channel->addSystemMessage("You must be logged in to start a raid!"); return ""; } @@ -155,19 +153,18 @@ QString startRaid(const CommandContext &ctx) getHelix()->startRaid( twitchChannel->roomId(), targetUser.id, [channel, targetUser] { - channel->addMessage( - makeSystemMessage(QString("You started to raid %1.") - .arg(targetUser.displayName))); + channel->addSystemMessage(QString("You started to raid %1.") + .arg(targetUser.displayName)); }, [channel, targetUser](auto error, auto message) { auto errorMessage = formatStartRaidError(error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); }, [channel{ctx.channel}, target] { // Equivalent error from IRC - channel->addMessage( - makeSystemMessage(QString("Invalid username: %1").arg(target))); + channel->addSystemMessage( + QString("Invalid username: %1").arg(target)); }); return ""; @@ -182,36 +179,35 @@ QString cancelRaid(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /unraid command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /unraid command only works in Twitch channels."); return ""; } if (ctx.words.size() != 1) { - ctx.channel->addMessage( - makeSystemMessage("Usage: \"/unraid\" - Cancel the current raid. " - "Only the broadcaster can cancel the raid.")); + ctx.channel->addSystemMessage( + "Usage: \"/unraid\" - Cancel the current raid. " + "Only the broadcaster can cancel the raid."); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to cancel the raid!")); + ctx.channel->addSystemMessage( + "You must be logged in to cancel the raid!"); return ""; } getHelix()->cancelRaid( ctx.twitchChannel->roomId(), [channel{ctx.channel}] { - channel->addMessage( - makeSystemMessage(QString("You cancelled the raid."))); + channel->addSystemMessage("You cancelled the raid."); }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatCancelRaidError(error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/RemoveModerator.cpp b/src/controllers/commands/builtin/twitch/RemoveModerator.cpp index ba79c4d33..65611ff3e 100644 --- a/src/controllers/commands/builtin/twitch/RemoveModerator.cpp +++ b/src/controllers/commands/builtin/twitch/RemoveModerator.cpp @@ -1,10 +1,8 @@ #include "controllers/commands/builtin/twitch/RemoveModerator.hpp" #include "Application.hpp" -#include "common/Channel.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -22,23 +20,23 @@ QString removeModerator(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /unmod command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /unmod command only works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: \"/unmod \" - Revoke moderator status from a " - "user. Use \"/mods\" to list the moderators of this channel.")); + "user. Use \"/mods\" to list the moderators of this channel."); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to unmod someone!")); + ctx.channel->addSystemMessage( + "You must be logged in to unmod someone!"); return ""; } @@ -52,10 +50,10 @@ QString removeModerator(const CommandContext &ctx) getHelix()->removeChannelModerator( twitchChannel->roomId(), targetUser.id, [channel, targetUser] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("You have removed %1 as a moderator of " "this channel.") - .arg(targetUser.displayName))); + .arg(targetUser.displayName)); }, [channel, targetUser](auto error, auto message) { QString errorMessage = @@ -107,13 +105,13 @@ QString removeModerator(const CommandContext &ctx) } break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); }, [channel{ctx.channel}, target] { // Equivalent error from IRC - channel->addMessage( - makeSystemMessage(QString("Invalid username: %1").arg(target))); + channel->addSystemMessage( + QString("Invalid username: %1").arg(target)); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/RemoveVIP.cpp b/src/controllers/commands/builtin/twitch/RemoveVIP.cpp index 53a1ba2b5..2703418f9 100644 --- a/src/controllers/commands/builtin/twitch/RemoveVIP.cpp +++ b/src/controllers/commands/builtin/twitch/RemoveVIP.cpp @@ -22,23 +22,23 @@ QString removeVIP(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /unvip command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /unvip command only works in Twitch channels."); return ""; } if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( "Usage: \"/unvip \" - Revoke VIP status from a user. " - "Use \"/vips\" to list the VIPs of this channel.")); + "Use \"/vips\" to list the VIPs of this channel."); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to UnVIP someone!")); + ctx.channel->addSystemMessage( + "You must be logged in to UnVIP someone!"); return ""; } @@ -52,9 +52,9 @@ QString removeVIP(const CommandContext &ctx) getHelix()->removeChannelVIP( twitchChannel->roomId(), targetUser.id, [channel, targetUser] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("You have removed %1 as a VIP of this channel.") - .arg(targetUser.displayName))); + .arg(targetUser.displayName)); }, [channel, targetUser](auto error, auto message) { QString errorMessage = QString("Failed to remove VIP - "); @@ -97,13 +97,13 @@ QString removeVIP(const CommandContext &ctx) } break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); }, [channel{ctx.channel}, target] { // Equivalent error from IRC - channel->addMessage( - makeSystemMessage(QString("Invalid username: %1").arg(target))); + channel->addSystemMessage( + QString("Invalid username: %1").arg(target)); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/SendReply.cpp b/src/controllers/commands/builtin/twitch/SendReply.cpp index 381c66b30..80deb0154 100644 --- a/src/controllers/commands/builtin/twitch/SendReply.cpp +++ b/src/controllers/commands/builtin/twitch/SendReply.cpp @@ -1,9 +1,7 @@ #include "controllers/commands/builtin/twitch/SendReply.hpp" -#include "common/Channel.hpp" #include "controllers/commands/CommandContext.hpp" #include "messages/Message.hpp" -#include "messages/MessageBuilder.hpp" #include "messages/MessageThread.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "util/Twitch.hpp" @@ -19,15 +17,14 @@ QString sendReply(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /reply command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /reply command only works in Twitch channels."); return ""; } if (ctx.words.size() < 3) { - ctx.channel->addMessage( - makeSystemMessage("Usage: /reply ")); + ctx.channel->addSystemMessage("Usage: /reply "); return ""; } @@ -54,8 +51,7 @@ QString sendReply(const CommandContext &ctx) } } - ctx.channel->addMessage( - makeSystemMessage("A message from that user wasn't found.")); + ctx.channel->addSystemMessage("A message from that user wasn't found."); return ""; } diff --git a/src/controllers/commands/builtin/twitch/SendWhisper.cpp b/src/controllers/commands/builtin/twitch/SendWhisper.cpp index 1d8046046..694647c8f 100644 --- a/src/controllers/commands/builtin/twitch/SendWhisper.cpp +++ b/src/controllers/commands/builtin/twitch/SendWhisper.cpp @@ -208,16 +208,15 @@ QString sendWhisper(const CommandContext &ctx) if (ctx.words.size() < 3) { - ctx.channel->addMessage( - makeSystemMessage("Usage: /w ")); + ctx.channel->addSystemMessage("Usage: /w "); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to send a whisper!")); + ctx.channel->addSystemMessage( + "You must be logged in to send a whisper!"); return ""; } auto target = ctx.words.at(1); @@ -236,12 +235,11 @@ QString sendWhisper(const CommandContext &ctx) }, [channel, target, targetUser](auto error, auto message) { auto errorMessage = formatWhisperError(error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); }, [channel{ctx.channel}] { - channel->addMessage( - makeSystemMessage("No user matching that username.")); + channel->addSystemMessage("No user matching that username."); }); return ""; } diff --git a/src/controllers/commands/builtin/twitch/ShieldMode.cpp b/src/controllers/commands/builtin/twitch/ShieldMode.cpp index 424a9e31a..1a7bf3a32 100644 --- a/src/controllers/commands/builtin/twitch/ShieldMode.cpp +++ b/src/controllers/commands/builtin/twitch/ShieldMode.cpp @@ -3,7 +3,6 @@ #include "Application.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -17,9 +16,9 @@ QString toggleShieldMode(const CommandContext &ctx, bool isActivating) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( QStringLiteral("The %1 command only works in Twitch channels.") - .arg(command))); + .arg(command)); return {}; } @@ -28,9 +27,9 @@ QString toggleShieldMode(const CommandContext &ctx, bool isActivating) // Avoid Helix calls without Client ID and/or OAuth Token if (user->isAnon()) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( QStringLiteral("You must be logged in to use the %1 command.") - .arg(command))); + .arg(command)); return {}; } @@ -39,13 +38,11 @@ QString toggleShieldMode(const CommandContext &ctx, bool isActivating) [channel = ctx.channel](const auto &res) { if (!res.isActive) { - channel->addMessage( - makeSystemMessage("Shield mode was deactivated.")); + channel->addSystemMessage("Shield mode was deactivated."); return; } - channel->addMessage( - makeSystemMessage("Shield mode was activated.")); + channel->addSystemMessage("Shield mode was activated."); }, [channel = ctx.channel](const auto error, const auto &message) { using Error = HelixUpdateShieldModeError; @@ -78,7 +75,7 @@ QString toggleShieldMode(const CommandContext &ctx, bool isActivating) } break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return {}; diff --git a/src/controllers/commands/builtin/twitch/Shoutout.cpp b/src/controllers/commands/builtin/twitch/Shoutout.cpp index 99c5c50b2..8d9b65617 100644 --- a/src/controllers/commands/builtin/twitch/Shoutout.cpp +++ b/src/controllers/commands/builtin/twitch/Shoutout.cpp @@ -3,7 +3,6 @@ #include "Application.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -19,24 +18,22 @@ QString sendShoutout(const CommandContext &ctx) if (twitchChannel == nullptr) { - channel->addMessage(makeSystemMessage( - "The /shoutout command only works in Twitch channels.")); + channel->addSystemMessage( + "The /shoutout command only works in Twitch channels."); return ""; } auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - channel->addMessage( - makeSystemMessage("You must be logged in to send shoutout.")); + channel->addSystemMessage("You must be logged in to send shoutout."); return ""; } if (words->size() < 2) { - channel->addMessage( - makeSystemMessage("Usage: \"/shoutout \" - Sends a " - "shoutout to the specified twitch user")); + channel->addSystemMessage("Usage: \"/shoutout \" - Sends a " + "shoutout to the specified twitch user"); return ""; } @@ -52,8 +49,8 @@ QString sendShoutout(const CommandContext &ctx) twitchChannel->roomId(), targetUser.id, currentUser->getUserId(), [channel, targetUser]() { - channel->addMessage(makeSystemMessage( - QString("Sent shoutout to %1").arg(targetUser.login))); + channel->addSystemMessage( + QString("Sent shoutout to %1").arg(targetUser.login)); }, [channel](auto error, auto message) { QString errorMessage = "Failed to send shoutout - "; @@ -99,13 +96,13 @@ QString sendShoutout(const CommandContext &ctx) break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); }, [channel, target] { // Equivalent error from IRC - channel->addMessage( - makeSystemMessage(QString("Invalid username: %1").arg(target))); + channel->addSystemMessage( + QString("Invalid username: %1").arg(target)); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/StartCommercial.cpp b/src/controllers/commands/builtin/twitch/StartCommercial.cpp index c582ad58e..f09316416 100644 --- a/src/controllers/commands/builtin/twitch/StartCommercial.cpp +++ b/src/controllers/commands/builtin/twitch/StartCommercial.cpp @@ -1,10 +1,8 @@ #include "controllers/commands/builtin/twitch/StartCommercial.hpp" #include "Application.hpp" -#include "common/Channel.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -83,8 +81,8 @@ QString startCommercial(const CommandContext &ctx) if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage(makeSystemMessage( - "The /commercial command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /commercial command only works in Twitch channels."); return ""; } @@ -96,7 +94,7 @@ QString startCommercial(const CommandContext &ctx) if (ctx.words.size() < 2) { - ctx.channel->addMessage(makeSystemMessage(usageStr)); + ctx.channel->addSystemMessage(usageStr); return ""; } @@ -105,8 +103,8 @@ QString startCommercial(const CommandContext &ctx) // Avoid Helix calls without Client ID and/or OAuth Token if (user->isAnon()) { - ctx.channel->addMessage(makeSystemMessage( - "You must be logged in to use the /commercial command.")); + ctx.channel->addSystemMessage( + "You must be logged in to use the /commercial command."); return ""; } @@ -116,18 +114,18 @@ QString startCommercial(const CommandContext &ctx) getHelix()->startCommercial( broadcasterID, length, [channel{ctx.channel}](auto response) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Starting %1 second long commercial break. " "Keep in mind you are still " "live and not all viewers will receive a " "commercial. " "You may run another commercial in %2 seconds.") .arg(response.length) - .arg(response.retryAfter))); + .arg(response.retryAfter)); }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatStartCommercialError(error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/Unban.cpp b/src/controllers/commands/builtin/twitch/Unban.cpp index f47d70168..950af39b9 100644 --- a/src/controllers/commands/builtin/twitch/Unban.cpp +++ b/src/controllers/commands/builtin/twitch/Unban.cpp @@ -6,7 +6,6 @@ #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" #include "controllers/commands/common/ChannelAction.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" @@ -76,7 +75,7 @@ void unbanUserByID(const ChannelPtr &channel, const QString &channelID, break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); } @@ -96,7 +95,7 @@ QString unbanUser(const CommandContext &ctx) { if (ctx.channel != nullptr) { - ctx.channel->addMessage(makeSystemMessage(actions.error())); + ctx.channel->addSystemMessage(actions.error()); } else { @@ -112,8 +111,8 @@ QString unbanUser(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to unban someone!")); + ctx.channel->addSystemMessage( + "You must be logged in to unban someone!"); return ""; } @@ -159,16 +158,16 @@ QString unbanUser(const CommandContext &ctx) userLoginsToFetch](const auto &users) mutable { if (!actionChannel.hydrateFrom(users)) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to timeout, bad channel name: %1") - .arg(actionChannel.login))); + .arg(actionChannel.login)); return; } if (!actionTarget.hydrateFrom(users)) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to timeout, bad target name: %1") - .arg(actionTarget.login))); + .arg(actionTarget.login)); return; } @@ -177,9 +176,9 @@ QString unbanUser(const CommandContext &ctx) actionTarget.displayName); }, [channel{ctx.channel}, userLoginsToFetch] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to timeout, bad username(s): %1") - .arg(userLoginsToFetch.join(", ")))); + .arg(userLoginsToFetch.join(", "))); }); } else diff --git a/src/controllers/commands/builtin/twitch/UpdateChannel.cpp b/src/controllers/commands/builtin/twitch/UpdateChannel.cpp index bb026bf4d..767f60899 100644 --- a/src/controllers/commands/builtin/twitch/UpdateChannel.cpp +++ b/src/controllers/commands/builtin/twitch/UpdateChannel.cpp @@ -1,9 +1,7 @@ #include "controllers/commands/builtin/twitch/UpdateChannel.hpp" -#include "common/Channel.hpp" #include "common/network/NetworkResult.hpp" #include "controllers/commands/CommandContext.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -70,15 +68,14 @@ QString setTitle(const CommandContext &ctx) if (ctx.words.size() < 2) { - ctx.channel->addMessage( - makeSystemMessage("Usage: /settitle ")); + ctx.channel->addSystemMessage("Usage: /settitle "); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage( - makeSystemMessage("Unable to set title of non-Twitch channel.")); + ctx.channel->addSystemMessage( + "Unable to set title of non-Twitch channel."); return ""; } @@ -89,13 +86,13 @@ QString setTitle(const CommandContext &ctx) [channel{ctx.channel}, title](const auto &result) { (void)result; - channel->addMessage( - makeSystemMessage(QString("Updated title to %1").arg(title))); + channel->addSystemMessage( + QString("Updated title to %1").arg(title)); }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatUpdateChannelError("title", error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; @@ -110,15 +107,14 @@ QString setGame(const CommandContext &ctx) if (ctx.words.size() < 2) { - ctx.channel->addMessage( - makeSystemMessage("Usage: /setgame ")); + ctx.channel->addSystemMessage("Usage: /setgame "); return ""; } if (ctx.twitchChannel == nullptr) { - ctx.channel->addMessage( - makeSystemMessage("Unable to set game of non-Twitch channel.")); + ctx.channel->addSystemMessage( + "Unable to set game of non-Twitch channel."); return ""; } @@ -130,7 +126,7 @@ QString setGame(const CommandContext &ctx) gameName](const std::vector &games) { if (games.empty()) { - channel->addMessage(makeSystemMessage("Game not found.")); + channel->addSystemMessage("Game not found."); return; } @@ -154,17 +150,17 @@ QString setGame(const CommandContext &ctx) getHelix()->updateChannel( twitchChannel->roomId(), matchedGame.id, "", "", [channel, games, matchedGame](const NetworkResult &) { - channel->addMessage(makeSystemMessage( - QString("Updated game to %1").arg(matchedGame.name))); + channel->addSystemMessage( + QString("Updated game to %1").arg(matchedGame.name)); }, [channel](auto error, auto message) { auto errorMessage = formatUpdateChannelError("game", error, message); - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); }, [channel{ctx.channel}] { - channel->addMessage(makeSystemMessage("Failed to look up game.")); + channel->addSystemMessage("Failed to look up game."); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/UpdateColor.cpp b/src/controllers/commands/builtin/twitch/UpdateColor.cpp index 7e48873a2..b0fb8e71f 100644 --- a/src/controllers/commands/builtin/twitch/UpdateColor.cpp +++ b/src/controllers/commands/builtin/twitch/UpdateColor.cpp @@ -21,8 +21,8 @@ QString updateUserColor(const CommandContext &ctx) if (!ctx.channel->isTwitchChannel()) { - ctx.channel->addMessage(makeSystemMessage( - "The /color command only works in Twitch channels.")); + ctx.channel->addSystemMessage( + "The /color command only works in Twitch channels."); return ""; } auto user = getIApp()->getAccounts()->twitch.getCurrent(); @@ -30,8 +30,8 @@ QString updateUserColor(const CommandContext &ctx) // Avoid Helix calls without Client ID and/or OAuth Token if (user->isAnon()) { - ctx.channel->addMessage(makeSystemMessage( - "You must be logged in to use the /color command.")); + ctx.channel->addSystemMessage( + "You must be logged in to use the /color command."); return ""; } @@ -39,11 +39,11 @@ QString updateUserColor(const CommandContext &ctx) if (colorString.isEmpty()) { - ctx.channel->addMessage(makeSystemMessage( + ctx.channel->addSystemMessage( QString("Usage: /color - Color must be one of Twitch's " "supported colors (%1) or a hex code (#000000) if you " "have Turbo or Prime.") - .arg(VALID_HELIX_COLORS.join(", ")))); + .arg(VALID_HELIX_COLORS.join(", "))); return ""; } @@ -54,7 +54,7 @@ QString updateUserColor(const CommandContext &ctx) [colorString, channel{ctx.channel}] { QString successMessage = QString("Your color has been changed to %1.").arg(colorString); - channel->addMessage(makeSystemMessage(successMessage)); + channel->addSystemMessage(successMessage); }, [colorString, channel{ctx.channel}](auto error, auto message) { QString errorMessage = @@ -90,7 +90,7 @@ QString updateUserColor(const CommandContext &ctx) break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); return ""; diff --git a/src/controllers/commands/builtin/twitch/Warn.cpp b/src/controllers/commands/builtin/twitch/Warn.cpp index 30cc54e6f..c36ab681c 100644 --- a/src/controllers/commands/builtin/twitch/Warn.cpp +++ b/src/controllers/commands/builtin/twitch/Warn.cpp @@ -1,14 +1,13 @@ #include "controllers/commands/builtin/twitch/Warn.hpp" #include "Application.hpp" +#include "common/Channel.hpp" #include "common/QLogging.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandContext.hpp" #include "controllers/commands/common/ChannelAction.hpp" -#include "messages/MessageBuilder.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" -#include "providers/twitch/TwitchChannel.hpp" namespace { @@ -73,7 +72,7 @@ void warnUserByID(const ChannelPtr &channel, const QString &channelID, break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); } @@ -92,7 +91,7 @@ QString sendWarn(const CommandContext &ctx) { if (ctx.channel != nullptr) { - ctx.channel->addMessage(makeSystemMessage(actions.error())); + ctx.channel->addSystemMessage(actions.error()); } else { @@ -108,8 +107,7 @@ QString sendWarn(const CommandContext &ctx) auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { - ctx.channel->addMessage( - makeSystemMessage("You must be logged in to warn someone!")); + ctx.channel->addSystemMessage("You must be logged in to warn someone!"); return ""; } @@ -118,8 +116,8 @@ QString sendWarn(const CommandContext &ctx) const auto &reason = action.reason; if (reason.isEmpty()) { - ctx.channel->addMessage( - makeSystemMessage("Failed to warn, you must specify a reason")); + ctx.channel->addSystemMessage( + "Failed to warn, you must specify a reason"); break; } @@ -161,16 +159,16 @@ QString sendWarn(const CommandContext &ctx) userLoginsToFetch](const auto &users) mutable { if (!actionChannel.hydrateFrom(users)) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to warn, bad channel name: %1") - .arg(actionChannel.login))); + .arg(actionChannel.login)); return; } if (!actionTarget.hydrateFrom(users)) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to warn, bad target name: %1") - .arg(actionTarget.login))); + .arg(actionTarget.login)); return; } @@ -179,9 +177,9 @@ QString sendWarn(const CommandContext &ctx) reason, actionTarget.displayName); }, [channel{ctx.channel}, userLoginsToFetch] { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString("Failed to warn, bad username(s): %1") - .arg(userLoginsToFetch.join(", ")))); + .arg(userLoginsToFetch.join(", "))); }); } else diff --git a/src/providers/bttv/BttvEmotes.cpp b/src/providers/bttv/BttvEmotes.cpp index f76417fa1..37cda37b8 100644 --- a/src/providers/bttv/BttvEmotes.cpp +++ b/src/providers/bttv/BttvEmotes.cpp @@ -248,13 +248,12 @@ void BttvEmotes::loadChannel(std::weak_ptr channel, { if (hasEmotes) { - shared->addMessage(makeSystemMessage( - "BetterTTV channel emotes reloaded.")); + shared->addSystemMessage( + "BetterTTV channel emotes reloaded."); } else { - shared->addMessage( - makeSystemMessage(CHANNEL_HAS_NO_EMOTES)); + shared->addSystemMessage(CHANNEL_HAS_NO_EMOTES); } } }) @@ -270,8 +269,7 @@ void BttvEmotes::loadChannel(std::weak_ptr channel, // User does not have any BTTV emotes if (manualRefresh) { - shared->addMessage( - makeSystemMessage(CHANNEL_HAS_NO_EMOTES)); + shared->addSystemMessage(CHANNEL_HAS_NO_EMOTES); } } else @@ -281,10 +279,10 @@ void BttvEmotes::loadChannel(std::weak_ptr channel, qCWarning(chatterinoBttv) << "Error fetching BTTV emotes for channel" << channelId << ", error" << errorString; - shared->addMessage(makeSystemMessage( + shared->addSystemMessage( QStringLiteral("Failed to fetch BetterTTV channel " "emotes. (Error: %1)") - .arg(errorString))); + .arg(errorString)); } }) .execute(); diff --git a/src/providers/ffz/FfzEmotes.cpp b/src/providers/ffz/FfzEmotes.cpp index 8e589e9bd..283f8f4f6 100644 --- a/src/providers/ffz/FfzEmotes.cpp +++ b/src/providers/ffz/FfzEmotes.cpp @@ -287,13 +287,12 @@ void FfzEmotes::loadChannel( { if (hasEmotes) { - shared->addMessage(makeSystemMessage( - "FrankerFaceZ channel emotes reloaded.")); + shared->addSystemMessage( + "FrankerFaceZ channel emotes reloaded."); } else { - shared->addMessage( - makeSystemMessage(CHANNEL_HAS_NO_EMOTES)); + shared->addSystemMessage(CHANNEL_HAS_NO_EMOTES); } } }) @@ -309,8 +308,7 @@ void FfzEmotes::loadChannel( // User does not have any FFZ emotes if (manualRefresh) { - shared->addMessage( - makeSystemMessage(CHANNEL_HAS_NO_EMOTES)); + shared->addSystemMessage(CHANNEL_HAS_NO_EMOTES); } } else @@ -319,10 +317,10 @@ void FfzEmotes::loadChannel( auto errorString = result.formatError(); qCWarning(LOG) << "Error fetching FFZ emotes for channel" << channelID << ", error" << errorString; - shared->addMessage(makeSystemMessage( + shared->addSystemMessage( QStringLiteral("Failed to fetch FrankerFaceZ channel " "emotes. (Error: %1)") - .arg(errorString))); + .arg(errorString)); } }) .execute(); diff --git a/src/providers/irc/IrcChannel2.cpp b/src/providers/irc/IrcChannel2.cpp index 7eeea1c1a..0ab537a73 100644 --- a/src/providers/irc/IrcChannel2.cpp +++ b/src/providers/irc/IrcChannel2.cpp @@ -1,5 +1,6 @@ #include "IrcChannel2.hpp" +#include "common/Channel.hpp" #include "debug/AssertInGuiThread.hpp" #include "messages/Message.hpp" #include "messages/MessageBuilder.hpp" @@ -28,7 +29,7 @@ void IrcChannel::sendMessage(const QString &message) if (message.startsWith("/")) { - int index = message.indexOf(' ', 1); + auto index = message.indexOf(' ', 1); QString command = message.mid(1, index - 1); QString params = index == -1 ? "" : message.mid(index + 1); @@ -73,7 +74,7 @@ void IrcChannel::sendMessage(const QString &message) } else { - this->addMessage(makeSystemMessage("You are not connected.")); + this->addSystemMessage("You are not connected."); } } } diff --git a/src/providers/irc/IrcCommands.cpp b/src/providers/irc/IrcCommands.cpp index 65264663f..3dff08cb6 100644 --- a/src/providers/irc/IrcCommands.cpp +++ b/src/providers/irc/IrcCommands.cpp @@ -27,7 +27,7 @@ Outcome invokeIrcCommand(const QString &commandName, const QString &allParams, if (auto it = staticMessages.find(cmd); it != staticMessages.end()) { - channel.addMessage(makeSystemMessage(it->second)); + channel.addSystemMessage(it->second); return Success; } @@ -57,8 +57,8 @@ Outcome invokeIrcCommand(const QString &commandName, const QString &allParams, { if (params.size() < 2) { - channel.addMessage( - makeSystemMessage("Usage: /kick [message]")); + channel.addSystemMessage( + "Usage: /kick [message]"); return Failure; } const auto &channelParam = params[0]; diff --git a/src/providers/irc/IrcServer.cpp b/src/providers/irc/IrcServer.cpp index c90211fcb..45b073f0e 100644 --- a/src/providers/irc/IrcServer.cpp +++ b/src/providers/irc/IrcServer.cpp @@ -84,10 +84,10 @@ void IrcServer::initializeConnectionSignals(IrcConnection *connection, { if (auto shared = weak.lock()) { - shared->addMessage(makeSystemMessage( + shared->addSystemMessage( QStringLiteral("Socket error: ") + QAbstractSocket::staticMetaObject.enumerator(index) - .valueToKey(error))); + .valueToKey(error)); } } }); @@ -270,7 +270,7 @@ void IrcServer::readConnectionMessageReceived(Communi::IrcMessage *message) { if (message->nick() == this->data_->nick) { - shared->addMessage(makeSystemMessage("joined")); + shared->addSystemMessage("joined"); } else { @@ -295,7 +295,7 @@ void IrcServer::readConnectionMessageReceived(Communi::IrcMessage *message) { if (message->nick() == this->data_->nick) { - shared->addMessage(makeSystemMessage("parted")); + shared->addSystemMessage("parted"); } else { diff --git a/src/providers/recentmessages/Api.cpp b/src/providers/recentmessages/Api.cpp index 88d456515..e1b0945b6 100644 --- a/src/providers/recentmessages/Api.cpp +++ b/src/providers/recentmessages/Api.cpp @@ -68,9 +68,9 @@ void load( if (errorCode == "channel_not_joined" && !messages.empty()) { - shared->addMessage(makeSystemMessage( + shared->addSystemMessage( "Message history service recovering, there may " - "be gaps in the message history.")); + "be gaps in the message history."); } } @@ -87,10 +87,10 @@ void load( qCDebug(LOG) << "Failed to load recent messages for" << shared->getName(); - shared->addMessage(makeSystemMessage( + shared->addSystemMessage( QStringLiteral( "Message history service unavailable (Error: %1)") - .arg(result.formatError()))); + .arg(result.formatError())); onError(); }) diff --git a/src/providers/seventv/SeventvEmotes.cpp b/src/providers/seventv/SeventvEmotes.cpp index f66d99e28..ae9376c01 100644 --- a/src/providers/seventv/SeventvEmotes.cpp +++ b/src/providers/seventv/SeventvEmotes.cpp @@ -289,13 +289,11 @@ void SeventvEmotes::loadChannelEmotes( { if (hasEmotes) { - shared->addMessage( - makeSystemMessage("7TV channel emotes reloaded.")); + shared->addSystemMessage("7TV channel emotes reloaded."); } else { - shared->addMessage( - makeSystemMessage(CHANNEL_HAS_NO_EMOTES)); + shared->addSystemMessage(CHANNEL_HAS_NO_EMOTES); } } }, @@ -312,8 +310,7 @@ void SeventvEmotes::loadChannelEmotes( << result.parseJson(); if (manualRefresh) { - shared->addMessage( - makeSystemMessage(CHANNEL_HAS_NO_EMOTES)); + shared->addSystemMessage(CHANNEL_HAS_NO_EMOTES); } } else @@ -323,10 +320,10 @@ void SeventvEmotes::loadChannelEmotes( qCWarning(chatterinoSeventv) << "Error fetching 7TV emotes for channel" << channelId << ", error" << errorString; - shared->addMessage(makeSystemMessage( + shared->addSystemMessage( QStringLiteral("Failed to fetch 7TV channel " "emotes. (Error: %1)") - .arg(errorString))); + .arg(errorString)); } }); } diff --git a/src/providers/twitch/IrcMessageHandler.cpp b/src/providers/twitch/IrcMessageHandler.cpp index 4657438ad..d42325262 100644 --- a/src/providers/twitch/IrcMessageHandler.cpp +++ b/src/providers/twitch/IrcMessageHandler.cpp @@ -1,6 +1,7 @@ #include "providers/twitch/IrcMessageHandler.hpp" #include "Application.hpp" +#include "common/Channel.hpp" #include "common/Common.hpp" #include "common/Literals.hpp" #include "common/QLogging.hpp" @@ -1136,15 +1137,15 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message) QString tags = message->tags().value("msg-id").toString(); if (tags == "usage_delete") { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( "Usage: /delete - Deletes the specified message. " - "Can't take more than one argument.")); + "Can't take more than one argument."); } else if (tags == "bad_delete_message_error") { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( "There was a problem deleting the message. " - "It might be from another channel or too old to delete.")); + "It might be from another channel or too old to delete."); } else if (tags == "host_on" || tags == "host_target_went_offline") { @@ -1218,7 +1219,7 @@ void IrcMessageHandler::handleJoinMessage(Communi::IrcMessage *message) if (message->nick() == getIApp()->getAccounts()->twitch.getCurrent()->getUserName()) { - twitchChannel->addMessage(makeSystemMessage("joined channel")); + twitchChannel->addSystemMessage("joined channel"); twitchChannel->joined.invoke(); } else if (getSettings()->showJoins.getValue()) diff --git a/src/providers/twitch/TwitchAccount.cpp b/src/providers/twitch/TwitchAccount.cpp index 8b531156f..0fed7548d 100644 --- a/src/providers/twitch/TwitchAccount.cpp +++ b/src/providers/twitch/TwitchAccount.cpp @@ -362,8 +362,8 @@ void TwitchAccount::loadUserstateEmotes(std::weak_ptr weakChannel) if (auto channel = weakChannel.lock(); channel != nullptr) { - channel->addMessage(makeSystemMessage( - "Twitch subscriber emotes reloaded.")); + channel->addSystemMessage( + "Twitch subscriber emotes reloaded."); } }, [] { @@ -427,7 +427,7 @@ void TwitchAccount::autoModAllow(const QString msgID, ChannelPtr channel) break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); } @@ -473,7 +473,7 @@ void TwitchAccount::autoModDeny(const QString msgID, ChannelPtr channel) break; } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); }); } diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index bb982c8fe..4216dfd26 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -2,7 +2,6 @@ #include "Application.hpp" #include "common/Common.hpp" -#include "common/Env.hpp" #include "common/network/NetworkRequest.hpp" #include "common/network/NetworkResult.hpp" #include "common/QLogging.hpp" @@ -217,7 +216,7 @@ TwitchChannel::TwitchChannel(const QString &name) // debugging #if 0 for (int i = 0; i < 1000; i++) { - this->addMessage(makeSystemMessage("asef")); + this->addSystemMessage("asef"); } #endif } @@ -1012,9 +1011,9 @@ void TwitchChannel::updateSeventvUser( if (auto shared = weak.lock()) { this->seventvEmotes_.set(EMPTY_EMOTE_MAP); - this->addMessage(makeSystemMessage( + this->addSystemMessage( QString("Failed updating 7TV emote set (%1).") - .arg(reason))); + .arg(reason)); } }); }); @@ -1512,7 +1511,7 @@ void TwitchChannel::refreshBadges() break; } - this->addMessage(makeSystemMessage(errorMessage)); + this->addSystemMessage(errorMessage); }); } @@ -1600,8 +1599,8 @@ void TwitchChannel::createClip() { if (!this->isLive()) { - this->addMessage(makeSystemMessage( - "Cannot create clip while the channel is offline!")); + this->addSystemMessage( + "Cannot create clip while the channel is offline!"); return; } @@ -1616,7 +1615,7 @@ void TwitchChannel::createClip() return; } - this->addMessage(makeSystemMessage("Creating clip...")); + this->addSystemMessage("Creating clip..."); this->isClipCreationInProgress = true; getHelix()->createClip( diff --git a/src/providers/twitch/TwitchIrcServer.cpp b/src/providers/twitch/TwitchIrcServer.cpp index 7012cdb21..28d4ad4b4 100644 --- a/src/providers/twitch/TwitchIrcServer.cpp +++ b/src/providers/twitch/TwitchIrcServer.cpp @@ -42,8 +42,8 @@ void sendHelixMessage(const std::shared_ptr &channel, auto broadcasterID = channel->roomId(); if (broadcasterID.isEmpty()) { - channel->addMessage(makeSystemMessage( - "Sending messages in this channel isn't possible.")); + channel->addSystemMessage( + "Sending messages in this channel isn't possible."); return; } @@ -67,14 +67,14 @@ void sendHelixMessage(const std::shared_ptr &channel, return; } - auto errorMessage = [&] { - if (res.dropReason) - { - return makeSystemMessage(res.dropReason->message); - } - return makeSystemMessage("Your message was not sent."); - }(); - chan->addMessage(errorMessage); + if (res.dropReason) + { + chan->addSystemMessage(res.dropReason->message); + } + else + { + chan->addSystemMessage("Your message was not sent."); + } }, [weak = std::weak_ptr(channel)](auto error, auto message) { auto chan = weak.lock(); @@ -112,7 +112,7 @@ void sendHelixMessage(const std::shared_ptr &channel, return "Unknown error: " + message; } }(); - chan->addMessage(makeSystemMessage(errorMessage)); + chan->addSystemMessage(errorMessage); }); } @@ -390,14 +390,13 @@ std::shared_ptr TwitchIrcServer::getCustomChannel( { for (auto i = 0; i < 1000; i++) { - channel->addMessage(makeSystemMessage(QString::number(i + 1))); + channel->addSystemMessage(QString::number(i + 1)); } } auto *timer = new QTimer; QObject::connect(timer, &QTimer::timeout, [channel] { - channel->addMessage( - makeSystemMessage(QTime::currentTime().toString())); + channel->addSystemMessage(QTime::currentTime().toString()); }); timer->start(msBetweenMessages); return timer; @@ -562,10 +561,7 @@ bool TwitchIrcServer::prepareToSend( { if (this->lastErrorTimeSpeed_ + 30s < now) { - auto errorMessage = - makeSystemMessage("You are sending messages too quickly."); - - channel->addMessage(errorMessage); + channel->addSystemMessage("You are sending messages too quickly."); this->lastErrorTimeSpeed_ = now; } @@ -583,10 +579,7 @@ bool TwitchIrcServer::prepareToSend( { if (this->lastErrorTimeAmount_ + 30s < now) { - auto errorMessage = - makeSystemMessage("You are sending too many messages."); - - channel->addMessage(errorMessage); + channel->addSystemMessage("You are sending too many messages."); this->lastErrorTimeAmount_ = now; } diff --git a/src/singletons/ImageUploader.cpp b/src/singletons/ImageUploader.cpp index 3926df8f5..f0b920464 100644 --- a/src/singletons/ImageUploader.cpp +++ b/src/singletons/ImageUploader.cpp @@ -64,8 +64,8 @@ void ImageUploader::logToFile(const QString &originalFilePath, logReadFile.open(QIODevice::ReadWrite | QIODevice::Text); if (!isLogFileOkay) { - channel->addMessage(makeSystemMessage( - QString("Failed to open log file with links at ") + logFileName)); + channel->addSystemMessage( + QString("Failed to open log file with links at ") + logFileName); return; } auto logs = logReadFile.readAll(); @@ -197,7 +197,7 @@ void ImageUploader::handleFailedUpload(const NetworkResult &result, } } - channel->addMessage(makeSystemMessage(errorMessage)); + channel->addSystemMessage(errorMessage); // NOTE: We abort any future uploads on failure. Should this be handled differently? while (!this->uploadQueue_.empty()) { @@ -376,8 +376,7 @@ void ImageUploader::upload(std::queue images, ChannelPtr channel, BenchmarkGuard benchmarkGuard("upload"); if (!this->uploadMutex_.tryLock()) { - channel->addMessage(makeSystemMessage( - QString("Please wait until the upload finishes."))); + channel->addSystemMessage("Please wait until the upload finishes."); return; } @@ -386,7 +385,7 @@ void ImageUploader::upload(std::queue images, ChannelPtr channel, std::swap(this->uploadQueue_, images); - channel->addMessage(makeSystemMessage("Started upload...")); + channel->addSystemMessage("Started upload..."); this->sendImageUploadRequest(this->uploadQueue_.front(), std::move(channel), std::move(outputTextEdit)); diff --git a/src/util/StreamLink.cpp b/src/util/StreamLink.cpp index 06452c496..a3596f9b4 100644 --- a/src/util/StreamLink.cpp +++ b/src/util/StreamLink.cpp @@ -194,8 +194,8 @@ void openStreamlinkForChannel(const QString &channel) auto *currentSplit = currentPage->getSelectedSplit(); if (currentSplit != nullptr) { - currentSplit->getChannel()->addMessage( - makeSystemMessage(INFO_TEMPLATE.arg(channel))); + currentSplit->getChannel()->addSystemMessage( + INFO_TEMPLATE.arg(channel)); } } diff --git a/src/widgets/dialogs/NotificationPopup.cpp b/src/widgets/dialogs/NotificationPopup.cpp deleted file mode 100644 index 5e8d7360b..000000000 --- a/src/widgets/dialogs/NotificationPopup.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "NotificationPopup.hpp" - -#include "common/Channel.hpp" -#include "messages/Message.hpp" -#include "widgets/helper/ChannelView.hpp" - -#include -#include -#include - -namespace chatterino { - -NotificationPopup::NotificationPopup() - : BaseWindow({BaseWindow::Frameless, BaseWindow::DisableLayoutSave}) - , channel_(std::make_shared("notifications", Channel::Type::None)) - -{ - this->channelView_ = new ChannelView(this); - - auto *layout = new QVBoxLayout(this); - this->setLayout(layout); - - layout->addWidget(this->channelView_); - - this->channelView_->setChannel(this->channel_); - this->setScaleIndependantSize(300, 150); -} - -void NotificationPopup::updatePosition() -{ - Location location = BottomRight; - - const QRect rect = QGuiApplication::primaryScreen()->availableGeometry(); - - switch (location) - { - case BottomRight: { - this->move(rect.right() - this->width(), - rect.bottom() - this->height()); - } - break; - } -} - -void NotificationPopup::addMessage(MessagePtr msg) -{ - this->channel_->addMessage(std::move(msg)); - - // QTimer::singleShot(5000, this, [this, msg] { this->channel->remove }); -} - -} // namespace chatterino diff --git a/src/widgets/dialogs/NotificationPopup.hpp b/src/widgets/dialogs/NotificationPopup.hpp deleted file mode 100644 index f2787a786..000000000 --- a/src/widgets/dialogs/NotificationPopup.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "widgets/BaseWindow.hpp" - -namespace chatterino { - -class ChannelView; - -class Channel; -using ChannelPtr = std::shared_ptr; - -struct Message; -using MessagePtr = std::shared_ptr; - -class NotificationPopup : public BaseWindow -{ -public: - enum Location { TopLeft, TopRight, BottomLeft, BottomRight }; - NotificationPopup(); - - void addMessage(MessagePtr msg); - void updatePosition(); - -private: - ChannelView *channelView_; - ChannelPtr channel_; -}; - -} // namespace chatterino diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index d519cdcfc..683cba271 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -620,17 +620,17 @@ void UserInfoPopup::installEvents() getIApp()->getAccounts()->twitch.getCurrent()->unblockUser( this->userId_, this, [this, reenableBlockCheckbox, currentUser] { - this->channel_->addMessage(makeSystemMessage( + this->channel_->addSystemMessage( QString("You successfully unblocked user %1") - .arg(this->userName_))); + .arg(this->userName_)); reenableBlockCheckbox(); }, [this, reenableBlockCheckbox] { - this->channel_->addMessage(makeSystemMessage( + this->channel_->addSystemMessage( QString( "User %1 couldn't be unblocked, an unknown " "error occurred!") - .arg(this->userName_))); + .arg(this->userName_)); reenableBlockCheckbox(); }); } @@ -647,17 +647,17 @@ void UserInfoPopup::installEvents() getIApp()->getAccounts()->twitch.getCurrent()->blockUser( this->userId_, this, [this, reenableBlockCheckbox, currentUser] { - this->channel_->addMessage(makeSystemMessage( + this->channel_->addSystemMessage( QString("You successfully blocked user %1") - .arg(this->userName_))); + .arg(this->userName_)); reenableBlockCheckbox(); }, [this, reenableBlockCheckbox] { - this->channel_->addMessage(makeSystemMessage( + this->channel_->addSystemMessage( QString( "User %1 couldn't be blocked, an unknown " "error occurred!") - .arg(this->userName_))); + .arg(this->userName_)); reenableBlockCheckbox(); }); } diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index 2be5bff57..36c6888d4 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -393,10 +393,10 @@ Split::Split(QWidget *parent) imageUploader->getImages(original); if (images.empty()) { - channel->addMessage(makeSystemMessage( + channel->addSystemMessage( QString( "An error occurred trying to process your image: %1") - .arg(imageProcessError))); + .arg(imageProcessError)); return; } From 126200da823242acec6797636ed618bbba5f69fa Mon Sep 17 00:00:00 2001 From: nerix Date: Tue, 9 Jul 2024 16:18:35 +0200 Subject: [PATCH 07/63] show running qt version if it differs from compiled version (#5501) --- CHANGELOG.md | 1 + src/CMakeLists.txt | 4 ++++ src/common/Version.cpp | 18 ++++++++++++++---- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97cf0796f..83d7c8940 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ - Dev: Refactor/unsingletonize `UserDataController`. (#5459) - Dev: Cleanup `BrowserExtension`. (#5465) - Dev: Deprecate Qt 5.12. (#5396) +- Dev: The running Qt version is now shown in the about page if it differs from the compiled version. (#5501) ## 2.5.1 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7728acdf6..849397b7d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -947,6 +947,10 @@ set_target_properties(${LIBRARY_PROJECT} # this is its own project. set(VERSION_SOURCE_FILES common/Version.cpp common/Version.hpp) add_library(${VERSION_PROJECT} STATIC ${VERSION_SOURCE_FILES}) +target_compile_definitions(${VERSION_PROJECT} PRIVATE + $<$:USEWINSDK> + $<$:CHATTERINO_WITH_CRASHPAD> +) # source group for IDEs source_group(TREE ${CMAKE_SOURCE_DIR} FILES ${VERSION_SOURCE_FILES}) diff --git a/src/common/Version.cpp b/src/common/Version.cpp index 76ef549a0..5e23272cb 100644 --- a/src/common/Version.cpp +++ b/src/common/Version.cpp @@ -1,11 +1,15 @@ #include "common/Version.hpp" +#include "common/Literals.hpp" #include "common/Modes.hpp" #include +#include namespace chatterino { +using namespace literals; + Version::Version() : version_(CHATTERINO_VERSION) , commitHash_(QStringLiteral(CHATTERINO_GIT_HASH)) @@ -79,11 +83,17 @@ QStringList Version::buildTags() const { QStringList tags; - tags.append("Qt " QT_VERSION_STR); + const auto *runtimeVersion = qVersion(); + if (runtimeVersion != QLatin1String{QT_VERSION_STR}) + { + tags.append(u"Qt "_s QT_VERSION_STR u" (running on " % runtimeVersion % + u")"); + } + else + { + tags.append(u"Qt "_s QT_VERSION_STR); + } -#ifdef USEWINSDK - tags.append("Windows SDK"); -#endif #ifdef _MSC_FULL_VER tags.append("MSVC " + QString::number(_MSC_FULL_VER, 10)); #endif From e2c3823a142483ad5c6f98fdf2df39f4081ec5b9 Mon Sep 17 00:00:00 2001 From: teknsl <64030674+teknsl@users.noreply.github.com> Date: Thu, 11 Jul 2024 12:42:20 +0200 Subject: [PATCH 08/63] Support more firefox variants for incognito link opening (#5503) --- CHANGELOG.md | 1 + src/util/IncognitoBrowser.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83d7c8940..467c2810e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Minor: Added `/warn ` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474) - Minor: Improve appearance of reply button. (#5491) - Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) +- Minor: Support more Firefox variants for incognito link opening. (#5503) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) - Bugfix: Fixed restricted users usernames not being clickable. (#5405) diff --git a/src/util/IncognitoBrowser.cpp b/src/util/IncognitoBrowser.cpp index 77f14160a..3d147b6f7 100644 --- a/src/util/IncognitoBrowser.cpp +++ b/src/util/IncognitoBrowser.cpp @@ -30,6 +30,10 @@ QString getPrivateSwitch(const QString &browserExecutable) {"firefox-esr", "-private-window"}, {"chromium", "-incognito"}, {"brave", "-incognito"}, + {"firefox-devedition", "-private-window"}, + {"firefox-developer-edition", "-private-window"}, + {"firefox-beta", "-private-window"}, + {"firefox-nightly", "-private-window"}, }; // compare case-insensitively From 49de421bd84396bef05ee1b6d2d9ca6ee488faa0 Mon Sep 17 00:00:00 2001 From: Mm2PL Date: Sat, 13 Jul 2024 11:21:27 +0200 Subject: [PATCH 09/63] Fixed splits staying paused after unfocusing Chatterino in certain configurations (#5504) --- CHANGELOG.md | 1 + src/widgets/Window.cpp | 7 +++++++ src/widgets/splits/Split.cpp | 7 +++++++ src/widgets/splits/Split.hpp | 3 +++ 4 files changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 467c2810e..e7674de6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - Bugfix: Fixed a crash when tab completing while having an invalid plugin loaded. (#5401) - Bugfix: Fixed windows on Windows not saving correctly when snapping them to the edges. (#5478) - Bugfix: Fixed `/clearmessages` not working with more than one window. (#5489) +- Bugfix: Fixed splits staying paused after unfocusing Chatterino in certain configurations. (#5504) - Dev: Update Windows build from Qt 6.5.0 to Qt 6.7.1. (#5420) - Dev: Update vcpkg build Qt from 6.5.0 to 6.7.0, boost from 1.83.0 to 1.85.0, openssl from 3.1.3 to 3.3.0. (#5422) - Dev: Unsingletonize `ISoundController`. (#5462) diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index a1a646c4b..f7df6bcb0 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,12 @@ bool Window::event(QEvent *event) } case QEvent::WindowDeactivate: { + for (const auto &split : + this->notebook_->getSelectedPage()->getSplits()) + { + split->unpause(); + } + auto *page = this->notebook_->getSelectedPage(); if (page != nullptr) diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index 36c6888d4..9d4ff5ed4 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -1599,6 +1599,13 @@ void Split::setInputReply(const MessagePtr &reply) this->input_->setReply(reply); } +void Split::unpause() +{ + this->view_->unpause(PauseReason::KeyboardModifier); + this->view_->unpause(PauseReason::DoubleClick); + // Mouse intentionally left out, we may still have the mouse over the split +} + } // namespace chatterino QDebug operator<<(QDebug dbg, const chatterino::Split &split) diff --git a/src/widgets/splits/Split.hpp b/src/widgets/splits/Split.hpp index bc98de5e7..ab6322d5c 100644 --- a/src/widgets/splits/Split.hpp +++ b/src/widgets/splits/Split.hpp @@ -77,6 +77,9 @@ public: void setInputReply(const MessagePtr &reply); + // This is called on window focus lost + void unpause(); + static pajlada::Signals::Signal modifierStatusChanged; static Qt::KeyboardModifiers modifierStatus; From 973b7a3bdd1231f44b997731b59b1785e7d3671c Mon Sep 17 00:00:00 2001 From: pajlada Date: Sat, 13 Jul 2024 13:15:11 +0200 Subject: [PATCH 10/63] Add extra context to messages that are added to channels, allowing the logging controller to take more responsibility in what messages to log (#5499) Co-auhtored-by: James Upjohn --- CHANGELOG.md | 1 + src/Application.cpp | 38 +++++++++------- src/common/Channel.cpp | 45 ++++++++----------- src/common/Channel.hpp | 11 ++++- src/common/ChannelChatters.cpp | 6 ++- .../commands/builtin/chatterino/Debugging.cpp | 2 +- .../commands/builtin/twitch/Chatters.cpp | 2 +- .../commands/builtin/twitch/GetModerators.cpp | 2 +- .../commands/builtin/twitch/GetVIPs.cpp | 2 +- .../commands/builtin/twitch/SendWhisper.cpp | 10 ++--- .../notifications/NotificationController.cpp | 3 +- src/controllers/plugins/PluginController.cpp | 4 +- src/controllers/plugins/api/ChannelRef.cpp | 2 +- src/providers/irc/AbstractIrcServer.cpp | 6 +-- src/providers/irc/IrcChannel2.cpp | 14 +++++- src/providers/irc/IrcChannel2.hpp | 2 +- src/providers/irc/IrcServer.cpp | 14 +++--- src/providers/twitch/IrcMessageHandler.cpp | 33 ++++++++------ src/providers/twitch/TwitchChannel.cpp | 23 +++++----- src/singletons/ImageUploader.cpp | 2 +- src/singletons/Logging.cpp | 1 + src/widgets/dialogs/EmotePopup.cpp | 18 ++++---- src/widgets/dialogs/ReplyThreadPopup.cpp | 29 ++++++------ src/widgets/dialogs/UserInfoPopup.cpp | 7 +-- src/widgets/helper/ChannelView.cpp | 23 ++++------ src/widgets/helper/SearchPopup.cpp | 2 +- 26 files changed, 163 insertions(+), 139 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7674de6d..25dc4e7ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - Bugfix: Fixed message history occasionally not loading after a sleep. (#5457) - Bugfix: Fixed a crash when tab completing while having an invalid plugin loaded. (#5401) - Bugfix: Fixed windows on Windows not saving correctly when snapping them to the edges. (#5478) +- Bugfix: Fixed user info card popups adding duplicate line to log files. (#5499) - Bugfix: Fixed `/clearmessages` not working with more than one window. (#5489) - Bugfix: Fixed splits staying paused after unfocusing Chatterino in certain configurations. (#5504) - Dev: Update Windows build from Qt 6.5.0 to Qt 6.7.1. (#5420) diff --git a/src/Application.cpp b/src/Application.cpp index cf4e6f07a..2c97b8fd2 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -664,7 +664,7 @@ void Application::initPubSub() postToThread([chan, action] { MessageBuilder msg(action); msg->flags.set(MessageFlag::PubSub); - chan->addMessage(msg.release()); + chan->addMessage(msg.release(), MessageContext::Original); }); }); @@ -703,7 +703,7 @@ void Application::initPubSub() } if (!replaced) { - chan->addMessage(msg); + chan->addMessage(msg, MessageContext::Original); } }); }); @@ -720,7 +720,7 @@ void Application::initPubSub() auto msg = MessageBuilder(action).release(); postToThread([chan, msg] { - chan->addMessage(msg); + chan->addMessage(msg, MessageContext::Original); }); }); @@ -770,8 +770,10 @@ void Application::initPubSub() TwitchMessageBuilder::makeLowTrustUserMessage( action, twitchChannel->getName(), twitchChannel.get()); - twitchChannel->addMessage(p.first); - twitchChannel->addMessage(p.second); + twitchChannel->addMessage(p.first, + MessageContext::Original); + twitchChannel->addMessage(p.second, + MessageContext::Original); }); }); @@ -809,7 +811,7 @@ void Application::initPubSub() postToThread([chan, action] { auto msg = TwitchMessageBuilder::makeLowTrustUpdateMessage(action); - chan->addMessage(msg); + chan->addMessage(msg, MessageContext::Original); }); }); @@ -891,28 +893,32 @@ void Application::initPubSub() const auto p = TwitchMessageBuilder::makeAutomodMessage( action, chan->getName()); - chan->addMessage(p.first); - chan->addMessage(p.second); + chan->addMessage(p.first, MessageContext::Original); + chan->addMessage(p.second, + MessageContext::Original); getIApp() ->getTwitch() ->getAutomodChannel() - ->addMessage(p.first); + ->addMessage(p.first, MessageContext::Original); getIApp() ->getTwitch() ->getAutomodChannel() - ->addMessage(p.second); + ->addMessage(p.second, + MessageContext::Original); if (getSettings()->showAutomodInMentions) { getIApp() ->getTwitch() ->getMentionsChannel() - ->addMessage(p.first); + ->addMessage(p.first, + MessageContext::Original); getIApp() ->getTwitch() ->getMentionsChannel() - ->addMessage(p.second); + ->addMessage(p.second, + MessageContext::Original); } }); } @@ -939,8 +945,8 @@ void Application::initPubSub() postToThread([chan, action] { const auto p = TwitchMessageBuilder::makeAutomodMessage( action, chan->getName()); - chan->addMessage(p.first); - chan->addMessage(p.second); + chan->addMessage(p.first, MessageContext::Original); + chan->addMessage(p.second, MessageContext::Original); }); }); @@ -961,7 +967,7 @@ void Application::initPubSub() auto msg = MessageBuilder(action).release(); postToThread([chan, msg] { - chan->addMessage(msg); + chan->addMessage(msg, MessageContext::Original); }); chan->deleteMessage(msg->id); }); @@ -978,7 +984,7 @@ void Application::initPubSub() postToThread([chan, action] { const auto p = TwitchMessageBuilder::makeAutomodInfoMessage(action); - chan->addMessage(p); + chan->addMessage(p, MessageContext::Original); }); }); diff --git a/src/common/Channel.cpp b/src/common/Channel.cpp index 38d4014aa..afdc99c0b 100644 --- a/src/common/Channel.cpp +++ b/src/common/Channel.cpp @@ -32,6 +32,12 @@ Channel::Channel(const QString &name, Type type) , messages_(getSettings()->scrollbackSplitLimit) , type_(type) { + if (this->isTwitchChannel()) + { + this->platform_ = "twitch"; + } + + // Irc platform is set through IrcChannel2 ctor } Channel::~Channel() @@ -79,37 +85,24 @@ LimitedQueueSnapshot Channel::getMessageSnapshot() return this->messages_.getSnapshot(); } -void Channel::addMessage(MessagePtr message, +void Channel::addMessage(MessagePtr message, MessageContext context, std::optional overridingFlags) { MessagePtr deleted; - if (!overridingFlags || !overridingFlags->has(MessageFlag::DoNotLog)) + if (context == MessageContext::Original) { - QString channelPlatform("other"); - if (this->type_ == Type::Irc) + // Only log original messages + auto isDoNotLogSet = + (overridingFlags && overridingFlags->has(MessageFlag::DoNotLog)) || + message->flags.has(MessageFlag::DoNotLog); + + if (!isDoNotLogSet) { - auto *irc = dynamic_cast(this); - if (irc != nullptr) - { - auto *ircServer = irc->server(); - if (ircServer != nullptr) - { - channelPlatform = QString("irc-%1").arg( - irc->server()->userFriendlyIdentifier()); - } - else - { - channelPlatform = "irc-unknown"; - } - } + // Only log messages where the `DoNotLog` flag is not set + getIApp()->getChatLogger()->addMessage(this->name_, message, + this->platform_); } - else if (this->isTwitchChannel()) - { - channelPlatform = "twitch"; - } - getIApp()->getChatLogger()->addMessage(this->name_, message, - channelPlatform); } if (this->messages_.pushBack(message, deleted)) @@ -123,7 +116,7 @@ void Channel::addMessage(MessagePtr message, void Channel::addSystemMessage(const QString &contents) { auto msg = makeSystemMessage(contents); - this->addMessage(msg); + this->addMessage(msg, MessageContext::Original); } void Channel::addOrReplaceTimeout(MessagePtr message) @@ -134,7 +127,7 @@ void Channel::addOrReplaceTimeout(MessagePtr message) this->replaceMessage(msg, replacement); }, [this](auto msg) { - this->addMessage(msg); + this->addMessage(msg, MessageContext::Original); }, true); diff --git a/src/common/Channel.hpp b/src/common/Channel.hpp index aaea98621..ad4af5114 100644 --- a/src/common/Channel.hpp +++ b/src/common/Channel.hpp @@ -28,6 +28,14 @@ enum class TimeoutStackStyle : int { Default = DontStackBeyondUserMessage, }; +/// Context of the message being added to a channel +enum class MessageContext { + /// This message is the original + Original, + /// This message is a repost of a message that has already been added in a channel + Repost, +}; + class Channel : public std::enable_shared_from_this { public: @@ -79,7 +87,7 @@ public: // overridingFlags can be filled in with flags that should be used instead // of the message's flags. This is useful in case a flag is specific to a // type of split - void addMessage(MessagePtr message, + void addMessage(MessagePtr message, MessageContext context, std::optional overridingFlags = std::nullopt); void addMessagesAtStart(const std::vector &messages_); @@ -120,6 +128,7 @@ public: protected: virtual void onConnected(); virtual void messageRemovedFromStart(const MessagePtr &msg); + QString platform_{"other"}; private: const QString name_; diff --git a/src/common/ChannelChatters.cpp b/src/common/ChannelChatters.cpp index d65ae931b..3bb785a0a 100644 --- a/src/common/ChannelChatters.cpp +++ b/src/common/ChannelChatters.cpp @@ -43,7 +43,8 @@ void ChannelChatters::addJoinedUser(const QString &user) TwitchMessageBuilder::listOfUsersSystemMessage( "Users joined:", *joinedUsers, &this->channel_, &builder); builder->flags.set(MessageFlag::Collapsed); - this->channel_.addMessage(builder.release()); + this->channel_.addMessage(builder.release(), + MessageContext::Original); joinedUsers->clear(); this->joinedUsersMergeQueued_ = false; @@ -68,7 +69,8 @@ void ChannelChatters::addPartedUser(const QString &user) TwitchMessageBuilder::listOfUsersSystemMessage( "Users parted:", *partedUsers, &this->channel_, &builder); builder->flags.set(MessageFlag::Collapsed); - this->channel_.addMessage(builder.release()); + this->channel_.addMessage(builder.release(), + MessageContext::Original); partedUsers->clear(); this->partedUsersMergeQueued_ = false; diff --git a/src/controllers/commands/builtin/chatterino/Debugging.cpp b/src/controllers/commands/builtin/chatterino/Debugging.cpp index 52ec87967..1097143a3 100644 --- a/src/controllers/commands/builtin/chatterino/Debugging.cpp +++ b/src/controllers/commands/builtin/chatterino/Debugging.cpp @@ -90,7 +90,7 @@ QString listEnvironmentVariables(const CommandContext &ctx) builder.emplace(QTime::currentTime()); builder.emplace(str, MessageElementFlag::Text, MessageColor::System); - channel->addMessage(builder.release()); + channel->addMessage(builder.release(), MessageContext::Original); } return ""; } diff --git a/src/controllers/commands/builtin/twitch/Chatters.cpp b/src/controllers/commands/builtin/twitch/Chatters.cpp index 0daa75086..602da9cc9 100644 --- a/src/controllers/commands/builtin/twitch/Chatters.cpp +++ b/src/controllers/commands/builtin/twitch/Chatters.cpp @@ -129,7 +129,7 @@ QString testChatters(const CommandContext &ctx) TwitchMessageBuilder::listOfUsersSystemMessage( prefix, entries, twitchChannel, &builder); - channel->addMessage(builder.release()); + channel->addMessage(builder.release(), MessageContext::Original); }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatChattersError(error, message); diff --git a/src/controllers/commands/builtin/twitch/GetModerators.cpp b/src/controllers/commands/builtin/twitch/GetModerators.cpp index b3a1bbe18..8a70f8fa6 100644 --- a/src/controllers/commands/builtin/twitch/GetModerators.cpp +++ b/src/controllers/commands/builtin/twitch/GetModerators.cpp @@ -81,7 +81,7 @@ QString getModerators(const CommandContext &ctx) TwitchMessageBuilder::listOfUsersSystemMessage( "The moderators of this channel are", result, twitchChannel, &builder); - channel->addMessage(builder.release()); + channel->addMessage(builder.release(), MessageContext::Original); }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatModsError(error, message); diff --git a/src/controllers/commands/builtin/twitch/GetVIPs.cpp b/src/controllers/commands/builtin/twitch/GetVIPs.cpp index 94f7d82bb..3b6b98e01 100644 --- a/src/controllers/commands/builtin/twitch/GetVIPs.cpp +++ b/src/controllers/commands/builtin/twitch/GetVIPs.cpp @@ -110,7 +110,7 @@ QString getVIPs(const CommandContext &ctx) TwitchMessageBuilder::listOfUsersSystemMessage( messagePrefix, vipList, twitchChannel, &builder); - channel->addMessage(builder.release()); + channel->addMessage(builder.release(), MessageContext::Original); }, [channel{ctx.channel}](auto error, auto message) { auto errorMessage = formatGetVIPsError(error, message); diff --git a/src/controllers/commands/builtin/twitch/SendWhisper.cpp b/src/controllers/commands/builtin/twitch/SendWhisper.cpp index 694647c8f..aa30e2f15 100644 --- a/src/controllers/commands/builtin/twitch/SendWhisper.cpp +++ b/src/controllers/commands/builtin/twitch/SendWhisper.cpp @@ -177,18 +177,16 @@ bool appendWhisperMessageWordsLocally(const QStringList &words) b->flags.set(MessageFlag::Whisper); auto messagexD = b.release(); - getIApp()->getTwitch()->getWhispersChannel()->addMessage(messagexD); - - auto overrideFlags = std::optional(messagexD->flags); - overrideFlags->set(MessageFlag::DoNotLog); + getIApp()->getTwitch()->getWhispersChannel()->addMessage( + messagexD, MessageContext::Original); if (getSettings()->inlineWhispers && !(getSettings()->streamerModeSuppressInlineWhispers && getIApp()->getStreamerMode()->isEnabled())) { app->getTwitchAbstract()->forEachChannel( - [&messagexD, overrideFlags](ChannelPtr _channel) { - _channel->addMessage(messagexD, overrideFlags); + [&messagexD](ChannelPtr _channel) { + _channel->addMessage(messagexD, MessageContext::Repost); }); } diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index cfab7242f..1e30a7497 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -202,7 +202,8 @@ void NotificationController::checkStream(bool live, QString channelName) } MessageBuilder builder; TwitchMessageBuilder::liveMessage(channelName, &builder); - getIApp()->getTwitch()->getLiveChannel()->addMessage(builder.release()); + getIApp()->getTwitch()->getLiveChannel()->addMessage( + builder.release(), MessageContext::Original); // Indicate that we have pushed notifications for this stream fakeTwitchChannels.push_back(channelName); diff --git a/src/controllers/plugins/PluginController.cpp b/src/controllers/plugins/PluginController.cpp index 2fa2865f4..64e2a96b0 100644 --- a/src/controllers/plugins/PluginController.cpp +++ b/src/controllers/plugins/PluginController.cpp @@ -380,8 +380,8 @@ QString PluginController::tryExecPluginCommand(const QString &commandName, auto res = lua_pcall(L, 1, 0, 0); if (res != LUA_OK) { - ctx.channel->addMessage(makeSystemMessage( - "Lua error: " + lua::humanErrorText(L, res))); + ctx.channel->addSystemMessage("Lua error: " + + lua::humanErrorText(L, res)); return ""; } return ""; diff --git a/src/controllers/plugins/api/ChannelRef.cpp b/src/controllers/plugins/api/ChannelRef.cpp index 1e592d0db..64b146f55 100644 --- a/src/controllers/plugins/api/ChannelRef.cpp +++ b/src/controllers/plugins/api/ChannelRef.cpp @@ -200,7 +200,7 @@ int ChannelRef::add_system_message(lua_State *L) } ChannelPtr that = ChannelRef::getOrError(L); text = text.replace('\n', ' '); - that->addMessage(makeSystemMessage(text)); + that->addSystemMessage(text); return 0; } diff --git a/src/providers/irc/AbstractIrcServer.cpp b/src/providers/irc/AbstractIrcServer.cpp index 5880f2f6a..948a2962d 100644 --- a/src/providers/irc/AbstractIrcServer.cpp +++ b/src/providers/irc/AbstractIrcServer.cpp @@ -156,7 +156,7 @@ void AbstractIrcServer::addGlobalSystemMessage(const QString &messageText) continue; } - chan->addMessage(message); + chan->addMessage(message, MessageContext::Original); } } @@ -329,7 +329,7 @@ void AbstractIrcServer::onReadConnected(IrcConnection *connection) } else { - chan->addMessage(connectedMsg); + chan->addMessage(connectedMsg, MessageContext::Original); } } @@ -357,7 +357,7 @@ void AbstractIrcServer::onDisconnected() continue; } - chan->addMessage(disconnectedMsg); + chan->addMessage(disconnectedMsg, MessageContext::Original); if (auto *channel = dynamic_cast(chan.get())) { diff --git a/src/providers/irc/IrcChannel2.cpp b/src/providers/irc/IrcChannel2.cpp index 0ab537a73..2a2a3be93 100644 --- a/src/providers/irc/IrcChannel2.cpp +++ b/src/providers/irc/IrcChannel2.cpp @@ -17,6 +17,16 @@ IrcChannel::IrcChannel(const QString &name, IrcServer *server) , ChannelChatters(*static_cast(this)) , server_(server) { + auto *ircServer = this->server(); + if (ircServer != nullptr) + { + this->platform_ = + QString("irc-%1").arg(ircServer->userFriendlyIdentifier()); + } + else + { + this->platform_ = "irc-unknown"; + } } void IrcChannel::sendMessage(const QString &message) @@ -70,7 +80,7 @@ void IrcChannel::sendMessage(const QString &message) builder.message().messageText = message; builder.message().searchText = username + ": " + message; - this->addMessage(builder.release()); + this->addMessage(builder.release(), MessageContext::Original); } else { @@ -79,7 +89,7 @@ void IrcChannel::sendMessage(const QString &message) } } -IrcServer *IrcChannel::server() +IrcServer *IrcChannel::server() const { assertInGuiThread(); diff --git a/src/providers/irc/IrcChannel2.hpp b/src/providers/irc/IrcChannel2.hpp index 3e26200dc..75ff40ea4 100644 --- a/src/providers/irc/IrcChannel2.hpp +++ b/src/providers/irc/IrcChannel2.hpp @@ -16,7 +16,7 @@ public: void sendMessage(const QString &message) override; // server may be nullptr - IrcServer *server(); + IrcServer *server() const; // Channel methods bool canReconnect() const override; diff --git a/src/providers/irc/IrcServer.cpp b/src/providers/irc/IrcServer.cpp index 45b073f0e..24b8c39e1 100644 --- a/src/providers/irc/IrcServer.cpp +++ b/src/providers/irc/IrcServer.cpp @@ -111,7 +111,8 @@ void IrcServer::initializeConnectionSignals(IrcConnection *connection, { if (auto shared = weak.lock()) { - shared->addMessage(msg); + shared->addMessage(msg, + MessageContext::Original); } } }); @@ -218,7 +219,7 @@ void IrcServer::privateMessageReceived(Communi::IrcPrivateMessage *message) { if (auto shared = weak.lock()) { - shared->addMessage(msg); + shared->addMessage(msg, MessageContext::Original); } } return; @@ -236,7 +237,7 @@ void IrcServer::privateMessageReceived(Communi::IrcPrivateMessage *message) { auto msg = builder.build(); - channel->addMessage(msg); + channel->addMessage(msg, MessageContext::Original); builder.triggerHighlights(); const auto highlighted = msg->flags.has(MessageFlag::Highlighted); const auto showInMentions = @@ -244,7 +245,8 @@ void IrcServer::privateMessageReceived(Communi::IrcPrivateMessage *message) if (highlighted && showInMentions) { - getIApp()->getTwitch()->getMentionsChannel()->addMessage(msg); + getIApp()->getTwitch()->getMentionsChannel()->addMessage( + msg, MessageContext::Original); } } else @@ -332,7 +334,7 @@ void IrcServer::readConnectionMessageReceived(Communi::IrcMessage *message) { if (auto shared = weak.lock()) { - shared->addMessage(msg); + shared->addMessage(msg, MessageContext::Original); } } }; @@ -366,7 +368,7 @@ void IrcServer::sendWhisper(const QString &target, const QString &message) { if (auto shared = weak.lock()) { - shared->addMessage(msg); + shared->addMessage(msg, MessageContext::Original); } } } diff --git a/src/providers/twitch/IrcMessageHandler.cpp b/src/providers/twitch/IrcMessageHandler.cpp index d42325262..74bc00035 100644 --- a/src/providers/twitch/IrcMessageHandler.cpp +++ b/src/providers/twitch/IrcMessageHandler.cpp @@ -721,7 +721,7 @@ void IrcMessageHandler::handlePrivMessage(Communi::IrcPrivateMessage *message, auto ptr = TwitchMessageBuilder::buildHypeChatMessage(message); if (ptr) { - chan->addMessage(ptr); + chan->addMessage(ptr, MessageContext::Original); } } } @@ -812,7 +812,8 @@ void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message) if (clearChat.disableAllMessages) { chan->disableAllMessages(); - chan->addMessage(std::move(clearChat.message)); + chan->addMessage(std::move(clearChat.message), + MessageContext::Original); return; } @@ -868,7 +869,7 @@ void IrcMessageHandler::handleClearMessageMessage(Communi::IrcMessage *message) { MessageBuilder builder; TwitchMessageBuilder::deletionMessage(msg, &builder); - chan->addMessage(builder.release()); + chan->addMessage(builder.release(), MessageContext::Original); } } @@ -966,10 +967,11 @@ void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *ircMessage) if (message->flags.has(MessageFlag::ShowInMentions)) { - getIApp()->getTwitch()->getMentionsChannel()->addMessage(message); + getIApp()->getTwitch()->getMentionsChannel()->addMessage( + message, MessageContext::Original); } - c->addMessage(message); + c->addMessage(message, MessageContext::Original); auto overrideFlags = std::optional(message->flags); overrideFlags->set(MessageFlag::DoNotTriggerNotification); @@ -981,7 +983,8 @@ void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *ircMessage) { getIApp()->getTwitchAbstract()->forEachChannel( [&message, overrideFlags](ChannelPtr channel) { - channel->addMessage(message, overrideFlags); + channel->addMessage(message, MessageContext::Repost, + overrideFlags); }); } } @@ -1098,7 +1101,7 @@ void IrcMessageHandler::handleUserNoticeMessage( if (!chan->isEmpty()) { - chan->addMessage(newMessage); + chan->addMessage(newMessage, MessageContext::Original); } } } @@ -1117,7 +1120,7 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message) // channels getIApp()->getTwitch()->forEachChannelAndSpecialChannels( [msg](const auto &c) { - c->addMessage(msg); + c->addMessage(msg, MessageContext::Original); }); return; @@ -1167,7 +1170,7 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message) MessageBuilder builder; TwitchMessageBuilder::hostingSystemMessage(hostedChannelName, &builder, hostOn); - channel->addMessage(builder.release()); + channel->addMessage(builder.release(), MessageContext::Original); } else if (tags == "room_mods" || tags == "vips_success") { @@ -1196,11 +1199,11 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message) users.sort(Qt::CaseInsensitive); TwitchMessageBuilder::listOfUsersSystemMessage(msgParts.at(0), users, tc, &builder); - channel->addMessage(builder.release()); + channel->addMessage(builder.release(), MessageContext::Original); } else { - channel->addMessage(msg); + channel->addMessage(msg, MessageContext::Original); } } } @@ -1249,7 +1252,8 @@ void IrcMessageHandler::handlePartMessage(Communi::IrcMessage *message) if (message->nick() == selfAccountName) { - channel->addMessage(generateBannedMessage(false)); + channel->addMessage(generateBannedMessage(false), + MessageContext::Original); } } @@ -1460,10 +1464,11 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *message, if (highlighted && showInMentions) { - server.getMentionsChannel()->addMessage(msg); + server.getMentionsChannel()->addMessage(msg, + MessageContext::Original); } - chan->addMessage(msg); + chan->addMessage(msg, MessageContext::Original); if (auto *chatters = dynamic_cast(chan.get())) { chatters->addRecentChatter(msg->displayName); diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 4216dfd26..f57081c86 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -161,7 +161,7 @@ TwitchChannel::TwitchChannel(const QString &name) TwitchMessageBuilder::liveSystemMessage(this->getDisplayName(), &builder); builder.message().id = this->roomId(); - this->addMessage(builder.release()); + this->addMessage(builder.release(), MessageContext::Original); // Message in /live channel MessageBuilder builder2; @@ -169,7 +169,7 @@ TwitchChannel::TwitchChannel(const QString &name) &builder2); builder2.message().id = this->roomId(); getIApp()->getTwitch()->getLiveChannel()->addMessage( - builder2.release()); + builder2.release(), MessageContext::Original); // Notify on all channels with a ping sound if (getSettings()->notificationOnAnyChannel && @@ -187,7 +187,7 @@ TwitchChannel::TwitchChannel(const QString &name) MessageBuilder builder; TwitchMessageBuilder::offlineSystemMessage(this->getDisplayName(), &builder); - this->addMessage(builder.release()); + this->addMessage(builder.release(), MessageContext::Original); // "delete" old 'CHANNEL is live' message LimitedQueueSnapshot snapshot = @@ -395,7 +395,7 @@ void TwitchChannel::addChannelPointReward(const ChannelPointReward &reward) MessageBuilder builder; TwitchMessageBuilder::appendChannelPointRewardMessage( reward, &builder, this->isMod(), this->isBroadcaster()); - this->addMessage(builder.release()); + this->addMessage(builder.release(), MessageContext::Original); return; } @@ -566,7 +566,7 @@ void TwitchChannel::showLoginMessage() linkColor) ->setLink(accountsLink); - this->addMessage(builder.release()); + this->addMessage(builder.release(), MessageContext::Original); } void TwitchChannel::roomIdChanged() @@ -925,7 +925,7 @@ void TwitchChannel::updateBttvEmote( auto builder = MessageBuilder(liveUpdatesUpdateEmoteMessage, "BTTV", QString() /* actor */, newEmote->name.string, oldEmote->name.string); - this->addMessage(builder.release()); + this->addMessage(builder.release(), MessageContext::Original); } void TwitchChannel::removeBttvEmote( @@ -964,7 +964,7 @@ void TwitchChannel::updateSeventvEmote( auto builder = MessageBuilder(liveUpdatesUpdateEmoteMessage, "7TV", dispatch.actorName, dispatch.emoteName, dispatch.oldEmoteName); - this->addMessage(builder.release()); + this->addMessage(builder.release(), MessageContext::Original); } void TwitchChannel::removeSeventvEmote( @@ -1002,7 +1002,8 @@ void TwitchChannel::updateSeventvUser( auto builder = MessageBuilder(liveUpdatesUpdateEmoteSetMessage, "7TV", dispatch.actorName, name); - this->addMessage(builder.release()); + this->addMessage(builder.release(), + MessageContext::Original); } }); }, @@ -1085,7 +1086,7 @@ void TwitchChannel::addOrReplaceLiveUpdatesAddRemove(bool isEmoteAdd, this->lastLiveUpdateEmotePlatform_ = platform; this->lastLiveUpdateMessage_ = msg; this->lastLiveUpdateEmoteActor_ = actor; - this->addMessage(msg); + this->addMessage(msg, MessageContext::Original); } bool TwitchChannel::tryReplaceLastLiveUpdateAddOrRemove( @@ -1650,7 +1651,7 @@ void TwitchChannel::createClip() MessageColor::Link) ->setLink(Link(Link::Url, clip.editUrl)); - this->addMessage(builder.release()); + this->addMessage(builder.release(), MessageContext::Original); }, // failureCallback [this](auto error) { @@ -1699,7 +1700,7 @@ void TwitchChannel::createClip() builder.message().messageText = text; builder.message().searchText = text; - this->addMessage(builder.release()); + this->addMessage(builder.release(), MessageContext::Original); }, // finallyCallback - this will always execute, so clip creation won't ever be stuck [this] { diff --git a/src/singletons/ImageUploader.cpp b/src/singletons/ImageUploader.cpp index f0b920464..b6a191e85 100644 --- a/src/singletons/ImageUploader.cpp +++ b/src/singletons/ImageUploader.cpp @@ -239,7 +239,7 @@ void ImageUploader::handleSuccessfulUpload(const NetworkResult &result, auto timeToUpload = this->uploadQueue_.size() * (UPLOAD_DELAY / 1000 + 1); MessageBuilder builder(imageUploaderResultMessage, link, deletionLink, this->uploadQueue_.size(), timeToUpload); - channel->addMessage(builder.release()); + channel->addMessage(builder.release(), MessageContext::Original); if (this->uploadQueue_.empty()) { this->uploadMutex_.unlock(); diff --git a/src/singletons/Logging.cpp b/src/singletons/Logging.cpp index 8ea65289c..d8bb57127 100644 --- a/src/singletons/Logging.cpp +++ b/src/singletons/Logging.cpp @@ -1,5 +1,6 @@ #include "singletons/Logging.hpp" +#include "messages/Message.hpp" #include "singletons/helper/LoggingChannel.hpp" #include "singletons/Paths.hpp" #include "singletons/Settings.hpp" diff --git a/src/widgets/dialogs/EmotePopup.cpp b/src/widgets/dialogs/EmotePopup.cpp index 989233ff7..d771008ca 100644 --- a/src/widgets/dialogs/EmotePopup.cpp +++ b/src/widgets/dialogs/EmotePopup.cpp @@ -145,7 +145,7 @@ void addTwitchEmoteSets( auto currentChannelPair = mapOfSets[currentChannelName]; for (const auto &message : currentChannelPair.second) { - subChannel.addMessage(message); + subChannel.addMessage(message, MessageContext::Original); } mapOfSets.remove(currentChannelName); @@ -154,7 +154,7 @@ void addTwitchEmoteSets( auto &channel = pair.first ? globalChannel : subChannel; for (const auto &message : pair.second) { - channel.addMessage(message); + channel.addMessage(message, MessageContext::Original); } } } @@ -162,14 +162,16 @@ void addTwitchEmoteSets( void addEmotes(Channel &channel, const EmoteMap &map, const QString &title, const MessageElementFlag &emoteFlag) { - channel.addMessage(makeTitleMessage(title)); - channel.addMessage(makeEmoteMessage(map, emoteFlag)); + channel.addMessage(makeTitleMessage(title), MessageContext::Original); + channel.addMessage(makeEmoteMessage(map, emoteFlag), + MessageContext::Original); } void loadEmojis(ChannelView &view, const std::vector &emojiMap) { ChannelPtr emojiChannel(new Channel("", Channel::Type::None)); - emojiChannel->addMessage(makeEmojiMessage(emojiMap)); + emojiChannel->addMessage(makeEmojiMessage(emojiMap), + MessageContext::Original); view.setChannel(emojiChannel); } @@ -177,8 +179,8 @@ void loadEmojis(ChannelView &view, const std::vector &emojiMap) void loadEmojis(Channel &channel, const std::vector &emojiMap, const QString &title) { - channel.addMessage(makeTitleMessage(title)); - channel.addMessage(makeEmojiMessage(emojiMap)); + channel.addMessage(makeTitleMessage(title), MessageContext::Original); + channel.addMessage(makeEmojiMessage(emojiMap), MessageContext::Original); } // Create an emote @@ -454,7 +456,7 @@ void EmotePopup::loadChannel(ChannelPtr channel) builder.emplace("no subscription emotes available", MessageElementFlag::Text, MessageColor::System); - subChannel->addMessage(builder.release()); + subChannel->addMessage(builder.release(), MessageContext::Original); } } diff --git a/src/widgets/dialogs/ReplyThreadPopup.cpp b/src/widgets/dialogs/ReplyThreadPopup.cpp index 4d3dd3a83..fb35e9818 100644 --- a/src/widgets/dialogs/ReplyThreadPopup.cpp +++ b/src/widgets/dialogs/ReplyThreadPopup.cpp @@ -244,7 +244,8 @@ void ReplyThreadPopup::addMessagesFromThread() std::optional(this->thread_->root()->flags); rootOverrideFlags->set(MessageFlag::DoNotLog); - this->virtualChannel_->addMessage(this->thread_->root(), rootOverrideFlags); + this->virtualChannel_->addMessage( + this->thread_->root(), MessageContext::Repost, rootOverrideFlags); for (const auto &msgRef : this->thread_->replies()) { if (auto msg = msgRef.lock()) @@ -252,24 +253,26 @@ void ReplyThreadPopup::addMessagesFromThread() auto overrideFlags = std::optional(msg->flags); overrideFlags->set(MessageFlag::DoNotLog); - this->virtualChannel_->addMessage(msg, overrideFlags); + this->virtualChannel_->addMessage(msg, MessageContext::Repost, + overrideFlags); } } this->messageConnection_ = std::make_unique( - sourceChannel->messageAppended.connect([this](MessagePtr &message, - auto) { - if (message->replyThread == this->thread_) - { - auto overrideFlags = - std::optional(message->flags); - overrideFlags->set(MessageFlag::DoNotLog); + sourceChannel->messageAppended.connect( + [this](MessagePtr &message, auto) { + if (message->replyThread == this->thread_) + { + auto overrideFlags = + std::optional(message->flags); + overrideFlags->set(MessageFlag::DoNotLog); - // same reply thread, add message - this->virtualChannel_->addMessage(message, overrideFlags); - } - })); + // same reply thread, add message + this->virtualChannel_->addMessage( + message, MessageContext::Repost, overrideFlags); + } + })); } void ReplyThreadPopup::updateInputUI() diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index 683cba271..afd28d4fb 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -112,12 +112,9 @@ namespace { { MessagePtr message = snapshot[i]; - auto overrideFlags = std::optional(message->flags); - overrideFlags->set(MessageFlag::DoNotLog); - if (checkMessageUserName(userName, message)) { - channelPtr->addMessage(message, overrideFlags); + channelPtr->addMessage(message, MessageContext::Repost); } } @@ -787,7 +784,7 @@ void UserInfoPopup::updateLatestMessages() { // display message in ChannelView this->ui_.latestMessages->channel()->addMessage( - message); + message, MessageContext::Repost); } else { diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 00469e0a9..26e31c9bf 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -925,26 +925,17 @@ void ChannelView::setChannel(const ChannelPtr &underlyingChannel) { if (this->channel_->lastDate_ != QDate::currentDate()) { + // Day change message this->channel_->lastDate_ = QDate::currentDate(); auto msg = makeSystemMessage( QLocale().toString(QDate::currentDate(), QLocale::LongFormat), QTime(0, 0)); - this->channel_->addMessage(msg); + msg->flags.set(MessageFlag::DoNotLog); + this->channel_->addMessage(msg, MessageContext::Original); } - // When the message was received in the underlyingChannel, - // logging will be handled. Prevent duplications. - if (overridingFlags) - { - overridingFlags->set(MessageFlag::DoNotLog); - } - else - { - overridingFlags = MessageFlags(message->flags); - overridingFlags->set(MessageFlag::DoNotLog); - } - - this->channel_->addMessage(message, overridingFlags); + this->channel_->addMessage(message, MessageContext::Repost, + overridingFlags); } }); @@ -1010,7 +1001,9 @@ void ChannelView::setChannel(const ChannelPtr &underlyingChannel) } this->messages_.pushBack(messageLayout); - this->channel_->addMessage(msg); + + this->channel_->addMessage(msg, MessageContext::Repost); + nMessagesAdded++; if (this->showScrollbarHighlights()) { diff --git a/src/widgets/helper/SearchPopup.cpp b/src/widgets/helper/SearchPopup.cpp index 1f7347626..fb8dfee8b 100644 --- a/src/widgets/helper/SearchPopup.cpp +++ b/src/widgets/helper/SearchPopup.cpp @@ -55,7 +55,7 @@ ChannelPtr SearchPopup::filter(const QString &text, const QString &channelName, auto overrideFlags = std::optional(message->flags); overrideFlags->set(MessageFlag::DoNotLog); - channel->addMessage(message, overrideFlags); + channel->addMessage(message, MessageContext::Repost, overrideFlags); } } From b9f669d3a5816a935016f96d97c2cf9e9722a4f0 Mon Sep 17 00:00:00 2001 From: nerix Date: Sun, 14 Jul 2024 11:17:42 +0200 Subject: [PATCH 11/63] feat: strip prefixes and suffixes in links (#5486) --- CHANGELOG.md | 1 + benchmarks/src/LinkParser.cpp | 15 +-- src/common/LinkParser.cpp | 80 +++++++++--- src/common/LinkParser.hpp | 121 +++++++++++++++--- .../commands/builtin/twitch/SendWhisper.cpp | 6 +- src/messages/MessageBuilder.cpp | 51 +++++--- src/messages/MessageBuilder.hpp | 6 +- src/messages/search/LinkPredicate.cpp | 2 +- src/providers/twitch/TwitchMessageBuilder.cpp | 6 +- tests/src/LinkParser.cpp | 84 ++++++++++-- 10 files changed, 282 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25dc4e7ec..0b162187a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Minor: Improve appearance of reply button. (#5491) - Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) - Minor: Support more Firefox variants for incognito link opening. (#5503) +- Minor: Links can now have prefixes and suffixes such as parentheses. (#5486) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) - Bugfix: Fixed restricted users usernames not being clickable. (#5405) diff --git a/benchmarks/src/LinkParser.cpp b/benchmarks/src/LinkParser.cpp index 3a3312428..b38e15de3 100644 --- a/benchmarks/src/LinkParser.cpp +++ b/benchmarks/src/LinkParser.cpp @@ -5,8 +5,6 @@ #include #include -#include - using namespace chatterino; const QString INPUT = QStringLiteral( @@ -14,8 +12,9 @@ const QString INPUT = QStringLiteral( "(or 2.4.2 if its out) " "https://github.com/Chatterino/chatterino2/releases/tag/nightly-build " "AlienPls https://www.youtube.com/watch?v=ELBBiBDcWc0 " - "127.0.3 aaaa xd 256.256.256.256 AsdQwe xd 127.0.0.1 https://. https://.be " - "https://a http://a.b https://a.be ftp://xdd.com " + "127.0.3 aaaa xd 256.256.256.256 AsdQwe xd 127.0.0.1 https://. " + "*https://.be " + "https://a: http://a.b (https://a.be) ftp://xdd.com " "this is a text lol . ://foo.com //aa.de :/foo.de xd.XDDDDDD "); static void BM_LinkParsing(benchmark::State &state) @@ -24,15 +23,15 @@ static void BM_LinkParsing(benchmark::State &state) // Make sure the TLDs are loaded { - benchmark::DoNotOptimize(LinkParser("xd.com").result()); + benchmark::DoNotOptimize(linkparser::parse("xd.com")); } for (auto _ : state) { - for (auto word : words) + for (const auto &word : words) { - LinkParser parser(word); - benchmark::DoNotOptimize(parser.result()); + auto parsed = linkparser::parse(word); + benchmark::DoNotOptimize(parsed); } } } diff --git a/src/common/LinkParser.cpp b/src/common/LinkParser.cpp index d64abed31..ecc8fb751 100644 --- a/src/common/LinkParser.cpp +++ b/src/common/LinkParser.cpp @@ -113,19 +113,58 @@ bool startsWithPort(QStringView string) return true; } +/// @brief Strips ignored characters off @a source +/// +/// As per https://github.github.com/gfm/#autolinks-extension-: +/// +/// '<', '*', '_', '~', and '(' are ignored at the beginning +/// '>', '?', '!', '.', ',', ':', '*', '~', and ')' are ignored at the end +/// +/// A difference to GFM is that the source isn't scanned for parentheses and '_' +/// isn't a valid suffix. +void strip(QStringView &source) +{ + while (!source.isEmpty()) + { + auto c = source.first(); + if (c == u'<' || c == u'*' || c == u'_' || c == u'~' || c == u'(') + { + source = source.mid(1); + continue; + } + break; + } + + while (!source.isEmpty()) + { + auto c = source.last(); + if (c == u'>' || c == u'?' || c == u'!' || c == u'.' || c == u',' || + c == u':' || c == u'*' || c == u'~' || c == u')') + { + source.chop(1); + continue; + } + break; + } +} + } // namespace -namespace chatterino { +namespace chatterino::linkparser { -LinkParser::LinkParser(const QString &unparsedString) +std::optional parse(const QString &source) noexcept { - ParsedLink result; + std::optional result; // This is not implemented with a regex to increase performance. - QStringView remaining(unparsedString); - QStringView protocol(remaining); + + QStringView link{source}; + strip(link); + + QStringView remaining = link; + QStringView protocol; // Check protocol for https?:// - if (remaining.startsWith(QStringLiteral("http"), Qt::CaseInsensitive) && + if (remaining.startsWith(u"http", Qt::CaseInsensitive) && remaining.length() >= 4 + 3 + 1) // 'http' + '://' + [any] { // optimistic view assuming there's a protocol (http or https) @@ -136,11 +175,11 @@ LinkParser::LinkParser(const QString &unparsedString) withProto = withProto.mid(1); } - if (withProto.startsWith(QStringLiteral("://"))) + if (withProto.startsWith(u"://")) { // there's really a protocol => consume it remaining = withProto.mid(3); - result.protocol = {protocol.begin(), remaining.begin()}; + protocol = {link.begin(), remaining.begin()}; } } @@ -161,7 +200,7 @@ LinkParser::LinkParser(const QString &unparsedString) { if (lastWasDot) // no double dots .. { - return; + return result; } lastDotPos = i; lastWasDot = true; @@ -181,7 +220,7 @@ LinkParser::LinkParser(const QString &unparsedString) if (!startsWithPort(remaining)) { - return; + return result; } break; @@ -198,23 +237,22 @@ LinkParser::LinkParser(const QString &unparsedString) if (lastWasDot || lastDotPos <= 0) { - return; + return result; } // check host/tld if ((nDots == 3 && isValidIpv4(host)) || isValidTld(host.mid(lastDotPos + 1))) { - result.host = host; - result.rest = rest; - result.source = unparsedString; - this->result_ = std::move(result); + result = Parsed{ + .protocol = protocol, + .host = host, + .rest = rest, + .link = link, + }; } + + return result; } -const std::optional &LinkParser::result() const -{ - return this->result_; -} - -} // namespace chatterino +} // namespace chatterino::linkparser diff --git a/src/common/LinkParser.hpp b/src/common/LinkParser.hpp index 2ef118318..12976b25d 100644 --- a/src/common/LinkParser.hpp +++ b/src/common/LinkParser.hpp @@ -4,43 +4,126 @@ #include -namespace chatterino { +namespace chatterino::linkparser { -struct ParsedLink { +/// @brief Represents a parsed link +/// +/// A parsed link is represented as views over the source string for its +/// different segments. In this simplified model, a link consists of an optional +/// @a protocol, a mandatory @a host and an optional @a rest. These segments are +/// always next to eachother in the input string, however together, they don't +/// span the whole input as it could contain prefixes or suffixes. +/// +/// Prefixes and suffixes are almost identical to the ones in GitHub Flavored +/// Markdown (GFM - https://github.github.com/gfm/#autolinks-extension-). +/// The main differences are that '_' isn't a valid suffix and parentheses +/// aren't counted (e.g. "(a.com/(foo)! would result in "a.com/(foo"). +/// Matching is done case insensitive (e.g. "HTTp://a.com" would be valid). +/// +/// A @a protocol can either be empty, "http://", or "https://". +/// A @a host can either be an IPv4 address or a hostname. The hostname must end +/// in a valid top level domain. Otherwise, there are no restrictions on it. +/// The @a rest can start with an optional port followed by either a '/', '?', +/// or '#'. +/// +/// @b Example +/// +/// ```text +/// (https://wiki.chatterino.com/Help/#overview) +/// ▏▏proto ▕ host ▏ rest ▏▏ +/// ▏▏ link ▏▏ +/// ▏ source ▏ +/// ``` +struct Parsed { /// The parsed protocol of the link. Can be empty. /// + /// ```text /// https://www.forsen.tv/commands - /// ^------^ + /// ▏╌╌╌╌╌╌▕ + /// + /// www.forsen.tv/commands + /// (empty) + /// ``` QStringView protocol; /// The parsed host of the link. Can not be empty. /// + /// ```text /// https://www.forsen.tv/commands - /// ^-----------^ + /// ▏╌╌╌╌╌╌╌╌╌╌╌▕ + /// ``` QStringView host; /// The remainder of the link. Can be empty. /// + /// ```text /// https://www.forsen.tv/commands - /// ^-------^ + /// ▏╌╌╌╌╌╌╌▕ + /// + /// https://www.forsen.tv + /// (empty) + /// ``` QStringView rest; - /// The original unparsed link. + /// The matched link. Can not be empty. + /// + /// ```text + /// (https://www.forsen.tv/commands) + /// ▏╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌▕ + /// ``` + QStringView link; + + /// Checks if the parsed link contains a prefix + bool hasPrefix(const QString &source) const noexcept + { + return this->link.begin() != source.begin(); + } + + /// The prefix before the parsed link inside @a source. May be empty. + /// + /// ```text + /// (https://www.forsen.tv/commands) + /// ^ /// /// https://www.forsen.tv/commands - /// ^----------------------------^ - QString source; + /// (empty) + /// ``` + QStringView prefix(const QString &source) const noexcept + { + return {source.data(), this->link.begin()}; + } + + /// Checks if the parsed link contains a suffix + bool hasSuffix(const QString &source) const noexcept + { + return this->link.end() != source.end(); + } + + /// The suffix after the parsed link inside @a source. May be empty. + /// + /// ```text + /// (https://www.forsen.tv/commands) + /// ^ + /// + /// https://www.forsen.tv/commands + /// (empty) + /// ``` + QStringView suffix(const QString &source) const noexcept + { + return { + this->link.begin() + this->link.size(), + source.data() + source.length(), + }; + } }; -class LinkParser -{ -public: - explicit LinkParser(const QString &unparsedString); +/// @brief Parses a link from @a source into its segments +/// +/// If no link is contained in @a source, `std::nullopt` will be returned. +/// The returned value is valid as long as @a source exists, as it contains +/// views into @a source. +/// +/// For the accepted links, see Parsed. +std::optional parse(const QString &source) noexcept; - const std::optional &result() const; - -private: - std::optional result_{}; -}; - -} // namespace chatterino +} // namespace chatterino::linkparser diff --git a/src/controllers/commands/builtin/twitch/SendWhisper.cpp b/src/controllers/commands/builtin/twitch/SendWhisper.cpp index aa30e2f15..483f72853 100644 --- a/src/controllers/commands/builtin/twitch/SendWhisper.cpp +++ b/src/controllers/commands/builtin/twitch/SendWhisper.cpp @@ -152,10 +152,10 @@ bool appendWhisperMessageWordsLocally(const QStringList &words) void operator()(const QString &string, MessageBuilder &b) const { - LinkParser parser(string); - if (parser.result()) + auto link = linkparser::parse(string); + if (link) { - b.addLink(*parser.result()); + b.addLink(*link, string); } else { diff --git a/src/messages/MessageBuilder.cpp b/src/messages/MessageBuilder.cpp index 64af873b9..c7959da93 100644 --- a/src/messages/MessageBuilder.cpp +++ b/src/messages/MessageBuilder.cpp @@ -94,10 +94,10 @@ MessageBuilder::MessageBuilder(SystemMessageTag, const QString &text, text.split(QRegularExpression("\\s"), Qt::SkipEmptyParts); for (const auto &word : textFragments) { - LinkParser parser(word); - if (parser.result()) + auto link = linkparser::parse(word); + if (link) { - this->addLink(*parser.result()); + this->addLink(*link, word); continue; } @@ -637,30 +637,45 @@ std::unique_ptr MessageBuilder::releaseBack() return ptr; } -void MessageBuilder::addLink(const ParsedLink &parsedLink) +void MessageBuilder::addLink(const linkparser::Parsed &parsedLink, + const QString &source) { QString lowercaseLinkString; - QString origLink = parsedLink.source; + QString origLink = parsedLink.link.toString(); QString fullUrl; if (parsedLink.protocol.isNull()) { - fullUrl = QStringLiteral("http://") + parsedLink.source; + fullUrl = QStringLiteral("http://") + origLink; } else { lowercaseLinkString += parsedLink.protocol; - fullUrl = parsedLink.source; + fullUrl = origLink; } lowercaseLinkString += parsedLink.host.toString().toLower(); lowercaseLinkString += parsedLink.rest; auto textColor = MessageColor(MessageColor::Link); + + if (parsedLink.hasPrefix(source)) + { + this->emplace(parsedLink.prefix(source).toString(), + MessageElementFlag::Text, this->textColor_) + ->setTrailingSpace(false); + } auto *el = this->emplace( LinkElement::Parsed{.lowercase = lowercaseLinkString, .original = origLink}, fullUrl, MessageElementFlag::Text, textColor); + if (parsedLink.hasSuffix(source)) + { + el->setTrailingSpace(false); + this->emplace(parsedLink.suffix(source).toString(), + MessageElementFlag::Text, this->textColor_); + } + getIApp()->getLinkResolver()->resolve(el->linkInfo()); } @@ -676,20 +691,18 @@ void MessageBuilder::addIrcMessageText(const QString &text) int fg = -1; int bg = -1; - for (const auto &word : words) + for (const auto &string : words) { - if (word.isEmpty()) + if (string.isEmpty()) { continue; } - auto string = QString(word); - // Actually just text - LinkParser parser(string); - if (parser.result()) + auto link = linkparser::parse(string); + if (link) { - this->addLink(*parser.result()); + this->addLink(*link, string); continue; } @@ -772,15 +785,13 @@ void MessageBuilder::addTextOrEmoji(EmotePtr emote) this->emplace(emote, MessageElementFlag::EmojiAll); } -void MessageBuilder::addTextOrEmoji(const QString &string_) +void MessageBuilder::addTextOrEmoji(const QString &string) { - auto string = QString(string_); - // Actually just text - LinkParser linkParser(string); - if (linkParser.result()) + auto link = linkparser::parse(string); + if (link) { - this->addLink(*linkParser.result()); + this->addLink(*link, string); return; } diff --git a/src/messages/MessageBuilder.hpp b/src/messages/MessageBuilder.hpp index 63b9fd8cb..89de99212 100644 --- a/src/messages/MessageBuilder.hpp +++ b/src/messages/MessageBuilder.hpp @@ -24,7 +24,9 @@ class TextElement; struct Emote; using EmotePtr = std::shared_ptr; -struct ParsedLink; +namespace linkparser { + struct Parsed; +} // namespace linkparser struct SystemMessageTag { }; @@ -112,7 +114,7 @@ public: std::weak_ptr weakOf(); void append(std::unique_ptr element); - void addLink(const ParsedLink &parsedLink); + void addLink(const linkparser::Parsed &parsedLink, const QString &source); /** * Adds the text, applies irc colors, adds links, diff --git a/src/messages/search/LinkPredicate.cpp b/src/messages/search/LinkPredicate.cpp index 8430f84ba..4c4def2ae 100644 --- a/src/messages/search/LinkPredicate.cpp +++ b/src/messages/search/LinkPredicate.cpp @@ -14,7 +14,7 @@ bool LinkPredicate::appliesToImpl(const Message &message) { for (const auto &word : message.messageText.split(' ', Qt::SkipEmptyParts)) { - if (LinkParser(word).result()) + if (linkparser::parse(word).has_value()) { return true; } diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index fe7e44990..a5fa340b7 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -733,12 +733,12 @@ void TwitchMessageBuilder::addTextOrEmoji(const QString &string_) } // Actually just text - LinkParser parsed(string); + auto link = linkparser::parse(string); auto textColor = this->textColor_; - if (parsed.result()) + if (link) { - this->addLink(*parsed.result()); + this->addLink(*link, string); return; } diff --git a/tests/src/LinkParser.cpp b/tests/src/LinkParser.cpp index 9d964ce15..746486c97 100644 --- a/tests/src/LinkParser.cpp +++ b/tests/src/LinkParser.cpp @@ -8,21 +8,52 @@ using namespace chatterino; struct Case { + // -Wmissing-field-initializers complains otherwise + // NOLINTBEGIN(readability-redundant-member-init) QString protocol{}; QString host{}; QString rest{}; + // NOLINTEND(readability-redundant-member-init) void check() const { - auto input = this->protocol + this->host + this->rest; - LinkParser p(input); - ASSERT_TRUE(p.result().has_value()) << input; + QStringList prefixes{ + "", "_", "__", "<", "<<", "<_<", "(((", "<*_~(", "**", "~~", + }; + QStringList suffixes{ + "", ">", "?", "!", ".", ",", ":", + "*", "~", ">>", "?!.", "~~,*!?", "**", + }; - const auto &r = *p.result(); - ASSERT_EQ(r.source, input); - ASSERT_EQ(r.protocol, this->protocol) << this->protocol; - ASSERT_EQ(r.host, this->host) << this->host; - ASSERT_EQ(r.rest, this->rest) << this->rest; + for (const auto &prefix : prefixes) + { + for (const auto &suffix : suffixes) + { + checkSingle(prefix, suffix); + } + } + } + + void checkSingle(const QString &prefix, const QString &suffix) const + { + auto link = this->protocol + this->host + this->rest; + auto input = prefix + link + suffix; + auto p = linkparser::parse(input); + ASSERT_TRUE(p.has_value()) << input; + + if (!p) + { + return; + } + + ASSERT_EQ(p->link, link); + ASSERT_EQ(p->protocol, this->protocol); + ASSERT_EQ(p->host, this->host); + ASSERT_EQ(p->rest, this->rest); + ASSERT_EQ(p->prefix(input), prefix); + ASSERT_EQ(p->suffix(input), suffix); + ASSERT_EQ(p->hasPrefix(input), !prefix.isEmpty()); + ASSERT_EQ(p->hasSuffix(input), !suffix.isEmpty()); } }; @@ -56,6 +87,10 @@ TEST(LinkParser, parseDomainLinks) {"", "https.cat"}, {"", "httpsd.cat"}, {"", "http.cat", "/200"}, + {"", "http.cat", "/200("}, + {"", "a.com", "?("}, + {"", "a.com", "#("}, + {"", "a.com", "/__my_user__"}, // test case-insensitiveness {"HtTpS://", "127.0.0.1.CoM"}, {"HTTP://", "XD.CHATTERINO.COM", "/#?FOO"}, @@ -82,7 +117,6 @@ TEST(LinkParser, parseIpv4Links) {"", "1.1.1.1"}, {"", "001.001.01.1"}, {"", "123.246.87.0"}, - {"", "196.168.0.1", ":"}, {"", "196.168.4.2", "/foo"}, {"", "196.168.4.2", "?foo"}, {"http://", "196.168.4.0", "#foo"}, @@ -122,12 +156,24 @@ TEST(LinkParser, doesntParseInvalidIpv4Links) "255.256.255.255", "255.255.256.255", "255.255.255.256", + ":127.0.0.1", + ">1.2.3.4", + "?196.162.8.1", + "!196.162.8.1", + ".196.162.8.1", + ",196.162.8.1", + ":196.162.8.1", + "+196.162.8.1", + "196.162.8.1<", + "196.162.8.1(())", + "196.162.8.1(", + "196.162.8.1(!", }; for (const auto &input : inputs) { - LinkParser p(input); - ASSERT_FALSE(p.result().has_value()) << input; + auto p = linkparser::parse(input); + ASSERT_FALSE(p.has_value()) << input; } } @@ -166,11 +212,23 @@ TEST(LinkParser, doesntParseInvalidLinks) "http:/cat.com", "http:/cat.com", "https:/cat.com", + "chatterino.com-", + "<<>>", + ">><<", + "a.com>><<", + "~~a.com()", + "https://chatterino.com>", + // invalid characters are still accepted (see #4769) + // "chatterino.com>", + // "", }; for (const auto &input : inputs) { - LinkParser p(input); - ASSERT_FALSE(p.result().has_value()) << input; + auto p = linkparser::parse(input); + ASSERT_FALSE(p.has_value()) << input; } } From 9788d0f8f7fa861130e60cf81c7ce38cd60a701f Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 14 Jul 2024 11:45:21 +0200 Subject: [PATCH 12/63] Added option to log streams by their ID, allowing for easier "per-stream" log analyzing (#5507) --- CHANGELOG.md | 1 + mocks/include/mocks/Logging.hpp | 5 +- src/common/Channel.cpp | 8 +- src/common/Channel.hpp | 1 + src/providers/twitch/TwitchChannel.cpp | 12 ++ src/providers/twitch/TwitchChannel.hpp | 2 + src/singletons/Logging.cpp | 8 +- src/singletons/Logging.hpp | 6 +- src/singletons/Settings.hpp | 4 + src/singletons/helper/LoggingChannel.cpp | 141 +++++++++++++------ src/singletons/helper/LoggingChannel.hpp | 18 +-- src/widgets/settingspages/ModerationPage.cpp | 12 +- 12 files changed, 150 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b162187a..93290a1f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - Minor: Added support for Brave & google-chrome-stable browsers. (#5452) - Minor: Added drop indicator line while dragging in tables. (#5256) - Minor: Add channel points indication for new bits power-up redemptions. (#5471) +- Minor: Added option to log streams by their ID, allowing for easier "per-stream" log analyzing. (#5507) - Minor: Added `/warn ` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474) - Minor: Improve appearance of reply button. (#5491) - Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) diff --git a/mocks/include/mocks/Logging.hpp b/mocks/include/mocks/Logging.hpp index 8d444142b..0f4dba38a 100644 --- a/mocks/include/mocks/Logging.hpp +++ b/mocks/include/mocks/Logging.hpp @@ -16,7 +16,7 @@ public: MOCK_METHOD(void, addMessage, (const QString &channelName, MessagePtr message, - const QString &platformName), + const QString &platformName, const QString &streamID), (override)); }; @@ -27,7 +27,8 @@ public: ~EmptyLogging() override = default; void addMessage(const QString &channelName, MessagePtr message, - const QString &platformName) override + const QString &platformName, + const QString &streamID) override { // } diff --git a/src/common/Channel.cpp b/src/common/Channel.cpp index afdc99c0b..76dd8bb86 100644 --- a/src/common/Channel.cpp +++ b/src/common/Channel.cpp @@ -101,7 +101,8 @@ void Channel::addMessage(MessagePtr message, MessageContext context, { // Only log messages where the `DoNotLog` flag is not set getIApp()->getChatLogger()->addMessage(this->name_, message, - this->platform_); + this->platform_, + this->getCurrentStreamID()); } } @@ -356,6 +357,11 @@ void Channel::reconnect() { } +QString Channel::getCurrentStreamID() const +{ + return {}; +} + std::shared_ptr Channel::getEmpty() { static std::shared_ptr channel(new Channel("", Type::None)); diff --git a/src/common/Channel.hpp b/src/common/Channel.hpp index ad4af5114..b85fb83cb 100644 --- a/src/common/Channel.hpp +++ b/src/common/Channel.hpp @@ -119,6 +119,7 @@ public: virtual bool shouldIgnoreHighlights() const; virtual bool canReconnect() const; virtual void reconnect(); + virtual QString getCurrentStreamID() const; static std::shared_ptr getEmpty(); diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index f57081c86..cd293630d 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -457,6 +457,7 @@ void TwitchChannel::updateStreamStatus( auto stream = *helixStream; { auto status = this->streamStatus_.access(); + status->streamId = stream.id; status->viewerCount = stream.viewerCount; status->gameId = stream.gameId; status->game = stream.gameName; @@ -770,6 +771,17 @@ void TwitchChannel::reconnect() getIApp()->getTwitchAbstract()->connect(); } +QString TwitchChannel::getCurrentStreamID() const +{ + auto streamStatus = this->accessStreamStatus(); + if (streamStatus->live) + { + return streamStatus->streamId; + } + + return {}; +} + QString TwitchChannel::roomId() const { return *this->roomID_.access(); diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index 611fea1f9..e3d1e96d8 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -87,6 +87,7 @@ public: QString uptime; int uptimeSeconds = 0; QString streamType; + QString streamId; }; struct RoomModes { @@ -133,6 +134,7 @@ public: bool hasHighRateLimit() const override; bool canReconnect() const override; void reconnect() override; + QString getCurrentStreamID() const override; void createClip(); // Data diff --git a/src/singletons/Logging.cpp b/src/singletons/Logging.cpp index d8bb57127..138efd38a 100644 --- a/src/singletons/Logging.cpp +++ b/src/singletons/Logging.cpp @@ -33,7 +33,7 @@ Logging::Logging(Settings &settings) } void Logging::addMessage(const QString &channelName, MessagePtr message, - const QString &platformName) + const QString &platformName, const QString &streamID) { this->threadGuard.guard(); @@ -54,7 +54,7 @@ void Logging::addMessage(const QString &channelName, MessagePtr message, if (platIt == this->loggingChannels_.end()) { auto *channel = new LoggingChannel(channelName, platformName); - channel->addMessage(message); + channel->addMessage(message, streamID); auto map = std::map>(); this->loggingChannels_[platformName] = std::move(map); auto &ref = this->loggingChannels_.at(platformName); @@ -65,12 +65,12 @@ void Logging::addMessage(const QString &channelName, MessagePtr message, if (chanIt == platIt->second.end()) { auto *channel = new LoggingChannel(channelName, platformName); - channel->addMessage(message); + channel->addMessage(message, streamID); platIt->second.emplace(channelName, std::move(channel)); } else { - chanIt->second->addMessage(message); + chanIt->second->addMessage(message, streamID); } } diff --git a/src/singletons/Logging.hpp b/src/singletons/Logging.hpp index af86a702d..984932ad3 100644 --- a/src/singletons/Logging.hpp +++ b/src/singletons/Logging.hpp @@ -22,7 +22,8 @@ public: virtual ~ILogging() = default; virtual void addMessage(const QString &channelName, MessagePtr message, - const QString &platformName) = 0; + const QString &platformName, + const QString &streamID) = 0; }; class Logging : public ILogging @@ -31,7 +32,8 @@ public: Logging(Settings &settings); void addMessage(const QString &channelName, MessagePtr message, - const QString &platformName) override; + const QString &platformName, + const QString &streamID) override; private: using PlatformName = QString; diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index f0c19edf5..98ec53ed8 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -447,6 +447,10 @@ public: BoolSetting enableLogging = {"/logging/enabled", false}; BoolSetting onlyLogListedChannels = {"/logging/onlyLogListedChannels", false}; + BoolSetting separatelyStoreStreamLogs = { + "/logging/separatelyStoreStreamLogs", + false, + }; QStringSetting logPath = {"/logging/path", ""}; diff --git a/src/singletons/helper/LoggingChannel.cpp b/src/singletons/helper/LoggingChannel.cpp index f3a6fbb79..ad8cfb9a2 100644 --- a/src/singletons/helper/LoggingChannel.cpp +++ b/src/singletons/helper/LoggingChannel.cpp @@ -1,4 +1,4 @@ -#include "LoggingChannel.hpp" +#include "singletons/helper/LoggingChannel.hpp" #include "Application.hpp" #include "common/QLogging.hpp" @@ -7,16 +7,58 @@ #include "singletons/Paths.hpp" #include "singletons/Settings.hpp" +#include #include +namespace { + +const QByteArray ENDLINE("\n"); + +void appendLine(QFile &fileHandle, const QString &line) +{ + assert(fileHandle.isOpen()); + assert(fileHandle.isWritable()); + + fileHandle.write(line.toUtf8()); + fileHandle.flush(); +} + +QString generateOpeningString( + const QDateTime &now = QDateTime::currentDateTime()) +{ + QString ret("# Start logging at "); + + ret.append(now.toString("yyyy-MM-dd HH:mm:ss ")); + ret.append(now.timeZoneAbbreviation()); + ret.append(ENDLINE); + + return ret; +} + +QString generateClosingString( + const QDateTime &now = QDateTime::currentDateTime()) +{ + QString ret("# Stop logging at "); + + ret.append(now.toString("yyyy-MM-dd HH:mm:ss")); + ret.append(now.timeZoneAbbreviation()); + ret.append(ENDLINE); + + return ret; +} + +QString generateDateString(const QDateTime &now) +{ + return now.toString("yyyy-MM-dd"); +} + +} // namespace + namespace chatterino { -QByteArray endline("\n"); - -LoggingChannel::LoggingChannel(const QString &_channelName, - const QString &_platform) - : channelName(_channelName) - , platform(_platform) +LoggingChannel::LoggingChannel(QString _channelName, QString _platform) + : channelName(std::move(_channelName)) + , platform(std::move(_platform)) { if (this->channelName.startsWith("/whispers")) { @@ -54,14 +96,15 @@ LoggingChannel::LoggingChannel(const QString &_channelName, LoggingChannel::~LoggingChannel() { - this->appendLine(this->generateClosingString()); + appendLine(this->fileHandle, generateClosingString()); this->fileHandle.close(); + this->currentStreamFileHandle.close(); } void LoggingChannel::openLogFile() { QDateTime now = QDateTime::currentDateTime(); - this->dateString = this->generateDateString(now); + this->dateString = generateDateString(now); if (this->fileHandle.isOpen()) { @@ -87,14 +130,45 @@ void LoggingChannel::openLogFile() this->fileHandle.open(QIODevice::Append); - this->appendLine(this->generateOpeningString(now)); + appendLine(this->fileHandle, generateOpeningString(now)); } -void LoggingChannel::addMessage(MessagePtr message) +void LoggingChannel::openStreamLogFile(const QString &streamID) +{ + QDateTime now = QDateTime::currentDateTime(); + this->currentStreamID = streamID; + + if (this->currentStreamFileHandle.isOpen()) + { + this->currentStreamFileHandle.flush(); + this->currentStreamFileHandle.close(); + } + + QString baseFileName = this->channelName + "-" + streamID + ".log"; + + QString directory = + this->baseDirectory + QDir::separator() + this->subDirectory; + + if (!QDir().mkpath(directory)) + { + qCDebug(chatterinoHelper) << "Unable to create logging path"; + return; + } + + QString fileName = directory + QDir::separator() + baseFileName; + qCDebug(chatterinoHelper) << "Logging stream to" << fileName; + this->currentStreamFileHandle.setFileName(fileName); + + this->currentStreamFileHandle.open(QIODevice::Append); + appendLine(this->currentStreamFileHandle, generateOpeningString(now)); +} + +void LoggingChannel::addMessage(const MessagePtr &message, + const QString &streamID) { QDateTime now = QDateTime::currentDateTime(); - QString messageDateString = this->generateDateString(now); + QString messageDateString = generateDateString(now); if (messageDateString != this->dateString) { this->dateString = messageDateString; @@ -154,42 +228,19 @@ void LoggingChannel::addMessage(MessagePtr message) } } str.append(messageText); - str.append(endline); + str.append(ENDLINE); - this->appendLine(str); -} + appendLine(this->fileHandle, str); -QString LoggingChannel::generateOpeningString(const QDateTime &now) const -{ - QString ret("# Start logging at "); + if (!streamID.isEmpty() && getSettings()->separatelyStoreStreamLogs) + { + if (this->currentStreamID != streamID) + { + this->openStreamLogFile(streamID); + } - ret.append(now.toString("yyyy-MM-dd HH:mm:ss ")); - ret.append(now.timeZoneAbbreviation()); - ret.append(endline); - - return ret; -} - -QString LoggingChannel::generateClosingString(const QDateTime &now) const -{ - QString ret("# Stop logging at "); - - ret.append(now.toString("yyyy-MM-dd HH:mm:ss")); - ret.append(now.timeZoneAbbreviation()); - ret.append(endline); - - return ret; -} - -void LoggingChannel::appendLine(const QString &line) -{ - this->fileHandle.write(line.toUtf8()); - this->fileHandle.flush(); -} - -QString LoggingChannel::generateDateString(const QDateTime &now) -{ - return now.toString("yyyy-MM-dd"); + appendLine(this->currentStreamFileHandle, str); + } } } // namespace chatterino diff --git a/src/singletons/helper/LoggingChannel.hpp b/src/singletons/helper/LoggingChannel.hpp index 753a63b91..3e57dd9bd 100644 --- a/src/singletons/helper/LoggingChannel.hpp +++ b/src/singletons/helper/LoggingChannel.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -14,8 +13,7 @@ using MessagePtr = std::shared_ptr; class LoggingChannel { - explicit LoggingChannel(const QString &_channelName, - const QString &platform); + explicit LoggingChannel(QString _channelName, QString _platform); public: ~LoggingChannel(); @@ -26,19 +24,11 @@ public: LoggingChannel(LoggingChannel &&) = delete; LoggingChannel &operator=(LoggingChannel &&) = delete; - void addMessage(MessagePtr message); + void addMessage(const MessagePtr &message, const QString &streamID); private: void openLogFile(); - - QString generateOpeningString( - const QDateTime &now = QDateTime::currentDateTime()) const; - QString generateClosingString( - const QDateTime &now = QDateTime::currentDateTime()) const; - - void appendLine(const QString &line); - - QString generateDateString(const QDateTime &now); + void openStreamLogFile(const QString &streamID); const QString channelName; const QString platform; @@ -46,6 +36,8 @@ private: QString subDirectory; QFile fileHandle; + QFile currentStreamFileHandle; + QString currentStreamID; QString dateString; diff --git a/src/widgets/settingspages/ModerationPage.cpp b/src/widgets/settingspages/ModerationPage.cpp index 65ba577b1..95669cce9 100644 --- a/src/widgets/settingspages/ModerationPage.cpp +++ b/src/widgets/settingspages/ModerationPage.cpp @@ -157,11 +157,21 @@ ModerationPage::ModerationPage() onlyLogListedChannels->setEnabled(getSettings()->enableLogging); logs.append(onlyLogListedChannels); + auto *separatelyStoreStreamLogs = + this->createCheckBox("Store live stream logs as separate files", + getSettings()->separatelyStoreStreamLogs); + + separatelyStoreStreamLogs->setEnabled(getSettings()->enableLogging); + logs.append(separatelyStoreStreamLogs); + // Select event QObject::connect( enableLogging, &QCheckBox::stateChanged, this, - [enableLogging, onlyLogListedChannels]() mutable { + [enableLogging, onlyLogListedChannels, + separatelyStoreStreamLogs]() mutable { onlyLogListedChannels->setEnabled(enableLogging->isChecked()); + separatelyStoreStreamLogs->setEnabled( + getSettings()->enableLogging); }); EditableModelView *view = From 6b73bb53ec1b0a3aa6f918ee6fd8d4d6846bd5b2 Mon Sep 17 00:00:00 2001 From: Daniel Sage <24928223+dnsge@users.noreply.github.com> Date: Sun, 14 Jul 2024 12:06:42 -0700 Subject: [PATCH 13/63] Display message being replied to above input box (#4350) Co-authored-by: Rasmus Karlsson --- CHANGELOG.md | 1 + src/CMakeLists.txt | 2 + src/messages/MessageElement.cpp | 2 +- src/widgets/helper/MessageView.cpp | 134 ++++++++++++++++++++ src/widgets/helper/MessageView.hpp | 50 ++++++++ src/widgets/splits/SplitInput.cpp | 192 ++++++++++++++++++++++------- src/widgets/splits/SplitInput.hpp | 34 +++-- 7 files changed, 355 insertions(+), 60 deletions(-) create mode 100644 src/widgets/helper/MessageView.cpp create mode 100644 src/widgets/helper/MessageView.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 93290a1f8..21ace840d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - Minor: Improve appearance of reply button. (#5491) - Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) - Minor: Support more Firefox variants for incognito link opening. (#5503) +- Minor: Replying to a message will now display the message being replied to. (#4350) - Minor: Links can now have prefixes and suffixes such as parentheses. (#5486) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 849397b7d..9df047665 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -643,6 +643,8 @@ set(SOURCE_FILES widgets/helper/IconDelegate.hpp widgets/helper/InvisibleSizeGrip.cpp widgets/helper/InvisibleSizeGrip.hpp + widgets/helper/MessageView.cpp + widgets/helper/MessageView.hpp widgets/helper/NotebookButton.cpp widgets/helper/NotebookButton.hpp widgets/helper/NotebookTab.cpp diff --git a/src/messages/MessageElement.cpp b/src/messages/MessageElement.cpp index 0fb47cd0e..c49e53802 100644 --- a/src/messages/MessageElement.cpp +++ b/src/messages/MessageElement.cpp @@ -566,7 +566,7 @@ SingleLineTextElement::SingleLineTextElement(const QString &text, void SingleLineTextElement::addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) { - auto *app = getApp(); + auto *app = getIApp(); if (flags.hasAny(this->getFlags())) { diff --git a/src/widgets/helper/MessageView.cpp b/src/widgets/helper/MessageView.cpp new file mode 100644 index 000000000..6383ec5a6 --- /dev/null +++ b/src/widgets/helper/MessageView.cpp @@ -0,0 +1,134 @@ +#include "widgets/helper/MessageView.hpp" + +#include "Application.hpp" +#include "messages/layouts/MessageLayout.hpp" +#include "messages/MessageElement.hpp" +#include "messages/Selection.hpp" +#include "providers/colors/ColorProvider.hpp" +#include "singletons/Theme.hpp" +#include "singletons/WindowManager.hpp" + +#include +#include + +namespace { + +using namespace chatterino; + +const Selection EMPTY_SELECTION; + +const MessageElementFlags MESSAGE_FLAGS{ + MessageElementFlag::Text, + MessageElementFlag::EmojiAll, + MessageElementFlag::EmoteText, +}; + +} // namespace + +namespace chatterino { + +MessageView::MessageView() = default; +MessageView::~MessageView() = default; + +void MessageView::createMessageLayout() +{ + if (this->message_ == nullptr) + { + this->messageLayout_.reset(); + return; + } + + this->messageLayout_ = std::make_unique(this->message_); +} + +void MessageView::setMessage(const MessagePtr &message) +{ + if (!message) + { + return; + } + + auto singleLineMessage = std::make_shared(); + singleLineMessage->elements.emplace_back( + std::make_unique( + message->messageText, MESSAGE_FLAGS, MessageColor::Type::System, + FontStyle::ChatMediumSmall)); + this->message_ = std::move(singleLineMessage); + this->createMessageLayout(); + this->layoutMessage(); +} + +void MessageView::clearMessage() +{ + this->setMessage(nullptr); +} + +void MessageView::setWidth(int width) +{ + if (this->width_ != width) + { + this->width_ = width; + this->layoutMessage(); + } +} + +void MessageView::paintEvent(QPaintEvent * /*event*/) +{ + QPainter painter(this); + + auto ctx = MessagePaintContext{ + .painter = painter, + .selection = EMPTY_SELECTION, + .colorProvider = ColorProvider::instance(), + .messageColors = this->messageColors_, + .preferences = this->messagePreferences_, + + .canvasWidth = this->width_, + .isWindowFocused = this->window() == QApplication::activeWindow(), + .isMentions = false, + + .y = 0, + .messageIndex = 0, + .isLastReadMessage = false, + }; + + this->messageLayout_->paint(ctx); +} + +void MessageView::themeChangedEvent() +{ + this->messageColors_.applyTheme(getTheme()); + this->messageColors_.regular = getTheme()->splits.input.background; + if (this->messageLayout_) + { + this->messageLayout_->invalidateBuffer(); + } +} + +void MessageView::scaleChangedEvent(float newScale) +{ + (void)newScale; + + this->layoutMessage(); +} + +void MessageView::layoutMessage() +{ + if (this->messageLayout_ == nullptr) + { + return; + } + + bool updateRequired = this->messageLayout_->layout( + this->width_, this->scale(), + this->scale() * static_cast(this->devicePixelRatio()), + MESSAGE_FLAGS, false); + + if (updateRequired) + { + this->setFixedSize(this->width_, this->messageLayout_->getHeight()); + this->update(); + } +} + +} // namespace chatterino diff --git a/src/widgets/helper/MessageView.hpp b/src/widgets/helper/MessageView.hpp new file mode 100644 index 000000000..242b1b496 --- /dev/null +++ b/src/widgets/helper/MessageView.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "messages/layouts/MessageLayoutContext.hpp" +#include "messages/Message.hpp" +#include "widgets/BaseWidget.hpp" + +#include + +namespace chatterino { + +class MessageLayout; + +/// MessageView is a fixed-width widget that displays a single message. +/// For the message to be rendered, you must call setWidth. +class MessageView : public BaseWidget +{ + Q_OBJECT + +public: + MessageView(); + ~MessageView() override; + MessageView(const MessageView &) = delete; + MessageView(MessageView &&) = delete; + MessageView &operator=(const MessageView &) = delete; + MessageView &operator=(MessageView &&) = delete; + + void setMessage(const MessagePtr &message); + void clearMessage(); + + void setWidth(int width); + +protected: + void paintEvent(QPaintEvent *event) override; + void themeChangedEvent() override; + void scaleChangedEvent(float newScale) override; + +private: + void createMessageLayout(); + void layoutMessage(); + + MessagePtr message_; + std::unique_ptr messageLayout_; + + MessageColors messageColors_; + MessagePreferences messagePreferences_; + + int width_{}; +}; + +} // namespace chatterino diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 865392163..66940b280 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -7,7 +7,6 @@ #include "controllers/hotkeys/HotkeyController.hpp" #include "messages/Link.hpp" #include "messages/Message.hpp" -#include "messages/MessageThread.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchCommon.hpp" #include "providers/twitch/TwitchIrcServer.hpp" @@ -19,6 +18,7 @@ #include "widgets/dialogs/EmotePopup.hpp" #include "widgets/helper/ChannelView.hpp" #include "widgets/helper/EffectLabel.hpp" +#include "widgets/helper/MessageView.hpp" #include "widgets/helper/ResizingTextEdit.hpp" #include "widgets/Notebook.hpp" #include "widgets/Scrollbar.hpp" @@ -84,14 +84,28 @@ void SplitInput::initLayout() auto layout = layoutCreator.setLayoutType().withoutMargin().assign( &this->ui_.vbox); + layout->setSpacing(0); + auto marginPx = this->marginForTheme(); + layout->setContentsMargins(marginPx, marginPx, marginPx, marginPx); // reply label stuff auto replyWrapper = layout.emplace().assign(&this->ui_.replyWrapper); - this->ui_.replyWrapper->setContentsMargins(0, 0, 0, 0); + replyWrapper->setContentsMargins(0, 0, 0, 0); - auto replyHbox = replyWrapper.emplace().withoutMargin().assign( - &this->ui_.replyHbox); + auto replyVbox = + replyWrapper.setLayoutType().withoutMargin().assign( + &this->ui_.replyVbox); + replyVbox->setSpacing(0); + + auto replyHbox = + replyVbox.emplace().assign(&this->ui_.replyHbox); + + auto messageVbox = layoutCreator.setLayoutType(); + this->ui_.replyMessage = new MessageView(); + messageVbox->addWidget(this->ui_.replyMessage, 1, Qt::AlignLeft); + messageVbox->setContentsMargins(10, 0, 0, 0); + replyVbox->addLayout(messageVbox->layout(), 1); auto replyLabel = replyHbox.emplace().assign(&this->ui_.replyLabel); replyLabel->setAlignment(Qt::AlignLeft); @@ -107,9 +121,14 @@ void SplitInput::initLayout() replyCancelButton->hide(); replyLabel->hide(); + auto inputWrapper = + layout.emplace().assign(&this->ui_.inputWrapper); + inputWrapper->setContentsMargins(0, 0, 0, 0); + // hbox for input, right box auto hboxLayout = - layout.emplace().withoutMargin().assign(&this->ui_.hbox); + inputWrapper.setLayoutType().withoutMargin().assign( + &this->ui_.inputHbox); // input auto textEdit = @@ -176,7 +195,7 @@ void SplitInput::initLayout() this->openEmotePopup(); }); - // clear input and remove reply thread + // clear input and remove reply target QObject::connect(this->ui_.cancelReplyButton, &EffectLabel::leftClicked, [this] { this->clearInput(); @@ -211,6 +230,10 @@ void SplitInput::scaleChangedEvent(float scale) if (!this->hidden) { this->setMaximumHeight(this->scaledMaxHeight()); + if (this->replyTarget_ != nullptr) + { + this->ui_.vbox->setSpacing(this->marginForTheme() * 2); + } } this->ui_.textEdit->setFont( app->getFonts()->getFont(FontStyle::ChatMedium, scale)); @@ -236,8 +259,6 @@ void SplitInput::themeChangedEvent() this->ui_.textEdit->setStyleSheet(this->theme->splits.input.styleSheet); this->ui_.textEdit->setPalette(placeholderPalette); - auto marginPx = static_cast(2.F * this->scale()); - this->ui_.vbox->setContentsMargins(marginPx, marginPx, marginPx, marginPx); this->ui_.emoteButton->getLabel().setStyleSheet("color: #000"); @@ -249,6 +270,14 @@ void SplitInput::themeChangedEvent() { this->ui_.replyLabel->setStyleSheet("color: #ccc"); } + + // update vbox + auto marginPx = this->marginForTheme(); + this->ui_.vbox->setContentsMargins(marginPx, marginPx, marginPx, marginPx); + if (this->replyTarget_ != nullptr) + { + this->ui_.vbox->setSpacing(this->marginForTheme() * 2); + } } void SplitInput::updateEmoteButton() @@ -319,7 +348,7 @@ QString SplitInput::handleSendMessage(const std::vector &arguments) return ""; } - if (!c->isTwitchChannel() || this->replyThread_ == nullptr) + if (!c->isTwitchChannel() || this->replyTarget_ == nullptr) { // standard message send behavior QString message = ui_.textEdit->toPlainText(); @@ -338,7 +367,36 @@ QString SplitInput::handleSendMessage(const std::vector &arguments) auto *tc = dynamic_cast(c.get()); if (!tc) { - // this should not fail + // Reply to message + auto tc = dynamic_cast(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->replyTarget_->displayName.length() + + 1); // remove "@username" + + if (!message.isEmpty() && message.at(0) == ' ') + { + message.remove(0, 1); // remove possible space + } + } + + message = message.replace('\n', ' '); + QString sendMessage = + getIApp()->getCommands()->execCommand(message, c, false); + + // Reply within TwitchChannel + tc->sendReply(sendMessage, this->replyTarget_->id); + + this->postMessageSend(message, arguments); return ""; } @@ -347,7 +405,7 @@ QString SplitInput::handleSendMessage(const std::vector &arguments) if (this->enableInlineReplying_) { // Remove @username prefix that is inserted when doing inline replies - message.remove(0, this->replyThread_->displayName.length() + + message.remove(0, this->replyTarget_->displayName.length() + 1); // remove "@username" if (!message.isEmpty() && message.at(0) == ' ') @@ -361,7 +419,7 @@ QString SplitInput::handleSendMessage(const std::vector &arguments) getIApp()->getCommands()->execCommand(message, c, false); // Reply within TwitchChannel - tc->sendReply(sendMessage, this->replyThread_->id); + tc->sendReply(sendMessage, this->replyTarget_->id); this->postMessageSend(message, arguments); return ""; @@ -386,7 +444,15 @@ void SplitInput::postMessageSend(const QString &message, int SplitInput::scaledMaxHeight() const { - return int(150 * this->scale()); + if (this->replyTarget_ != nullptr) + { + // give more space for showing the message being replied to + return int(250 * this->scale()); + } + else + { + return int(150 * this->scale()); + } } void SplitInput::addShortcuts() @@ -1001,24 +1067,24 @@ void SplitInput::editTextChanged() bool hasReply = false; if (this->enableInlineReplying_) { - if (this->replyThread_ != nullptr) + if (this->replyTarget_ != nullptr) { // Check if the input still starts with @username. If not, don't reply. // // We need to verify that // 1. the @username prefix exists and // 2. if a character exists after the @username, it is a space - QString replyPrefix = "@" + this->replyThread_->displayName; + QString replyPrefix = "@" + this->replyTarget_->displayName; if (!text.startsWith(replyPrefix) || (text.length() > replyPrefix.length() && text.at(replyPrefix.length()) != ' ')) { - this->replyThread_ = nullptr; + this->clearReplyTarget(); } } // Show/hide reply label if inline replies are possible - hasReply = this->replyThread_ != nullptr; + hasReply = this->replyTarget_ != nullptr; } this->ui_.replyWrapper->setVisible(hasReply); @@ -1030,37 +1096,35 @@ void SplitInput::paintEvent(QPaintEvent * /*event*/) { QPainter painter(this); - int s{}; - QColor borderColor; + int s = this->marginForTheme(); + QColor borderColor = + this->theme->isLightTheme() ? QColor("#ccc") : QColor("#333"); - if (this->theme->isLightTheme()) - { - s = int(3 * this->scale()); - borderColor = QColor("#ccc"); - } - else - { - s = int(1 * this->scale()); - borderColor = QColor("#333"); - } - - QMargins removeMargins(s - 1, s - 1, s, s); QRect baseRect = this->rect(); + QRect inputBoxRect = this->ui_.inputWrapper->geometry(); + inputBoxRect.setX(baseRect.x()); + inputBoxRect.setWidth(baseRect.width()); - // completeAreaRect includes the reply label - QRect completeAreaRect = baseRect.marginsRemoved(removeMargins); - painter.fillRect(completeAreaRect, this->theme->splits.input.background); + painter.fillRect(inputBoxRect, this->theme->splits.input.background); painter.setPen(borderColor); - painter.drawRect(completeAreaRect); + painter.drawRect(inputBoxRect); - if (this->enableInlineReplying_ && this->replyThread_ != nullptr) + if (this->enableInlineReplying_ && this->replyTarget_ != nullptr) { - // Move top of rect down to not include reply label - baseRect.setTop(baseRect.top() + this->ui_.replyWrapper->height()); + QRect replyRect = this->ui_.replyWrapper->geometry(); + replyRect.setX(baseRect.x()); + replyRect.setWidth(baseRect.width()); - QRect onlyInputRect = baseRect.marginsRemoved(removeMargins); + painter.fillRect(replyRect, this->theme->splits.input.background); painter.setPen(borderColor); - painter.drawRect(onlyInputRect); + painter.drawRect(replyRect); + + QPoint replyLabelBorderStart( + replyRect.x(), + replyRect.y() + this->ui_.replyHbox->geometry().height()); + QPoint replyLabelBorderEnd(replyRect.right(), + replyLabelBorderStart.y()); + painter.drawLine(replyLabelBorderStart, replyLabelBorderEnd); } } @@ -1076,6 +1140,8 @@ void SplitInput::resizeEvent(QResizeEvent *event) { this->ui_.textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } + + this->ui_.replyMessage->setWidth(this->width()); } void SplitInput::giveFocus(Qt::FocusReason reason) @@ -1083,9 +1149,9 @@ void SplitInput::giveFocus(Qt::FocusReason reason) this->ui_.textEdit->setFocus(reason); } -void SplitInput::setReply(MessagePtr reply, bool showReplyingLabel) +void SplitInput::setReply(MessagePtr target) { - auto oldParent = this->replyThread_; + auto oldParent = this->replyTarget_; if (this->enableInlineReplying_ && oldParent) { // Remove old reply prefix @@ -1100,12 +1166,24 @@ void SplitInput::setReply(MessagePtr reply, bool showReplyingLabel) this->ui_.textEdit->resetCompletion(); } - this->replyThread_ = std::move(reply); + assert(target != nullptr); + this->replyTarget_ = std::move(target); if (this->enableInlineReplying_) { + this->ui_.replyMessage->setMessage(this->replyTarget_); + this->ui_.replyMessage->setWidth(this->width()); + + // add spacing between reply box and input box + this->ui_.vbox->setSpacing(this->marginForTheme() * 2); + if (!this->isHidden()) + { + // update maximum height to give space for message + this->setMaximumHeight(this->scaledMaxHeight()); + } + // Only enable reply label if inline replying - auto replyPrefix = "@" + this->replyThread_->displayName; + auto replyPrefix = "@" + this->replyTarget_->displayName; auto plainText = this->ui_.textEdit->toPlainText().trimmed(); // This makes it so if plainText contains "@StreamerFan" and @@ -1134,7 +1212,7 @@ void SplitInput::setReply(MessagePtr reply, bool showReplyingLabel) this->ui_.textEdit->moveCursor(QTextCursor::EndOfBlock); this->ui_.textEdit->resetCompletion(); this->ui_.replyLabel->setText("Replying to @" + - this->replyThread_->displayName); + this->replyTarget_->displayName); } } @@ -1148,9 +1226,17 @@ void SplitInput::clearInput() this->currMsg_ = ""; this->ui_.textEdit->setText(""); this->ui_.textEdit->moveCursor(QTextCursor::Start); - if (this->enableInlineReplying_) + this->clearReplyTarget(); +} + +void SplitInput::clearReplyTarget() +{ + this->replyTarget_.reset(); + this->ui_.replyMessage->clearMessage(); + this->ui_.vbox->setSpacing(0); + if (!this->isHidden()) { - this->replyThread_ = nullptr; + this->setMaximumHeight(this->scaledMaxHeight()); } } @@ -1177,4 +1263,16 @@ bool SplitInput::shouldPreventInput(const QString &text) const return text.length() > TWITCH_MESSAGE_LIMIT; } +int SplitInput::marginForTheme() const +{ + if (this->theme->isLightTheme()) + { + return int(3 * this->scale()); + } + else + { + return int(1 * this->scale()); + } +} + } // namespace chatterino diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index f66d5d27f..8319f9f71 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -20,6 +20,7 @@ class Split; class EmotePopup; class InputCompletionPopup; class EffectLabel; +class MessageView; class ResizingTextEdit; class ChannelView; enum class CompletionKind; @@ -40,7 +41,7 @@ public: QString getInputText() const; void insertText(const QString &text); - void setReply(MessagePtr reply, bool showInlineReplying = true); + void setReply(MessagePtr target); void setPlaceholderText(const QString &text); /** @@ -91,7 +92,7 @@ protected: void postMessageSend(const QString &message, const std::vector &arguments); - /// Clears the input box, clears reply thread if inline replies are enabled + /// Clears the input box, clears reply target if inline replies are enabled void clearInput(); void addShortcuts() override; @@ -109,6 +110,7 @@ protected: void hideCompletionPopup(); void insertCompletionText(const QString &input_) const; void openEmotePopup(); + void clearReplyTarget(); void updateCancelReplyButton(); @@ -120,27 +122,35 @@ protected: // the user's setting is set to Prevent, and the given text goes beyond the Twitch message length limit bool shouldPreventInput(const QString &text) const; + int marginForTheme() const; + Split *const split_; ChannelView *const channelView_; QPointer emotePopup_; QPointer inputCompletionPopup_; struct { + // vbox for all components + QVBoxLayout *vbox; + + // reply widgets + QWidget *replyWrapper; + QVBoxLayout *replyVbox; + QHBoxLayout *replyHbox; + MessageView *replyMessage; + QLabel *replyLabel; + EffectLabel *cancelReplyButton; + + // input widgets + QWidget *inputWrapper; + QHBoxLayout *inputHbox; ResizingTextEdit *textEdit; QLabel *textEditLength; EffectLabel *sendButton; EffectLabel *emoteButton; + } ui_; - QHBoxLayout *hbox; - QVBoxLayout *vbox; - - QWidget *replyWrapper; - QHBoxLayout *replyHbox; - QLabel *replyLabel; - EffectLabel *cancelReplyButton; - } ui_{}; - - MessagePtr replyThread_ = nullptr; + MessagePtr replyTarget_ = nullptr; bool enableInlineReplying_; pajlada::Signals::SignalHolder managedConnections_; From deb4401036ac6f03b9f96cb5f2dfa851e3b61be0 Mon Sep 17 00:00:00 2001 From: nerix Date: Tue, 16 Jul 2024 16:35:44 +0200 Subject: [PATCH 14/63] chore: make `FlagsEnum` constexpr (#5510) --- CHANGELOG.md | 1 + src/PrecompiledHeader.hpp | 1 + src/common/FlagsEnum.hpp | 119 ++++++++----- tests/CMakeLists.txt | 1 + tests/src/FlagsEnum.cpp | 345 ++++++++++++++++++++++++++++++++++++++ tests/src/Test.hpp | 4 +- 6 files changed, 425 insertions(+), 46 deletions(-) create mode 100644 tests/src/FlagsEnum.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 21ace840d..f3d0e1f0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ - Dev: Cleanup `BrowserExtension`. (#5465) - Dev: Deprecate Qt 5.12. (#5396) - Dev: The running Qt version is now shown in the about page if it differs from the compiled version. (#5501) +- Dev: `FlagsEnum` is now `constexpr`. (#5510) ## 2.5.1 diff --git a/src/PrecompiledHeader.hpp b/src/PrecompiledHeader.hpp index 144faf56b..5a66ec73f 100644 --- a/src/PrecompiledHeader.hpp +++ b/src/PrecompiledHeader.hpp @@ -108,6 +108,7 @@ # include # include # include +# include # include # include # include diff --git a/src/common/FlagsEnum.hpp b/src/common/FlagsEnum.hpp index 7d1c11c8a..e49c30aa6 100644 --- a/src/common/FlagsEnum.hpp +++ b/src/common/FlagsEnum.hpp @@ -1,59 +1,74 @@ #pragma once -#include +#include #include namespace chatterino { -template ::type> +template + requires std::is_enum_v class FlagsEnum { public: - FlagsEnum() - : value_(static_cast(0)) + using Int = std::underlying_type_t; + + constexpr FlagsEnum() noexcept = default; + + constexpr FlagsEnum(std::convertible_to auto... flags) noexcept + : value_( + static_cast((static_cast(static_cast(flags)) | ...))) { } - FlagsEnum(T value) - : value_(value) + friend constexpr bool operator==(FlagsEnum lhs, FlagsEnum rhs) noexcept { + return lhs.value_ == rhs.value_; + } + friend constexpr bool operator!=(FlagsEnum lhs, FlagsEnum rhs) noexcept + { + return lhs.value_ != rhs.value_; } - FlagsEnum(std::initializer_list flags) + friend constexpr bool operator==(FlagsEnum lhs, T rhs) noexcept { - for (auto flag : flags) - { - this->set(flag); - } + return lhs.value_ == rhs; + } + friend constexpr bool operator!=(FlagsEnum lhs, T rhs) noexcept + { + return lhs.value_ != rhs; } - bool operator==(const FlagsEnum &other) const + friend constexpr bool operator==(T lhs, FlagsEnum rhs) noexcept { - return this->value_ == other.value_; + return lhs == rhs.value_; + } + friend constexpr bool operator!=(T lhs, FlagsEnum rhs) noexcept + { + return lhs != rhs.value_; } - bool operator!=(const FlagsEnum &other) const + constexpr void set(std::convertible_to auto... flags) noexcept { - return this->value_ != other.value_; - } - - void set(T flag) - { - reinterpret_cast(this->value_) |= static_cast(flag); + this->value_ = + static_cast(static_cast(this->value_) | + (static_cast(static_cast(flags)) | ...)); } /** Adds the flags from `flags` in this enum. */ - void set(FlagsEnum flags) + constexpr void set(FlagsEnum flags) noexcept { - reinterpret_cast(this->value_) |= static_cast(flags.value_); + this->value_ = static_cast(static_cast(this->value_) | + static_cast(flags.value_)); } - void unset(T flag) + constexpr void unset(std::convertible_to auto... flags) noexcept { - reinterpret_cast(this->value_) &= ~static_cast(flag); + this->value_ = + static_cast(static_cast(this->value_) & + ~(static_cast(static_cast(flags)) | ...)); } - void set(T flag, bool value) + constexpr void set(T flag, bool value) noexcept { if (value) { @@ -65,43 +80,59 @@ public: } } - bool has(T flag) const + constexpr FlagsEnum operator|(T flag) const noexcept { - return static_cast(this->value_) & static_cast(flag); + return static_cast(static_cast(this->value_) | + static_cast(flag)); } - FlagsEnum operator|(T flag) + constexpr FlagsEnum operator|(FlagsEnum rhs) const noexcept { - FlagsEnum xd; - xd.value_ = this->value_; - xd.set(flag, true); - - return xd; + return static_cast(static_cast(this->value_) | + static_cast(rhs.value_)); } - FlagsEnum operator|(FlagsEnum rhs) + constexpr bool has(T flag) const noexcept { - return static_cast(static_cast(this->value_) | - static_cast(rhs.value_)); + return static_cast(this->value_) & static_cast(flag); } - bool hasAny(FlagsEnum flags) const + constexpr bool hasAny(FlagsEnum flags) const noexcept { - return static_cast(this->value_) & static_cast(flags.value_); + return (static_cast(this->value_) & + static_cast(flags.value_)) != 0; } - bool hasAll(FlagsEnum flags) const + constexpr bool hasAny(std::convertible_to auto... flags) const noexcept { - return (static_cast(this->value_) & static_cast(flags.value_)) && - static_cast(flags->value); + return this->hasAny(FlagsEnum{flags...}); } - bool hasNone(std::initializer_list flags) const + constexpr bool hasAll(FlagsEnum flags) const noexcept { - return !this->hasAny(flags); + return (static_cast(this->value_) & + static_cast(flags.value_)) == + static_cast(flags.value_); } - T value() const + constexpr bool hasAll(std::convertible_to auto... flags) const noexcept + { + return this->hasAll(FlagsEnum{flags...}); + } + + constexpr bool hasNone(FlagsEnum flags) const noexcept + { + return (static_cast(this->value_) & + static_cast(flags.value_)) == 0; + } + + constexpr bool hasNone() const noexcept = delete; + constexpr bool hasNone(std::convertible_to auto... flags) const noexcept + { + return this->hasNone(FlagsEnum{flags...}); + } + + constexpr T value() const noexcept { return this->value_; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 19ac9195b..79c490fa9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -45,6 +45,7 @@ set(test_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/ModerationAction.cpp ${CMAKE_CURRENT_LIST_DIR}/src/Scrollbar.cpp ${CMAKE_CURRENT_LIST_DIR}/src/Commands.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/FlagsEnum.cpp # Add your new file above this line! ) diff --git a/tests/src/FlagsEnum.cpp b/tests/src/FlagsEnum.cpp new file mode 100644 index 000000000..4b3e94ba5 --- /dev/null +++ b/tests/src/FlagsEnum.cpp @@ -0,0 +1,345 @@ +#include "common/FlagsEnum.hpp" + +#include "Test.hpp" + +using namespace chatterino; + +namespace { + +enum class BasicScoped : std::uint16_t { + None = 0, + Foo = 1 << 0, + Bar = 1 << 1, + Baz = 1 << 2, + Qox = 1 << 3, + Quux = 1 << 4, + Corge = 1 << 5, + Grault = 1 << 6, + Garply = 1 << 7, + Waldo = 1 << 8, + Fred = 1 << 9, +}; +using BasicInt = std::underlying_type_t; + +enum BasicUnscoped : BasicInt { + None = 0, + Foo = 1 << 0, + Bar = 1 << 1, + Baz = 1 << 2, + Qox = 1 << 3, + Quux = 1 << 4, + Corge = 1 << 5, + Grault = 1 << 6, + Garply = 1 << 7, + Waldo = 1 << 8, + Fred = 1 << 9, +}; + +using Scoped = FlagsEnum; +using Unscoped = FlagsEnum; + +} // namespace + +TEST(FlagsEnum, sizeAndAlign) +{ + enum class U8 : std::uint8_t {}; + enum class I8 : std::int8_t {}; + enum class U16 : std::uint16_t {}; + enum class I16 : std::int16_t {}; + enum class U32 : std::uint32_t {}; + enum class I32 : std::int32_t {}; + enum class U64 : std::uint64_t {}; + enum class I64 : std::int64_t {}; + + auto check = []() { + return (((sizeof(T) == sizeof(FlagsEnum)) && ...) && + ((alignof(T) == alignof(FlagsEnum)) && ...)); + }; + + static_assert( + check.template operator()()); +} + +template +consteval void testCtor() +{ + using FE = FlagsEnum; + using U = std::underlying_type_t; + + static_assert(FE{}.value() == E::None); + static_assert(FE{E::Bar}.value() == E::Bar); + static_assert( + FE{E::Bar, E::Qox}.value() == + static_cast(static_cast(E::Bar) | static_cast(E::Qox))); + static_assert( + FE{E::Bar, E::Bar, E::Qox}.value() == + static_cast(static_cast(E::Bar) | static_cast(E::Qox))); +} + +TEST(FlagsEnum, ctor) +{ + testCtor(); + testCtor(); +} + +template +consteval void testOperatorEq() +{ + using FE = FlagsEnum; + + static_assert(FE{} == FE{}); + + static_assert(FE{E::Corge} == FE{E::Corge}); + + static_assert(FE{E::Corge, E::Garply} == FE{E::Garply, E::Corge}); + + static_assert(FE{} == E::None); + static_assert(E::None == FE{}); + static_assert(FE{E::Foo} == E::Foo); + static_assert(E::Foo == FE{E::Foo}); +} + +TEST(FlagsEnum, operatorEq) +{ + testOperatorEq(); + testOperatorEq(); +} + +template +consteval void testOperatorNeq() +{ + using FE = FlagsEnum; + + static_assert(FE{} != FE{E::Quux}); + + static_assert(FE{E::Corge} != FE{E::Grault}); + + static_assert(FE{E::Corge, E::Garply} != FE{E::Garply, E::Waldo}); + + static_assert(FE{} != E::Foo); + static_assert(E::Foo != FE{}); + static_assert(FE{E::Foo} != E::None); + static_assert(E::None != FE{E::Foo}); +} + +TEST(FlagsEnum, operatorNeq) +{ + testOperatorNeq(); + testOperatorNeq(); +} + +template +inline void testSetUnset() +{ + using FE = FlagsEnum; + + FE s; + ASSERT_EQ(s, FE{}); + s.set(E::Foo); + ASSERT_EQ(s, E::Foo); + s.set(E::Fred, E::Qox); + ASSERT_EQ(s, (FE{E::Foo, E::Fred, E::Qox})); + s.set(E::Foo); + ASSERT_EQ(s, (FE{E::Foo, E::Fred, E::Qox})); + + s.set(FE{E::Bar, E::Baz, E::Qox}); + ASSERT_EQ(s, (FE{E::Foo, E::Fred, E::Qox, E::Bar, E::Baz})); + + s.set(E::Foo, false); + ASSERT_EQ(s, (FE{E::Fred, E::Qox, E::Bar, E::Baz})); + + s.unset(E::Foo, E::Qox, E::Bar); + ASSERT_EQ(s, (FE{E::Fred, E::Baz})); + + s.unset(E::Fred, E::Baz, E ::Bar); + ASSERT_EQ(s, FE{}); + + s.unset(E::Baz); + ASSERT_EQ(s, FE{}); + + static_assert([] { + FE s; + bool result = s == FE{}; + + s.set(E::Foo); + result = result && s == E::Foo; + + s.set(E::Fred, E::Qox); + result = result && s == FE{E::Foo, E::Fred, E::Qox}; + + s.set(E::Foo); + result = result && s == FE{E::Foo, E::Fred, E::Qox}; + + s.set(FE{E::Bar, E::Baz, E::Qox}); + result = result && s == FE{E::Foo, E::Fred, E::Qox, E::Bar, E::Baz}; + + s.set(E::Foo, false); + result = result && s == (FE{E::Fred, E::Qox, E::Bar, E::Baz}); + + s.unset(E::Foo, E::Qox, E::Bar); + result = result && s == (FE{E::Fred, E::Baz}); + + s.unset(E::Fred, E::Baz, E ::Bar); + result = result && s == (FE{}); + + s.unset(E::Baz); + result = result && s == (FE{}); + + return result; + }()); +} + +TEST(FlagsEnum, setUnset) +{ + testSetUnset(); + testSetUnset(); +} + +template +consteval void testOperatorBitOr() +{ + using FE = FlagsEnum; + + static_assert((FE{E::Foo} | E::Bar) == FE{E::Foo, E::Bar}); + static_assert((FE{E::Foo} | E::Foo) == FE{E::Foo}); + static_assert((FE{E::Foo} | E::None) == FE{E::Foo}); + static_assert((FE{} | E::Foo) == FE{E::Foo}); + static_assert((FE{} | E::None) == FE{}); + + static_assert((FE{E::Foo} | FE{E::Bar}) == FE{E::Foo, E::Bar}); + static_assert((FE{E::Foo} | FE{E::Foo, E::Bar, E::Baz}) == + FE{E::Foo, E::Bar, E::Baz}); + static_assert((FE{E::Foo} | FE{}) == FE{E::Foo}); + static_assert((FE{} | FE{}) == FE{}); +} + +TEST(FlagsEnum, operatorBitOr) +{ + testOperatorBitOr(); + testOperatorBitOr(); +} + +template +consteval void testHas() +{ + using FE = FlagsEnum; + + static_assert(FE{E::Foo}.has(E::Foo)); + static_assert(!FE{E::Foo}.has(E::Bar)); + static_assert(!FE{E::Foo}.has(E::None)); + + static_assert(!FE{}.has(E::Foo)); + static_assert(!FE{}.has(E::None)); + + static_assert(FE{E::Qox, E::Waldo, E::Garply}.has(E::Qox)); + static_assert(FE{E::Qox, E::Waldo, E::Garply}.has(E::Waldo)); + static_assert(FE{E::Qox, E::Waldo, E::Garply}.has(E::Garply)); + static_assert(!FE{E::Qox, E::Waldo, E::Garply}.has(E::Grault)); +} + +TEST(FlagsEnum, has) +{ + testHas(); + testHas(); +} + +template +consteval void testHasAny() +{ + using FE = FlagsEnum; + + static_assert(FE{E::Foo}.hasAny(E::Foo)); + static_assert(!FE{E::Foo}.hasAny(E::Bar)); + static_assert(!FE{E::Foo}.hasAny(E::None)); + + static_assert(!FE{}.hasAny(E::Foo)); + static_assert(!FE{}.hasAny(E::None)); + + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAny(E::Qox, E::Foo)); + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAny({E::Qox, E::Foo})); + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAny(E::Waldo, E::None)); + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAny(E::Garply, E::Grault)); + static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAny(E::Grault)); + static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAny()); +} + +TEST(FlagsEnum, hasAny) +{ + testHasAny(); + testHasAny(); +} + +template +consteval void testHasAll() +{ + using FE = FlagsEnum; + + static_assert(FE{E::Foo}.hasAll(E::Foo)); + static_assert(FE{E::Foo}.hasAll(E::None)); + static_assert(!FE{E::Foo}.hasAll(E::Bar)); + + static_assert(FE{}.hasAll(E::None)); + static_assert(!FE{}.hasAll(E::Foo)); + + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Waldo, E::None)); + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAll({E::Waldo, E::None})); + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAll()); + static_assert( + FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Qox, E::Waldo, E::Garply)); + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Qox, E::Waldo, + E::Garply, E::None)); + + static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Qox, E::Foo)); + static_assert( + !FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Garply, E::Grault)); + static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Grault)); + static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasAll(E::Qox, E::Waldo, + E::Garply, E::Foo)); +} + +TEST(FlagsEnum, hasAll) +{ + testHasAll(); + testHasAll(); +} + +template +consteval void testHasNone() +{ + using FE = FlagsEnum; + + static_assert(FE{E::Foo}.hasNone(E::Bar)); + static_assert(FE{E::Foo}.hasNone(E::None)); + + static_assert(FE{}.hasNone(E::Foo)); + static_assert(FE{}.hasNone(E::None)); + + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasNone(E::Foo, E::Foo)); + static_assert(FE{E::Qox, E::Waldo, E::Garply}.hasNone({E::Bar, E::Foo})); + static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasNone(E::Waldo, E::Foo)); + static_assert(!FE{E::Qox, E::Waldo, E::Garply}.hasNone(E::Garply)); +} + +TEST(FlagsEnum, hasNone) +{ + testHasNone(); + testHasNone(); +} + +template +constexpr inline auto CONSTRUCTION_VALID = requires() { FlagsEnum{}; }; + +TEST(FlagsEnum, templateParam) +{ + struct S { + }; + + static_assert(!CONSTRUCTION_VALID); + static_assert(!CONSTRUCTION_VALID); + static_assert(!CONSTRUCTION_VALID); + static_assert(!CONSTRUCTION_VALID); + static_assert(!CONSTRUCTION_VALID); + + static_assert(CONSTRUCTION_VALID); + static_assert(CONSTRUCTION_VALID); +} diff --git a/tests/src/Test.hpp b/tests/src/Test.hpp index 064f90c6d..a44e244a7 100644 --- a/tests/src/Test.hpp +++ b/tests/src/Test.hpp @@ -1,7 +1,7 @@ #pragma once -#include -#include +#include // IWYU pragma: export +#include // IWYU pragma: export #include From b3c09b65d8e5276f07fcd4b190b1df3308a3d912 Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 20 Jul 2024 11:35:59 +0200 Subject: [PATCH 15/63] chore: mini refactorings and dead code removal (#5512) --- src/Application.cpp | 1 - src/CMakeLists.txt | 3 - src/common/ConcurrentMap.hpp | 102 ------------------- src/common/Credentials.cpp | 1 - src/providers/irc/IrcCommands.cpp | 1 - src/providers/twitch/PubSubClient.cpp | 1 - src/providers/twitch/PubSubManager.cpp | 1 - src/providers/twitch/PubSubMessages.hpp | 17 ++-- src/singletons/Settings.cpp | 6 +- src/singletons/WindowManager.cpp | 1 - src/util/Clamp.hpp | 13 --- src/util/ConcurrentMap.hpp | 102 ------------------- src/util/DisplayBadge.hpp | 1 + src/util/DistanceBetweenPoints.hpp | 8 +- src/util/ExponentialBackoff.hpp | 4 +- src/util/Helpers.cpp | 6 +- src/util/Helpers.hpp | 4 +- src/util/LayoutCreator.hpp | 96 +++++++---------- src/util/Overloaded.hpp | 13 --- src/util/PersistSignalVector.hpp | 28 ----- src/util/PostToThread.hpp | 24 ----- src/util/SplitCommand.cpp | 97 ------------------ src/util/SplitCommand.hpp | 15 --- src/util/StreamLink.cpp | 7 +- src/widgets/settingspages/ModerationPage.cpp | 7 +- src/widgets/settingspages/ModerationPage.hpp | 5 +- src/widgets/splits/SplitInput.cpp | 5 +- tests/src/Helpers.cpp | 2 +- 28 files changed, 65 insertions(+), 506 deletions(-) delete mode 100644 src/common/ConcurrentMap.hpp delete mode 100644 src/util/Clamp.hpp delete mode 100644 src/util/ConcurrentMap.hpp delete mode 100644 src/util/Overloaded.hpp delete mode 100644 src/util/PersistSignalVector.hpp delete mode 100644 src/util/SplitCommand.cpp delete mode 100644 src/util/SplitCommand.hpp diff --git a/src/Application.cpp b/src/Application.cpp index 2c97b8fd2..30e7cdb26 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -42,7 +42,6 @@ #include "providers/twitch/PubSubActions.hpp" #include "providers/twitch/PubSubManager.hpp" #include "providers/twitch/PubSubMessages.hpp" -#include "providers/twitch/pubsubmessages/LowTrustUsers.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchIrcServer.hpp" #include "providers/twitch/TwitchMessageBuilder.hpp" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9df047665..3e6f0939b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -487,7 +487,6 @@ set(SOURCE_FILES util/ChannelHelpers.hpp util/Clipboard.cpp util/Clipboard.hpp - util/ConcurrentMap.hpp util/DebugCount.cpp util/DebugCount.hpp util/DisplayBadge.cpp @@ -517,8 +516,6 @@ set(SOURCE_FILES util/SampleData.cpp util/SampleData.hpp util/SharedPtrElementLess.hpp - util/SplitCommand.cpp - util/SplitCommand.hpp util/StreamLink.cpp util/StreamLink.hpp util/ThreadGuard.hpp diff --git a/src/common/ConcurrentMap.hpp b/src/common/ConcurrentMap.hpp deleted file mode 100644 index 6f385559b..000000000 --- a/src/common/ConcurrentMap.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include - -namespace chatterino { - -template -class ConcurrentMap -{ -public: - ConcurrentMap() = default; - - bool tryGet(const TKey &name, TValue &value) const - { - QMutexLocker lock(&this->mutex); - - auto a = this->data.find(name); - if (a == this->data.end()) - { - return false; - } - - value = a.value(); - - return true; - } - - TValue getOrAdd(const TKey &name, std::function addLambda) - { - QMutexLocker lock(&this->mutex); - - auto a = this->data.find(name); - if (a == this->data.end()) - { - TValue value = addLambda(); - this->data.insert(name, value); - return value; - } - - return a.value(); - } - - TValue &operator[](const TKey &name) - { - QMutexLocker lock(&this->mutex); - - return this->data[name]; - } - - void clear() - { - QMutexLocker lock(&this->mutex); - - this->data.clear(); - } - - void insert(const TKey &name, const TValue &value) - { - QMutexLocker lock(&this->mutex); - - this->data.insert(name, value); - } - - void each( - std::function func) const - { - QMutexLocker lock(&this->mutex); - - QMapIterator it(this->data); - - while (it.hasNext()) - { - it.next(); - func(it.key(), it.value()); - } - } - - void each(std::function func) - { - QMutexLocker lock(&this->mutex); - - QMutableMapIterator it(this->data); - - while (it.hasNext()) - { - it.next(); - func(it.key(), it.value()); - } - } - -private: - mutable QMutex mutex; - QMap data; -}; - -} // namespace chatterino diff --git a/src/common/Credentials.cpp b/src/common/Credentials.cpp index 5784436f1..5fffe013f 100644 --- a/src/common/Credentials.cpp +++ b/src/common/Credentials.cpp @@ -6,7 +6,6 @@ #include "singletons/Paths.hpp" #include "singletons/Settings.hpp" #include "util/CombinePath.hpp" -#include "util/Overloaded.hpp" #include "util/Variant.hpp" #include diff --git a/src/providers/irc/IrcCommands.cpp b/src/providers/irc/IrcCommands.cpp index 3dff08cb6..cd5f7d5e6 100644 --- a/src/providers/irc/IrcCommands.cpp +++ b/src/providers/irc/IrcCommands.cpp @@ -3,7 +3,6 @@ #include "messages/MessageBuilder.hpp" #include "providers/irc/IrcChannel2.hpp" #include "providers/irc/IrcServer.hpp" -#include "util/Overloaded.hpp" #include "util/QStringHash.hpp" namespace chatterino { diff --git a/src/providers/twitch/PubSubClient.cpp b/src/providers/twitch/PubSubClient.cpp index 80b6d66ed..514fd487d 100644 --- a/src/providers/twitch/PubSubClient.cpp +++ b/src/providers/twitch/PubSubClient.cpp @@ -4,7 +4,6 @@ #include "providers/twitch/PubSubActions.hpp" #include "providers/twitch/PubSubHelpers.hpp" #include "providers/twitch/PubSubMessages.hpp" -#include "providers/twitch/pubsubmessages/Unlisten.hpp" #include "singletons/Settings.hpp" #include "util/DebugCount.hpp" #include "util/Helpers.hpp" diff --git a/src/providers/twitch/PubSubManager.cpp b/src/providers/twitch/PubSubManager.cpp index 447909812..9f16951a7 100644 --- a/src/providers/twitch/PubSubManager.cpp +++ b/src/providers/twitch/PubSubManager.cpp @@ -7,7 +7,6 @@ #include "providers/twitch/PubSubHelpers.hpp" #include "providers/twitch/PubSubMessages.hpp" #include "providers/twitch/TwitchAccount.hpp" -#include "pubsubmessages/LowTrustUsers.hpp" #include "util/DebugCount.hpp" #include "util/Helpers.hpp" #include "util/RapidjsonHelpers.hpp" diff --git a/src/providers/twitch/PubSubMessages.hpp b/src/providers/twitch/PubSubMessages.hpp index f9cc5c501..48c4066b3 100644 --- a/src/providers/twitch/PubSubMessages.hpp +++ b/src/providers/twitch/PubSubMessages.hpp @@ -1,10 +1,11 @@ #pragma once -#include "providers/twitch/pubsubmessages/AutoMod.hpp" -#include "providers/twitch/pubsubmessages/Base.hpp" -#include "providers/twitch/pubsubmessages/ChannelPoints.hpp" -#include "providers/twitch/pubsubmessages/ChatModeratorAction.hpp" -#include "providers/twitch/pubsubmessages/Listen.hpp" -#include "providers/twitch/pubsubmessages/Message.hpp" -#include "providers/twitch/pubsubmessages/Unlisten.hpp" -#include "providers/twitch/pubsubmessages/Whisper.hpp" +#include "providers/twitch/pubsubmessages/AutoMod.hpp" // IWYU pragma: export +#include "providers/twitch/pubsubmessages/Base.hpp" // IWYU pragma: export +#include "providers/twitch/pubsubmessages/ChannelPoints.hpp" // IWYU pragma: export +#include "providers/twitch/pubsubmessages/ChatModeratorAction.hpp" // IWYU pragma: export +#include "providers/twitch/pubsubmessages/Listen.hpp" // IWYU pragma: export +#include "providers/twitch/pubsubmessages/LowTrustUsers.hpp" // IWYU pragma: export +#include "providers/twitch/pubsubmessages/Message.hpp" // IWYU pragma: export +#include "providers/twitch/pubsubmessages/Unlisten.hpp" // IWYU pragma: export +#include "providers/twitch/pubsubmessages/Whisper.hpp" // IWYU pragma: export diff --git a/src/singletons/Settings.cpp b/src/singletons/Settings.cpp index 451692aa0..09e2b410a 100644 --- a/src/singletons/Settings.cpp +++ b/src/singletons/Settings.cpp @@ -10,8 +10,6 @@ #include "controllers/nicknames/Nickname.hpp" #include "debug/Benchmark.hpp" #include "pajlada/settings/signalargs.hpp" -#include "util/Clamp.hpp" -#include "util/PersistSignalVector.hpp" #include "util/WindowsHelper.hpp" #include @@ -267,12 +265,12 @@ void Settings::restoreSnapshot() float Settings::getClampedUiScale() const { - return clamp(this->uiScale.getValue(), 0.2f, 10); + return std::clamp(this->uiScale.getValue(), 0.2F, 10.F); } void Settings::setClampedUiScale(float value) { - this->uiScale.setValue(clamp(value, 0.2f, 10)); + this->uiScale.setValue(std::clamp(value, 0.2F, 10.F)); } Settings &Settings::instance() diff --git a/src/singletons/WindowManager.cpp b/src/singletons/WindowManager.cpp index 1e0f78451..66a0f606e 100644 --- a/src/singletons/WindowManager.cpp +++ b/src/singletons/WindowManager.cpp @@ -12,7 +12,6 @@ #include "singletons/Paths.hpp" #include "singletons/Settings.hpp" #include "singletons/Theme.hpp" -#include "util/Clamp.hpp" #include "util/CombinePath.hpp" #include "widgets/AccountSwitchPopup.hpp" #include "widgets/dialogs/SettingsDialog.hpp" diff --git a/src/util/Clamp.hpp b/src/util/Clamp.hpp deleted file mode 100644 index 33030f70a..000000000 --- a/src/util/Clamp.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -namespace chatterino { - -// http://en.cppreference.com/w/cpp/algorithm/clamp - -template -constexpr const T &clamp(const T &v, const T &lo, const T &hi) -{ - return assert(!(hi < lo)), (v < lo) ? lo : (hi < v) ? hi : v; -} - -} // namespace chatterino diff --git a/src/util/ConcurrentMap.hpp b/src/util/ConcurrentMap.hpp deleted file mode 100644 index 0346bcae6..000000000 --- a/src/util/ConcurrentMap.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include - -namespace chatterino { - -template -class ConcurrentMap -{ -public: - ConcurrentMap() = default; - - bool tryGet(const TKey &name, TValue &value) const - { - QMutexLocker lock(&this->mutex_); - - auto a = this->data_.find(name); - if (a == this->data_.end()) - { - return false; - } - - value = a.value(); - - return true; - } - - TValue getOrAdd(const TKey &name, std::function addLambda) - { - QMutexLocker lock(&this->mutex_); - - auto a = this->data_.find(name); - if (a == this->data_.end()) - { - TValue value = addLambda(); - this->data_.insert(name, value); - return value; - } - - return a.value(); - } - - TValue &operator[](const TKey &name) - { - QMutexLocker lock(&this->mutex_); - - return this->data_[name]; - } - - void clear() - { - QMutexLocker lock(&this->mutex_); - - this->data_.clear(); - } - - void insert(const TKey &name, const TValue &value) - { - QMutexLocker lock(&this->mutex_); - - this->data_.insert(name, value); - } - - void each( - std::function func) const - { - QMutexLocker lock(&this->mutex_); - - QMapIterator it(this->data_); - - while (it.hasNext()) - { - it.next(); - func(it.key(), it.value()); - } - } - - void each(std::function func) - { - QMutexLocker lock(&this->mutex_); - - QMutableMapIterator it(this->data_); - - while (it.hasNext()) - { - it.next(); - func(it.key(), it.value()); - } - } - -private: - mutable QMutex mutex_; - QMap data_; -}; - -} // namespace chatterino diff --git a/src/util/DisplayBadge.hpp b/src/util/DisplayBadge.hpp index e07e63bbb..69c23bdb7 100644 --- a/src/util/DisplayBadge.hpp +++ b/src/util/DisplayBadge.hpp @@ -3,6 +3,7 @@ #include namespace chatterino { + class DisplayBadge { public: diff --git a/src/util/DistanceBetweenPoints.hpp b/src/util/DistanceBetweenPoints.hpp index 7a2a834cc..332aee87e 100644 --- a/src/util/DistanceBetweenPoints.hpp +++ b/src/util/DistanceBetweenPoints.hpp @@ -6,15 +6,13 @@ namespace chatterino { -inline float distanceBetweenPoints(const QPointF &p1, const QPointF &p2) +inline qreal distanceBetweenPoints(const QPointF &p1, const QPointF &p2) { QPointF tmp = p1 - p2; - float distance = 0.f; - distance += tmp.x() * tmp.x(); - distance += tmp.y() * tmp.y(); + qreal distance = tmp.x() * tmp.x() + tmp.y() * tmp.y(); - return sqrt(distance); + return std::sqrt(distance); } } // namespace chatterino diff --git a/src/util/ExponentialBackoff.hpp b/src/util/ExponentialBackoff.hpp index 44eca67e1..bc7e1ec91 100644 --- a/src/util/ExponentialBackoff.hpp +++ b/src/util/ExponentialBackoff.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include namespace chatterino { @@ -20,7 +19,6 @@ public: **/ ExponentialBackoff(const std::chrono::milliseconds &start) : start_(start) - , step_{1} { static_assert(maxSteps > 1, "maxSteps must be higher than 1"); } @@ -54,7 +52,7 @@ public: private: const std::chrono::milliseconds start_; - unsigned step_; + unsigned step_ = 1; }; } // namespace chatterino diff --git a/src/util/Helpers.cpp b/src/util/Helpers.cpp index 7d66184d1..836214d05 100644 --- a/src/util/Helpers.cpp +++ b/src/util/Helpers.cpp @@ -9,7 +9,7 @@ namespace chatterino { -namespace _helpers_internal { +namespace helpers::detail { SizeType skipSpace(QStringView view, SizeType startPos) { @@ -110,8 +110,8 @@ namespace _helpers_internal { return std::make_pair(0, false); } -} // namespace _helpers_internal -using namespace _helpers_internal; +} // namespace helpers::detail +using namespace helpers::detail; bool startsWithOrContains(const QString &str1, const QString &str2, Qt::CaseSensitivity caseSensitivity, bool startsWith) diff --git a/src/util/Helpers.hpp b/src/util/Helpers.hpp index 6f0552487..02bf572e9 100644 --- a/src/util/Helpers.hpp +++ b/src/util/Helpers.hpp @@ -11,7 +11,7 @@ namespace chatterino { // only qualified for tests -namespace _helpers_internal { +namespace helpers::detail { using SizeType = QStringView::size_type; @@ -52,7 +52,7 @@ namespace _helpers_internal { std::pair findUnitMultiplierToSec(QStringView view, SizeType &pos); -} // namespace _helpers_internal +} // namespace helpers::detail /** * @brief startsWithOrContains is a wrapper for checking diff --git a/src/util/LayoutCreator.hpp b/src/util/LayoutCreator.hpp index 82f729d26..41f605d47 100644 --- a/src/util/LayoutCreator.hpp +++ b/src/util/LayoutCreator.hpp @@ -6,11 +6,12 @@ #include #include -#include +#include namespace chatterino { template + requires std::derived_from || std::derived_from class LayoutCreator { public: @@ -34,49 +35,41 @@ public: return this->item_; } - template - LayoutCreator append(T2 *_item) + template + LayoutCreator append(U *item) { - this->addItem(this->getOrCreateLayout(), _item); + addItem(this->getOrCreateLayout(), item); - return LayoutCreator(_item); + return LayoutCreator(item); } - template - // clang-format off - // clang-format can be enabled once clang-format v11+ has been installed in CI - LayoutCreator emplace(Args &&...args) - // clang-format on + template + LayoutCreator emplace(auto &&...args) { - T2 *t = new T2(std::forward(args)...); + auto *t = new U(std::forward(args)...); - this->addItem(this->getOrCreateLayout(), t); + addItem(this->getOrCreateLayout(), t); - return LayoutCreator(t); + return LayoutCreator(t); } - template ::value, - int>::type = 0> LayoutCreator emplaceScrollAreaWidget() + requires std::derived_from { - QWidget *widget = new QWidget; + auto *widget = new QWidget; this->item_->setWidget(widget); - return LayoutCreator(widget); + return {widget}; } - template ::value, - int>::type = 0, - typename std::enable_if::value, - int>::type = 0> - LayoutCreator setLayoutType() + template U> + LayoutCreator setLayoutType() + requires std::derived_from { - T2 *layout = new T2; + U *layout = new U; this->item_->setLayout(layout); - return LayoutCreator(layout); + return LayoutCreator(layout); } LayoutCreator assign(T **ptr) @@ -86,9 +79,6 @@ public: return *this; } - template ::value, - int>::type = 0> LayoutCreator withoutMargin() { this->item_->setContentsMargins(0, 0, 0, 0); @@ -97,36 +87,31 @@ public: } LayoutCreator withoutSpacing() + requires std::derived_from { this->item_->setSpacing(0); return *this; } - template ::value, - int>::type = 0> LayoutCreator hidden() + requires std::derived_from { this->item_->setVisible(false); return *this; } - template ::value, - int>::type = 0> - LayoutCreator appendTab(T2 *item, const QString &title) + template U> + LayoutCreator appendTab(U *item, const QString &title) + requires std::derived_from { - static_assert(std::is_base_of::value, - "needs to be QLayout"); - - QWidget *widget = new QWidget; + auto *widget = new QWidget; widget->setLayout(item); this->item_->addTab(widget, title); - return LayoutCreator(item); + return LayoutCreator(item); } template @@ -146,36 +131,26 @@ public: private: T *item_; - template ::value, - int>::type = 0> - void addItem(QLayout *layout, T2 *item) + static void addItem(QLayout *layout, QWidget *item) { layout->addWidget(item); } - template ::value, - int>::type = 0> - void addItem(QLayout *layout, T2 *item) + static void addItem(QLayout *layout, QLayout *item) { - QWidget *widget = new QWidget(); + auto *widget = new QWidget(); widget->setLayout(item); layout->addWidget(widget); } - template ::value, - int>::type = 0> QLayout *getOrCreateLayout() + requires std::derived_from { return this->item_; } - template ::value, - int>::type = 0> QLayout *getOrCreateLayout() + requires std::derived_from { if (!this->item_->layout()) { @@ -186,13 +161,10 @@ private: } }; -template -// clang-format off -// clang-format can be enabled once clang-format v11+ has been installed in CI -LayoutCreator makeDialog(Args &&...args) -// clang-format on +template +LayoutCreator makeDialog(auto &&...args) { - T *t = new T(std::forward(args)...); + T *t = new T(std::forward(args)...); t->setAttribute(Qt::WA_DeleteOnClose); return LayoutCreator(t); } diff --git a/src/util/Overloaded.hpp b/src/util/Overloaded.hpp deleted file mode 100644 index e5bc805f5..000000000 --- a/src/util/Overloaded.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -namespace chatterino { - -template -struct Overloaded : Ts... { - using Ts::operator()...; -}; - -template -Overloaded(Ts...) -> Overloaded; - -} // namespace chatterino diff --git a/src/util/PersistSignalVector.hpp b/src/util/PersistSignalVector.hpp deleted file mode 100644 index 9d6d8fd92..000000000 --- a/src/util/PersistSignalVector.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "common/ChatterinoSetting.hpp" -#include "common/SignalVector.hpp" - -#include - -namespace chatterino { - -template -inline void persist(SignalVector &vec, const std::string &name) -{ - auto setting = std::make_unique>>(name); - - for (auto &&item : setting->getValue()) - { - vec.append(item); - } - - vec.delayedItemsChanged.connect([setting = setting.get(), vec = &vec] { - setting->setValue(vec->raw()); - }); - - // TODO: Delete when appropriate. - setting.release(); -} - -} // namespace chatterino diff --git a/src/util/PostToThread.hpp b/src/util/PostToThread.hpp index e0db1fdd0..fa4792941 100644 --- a/src/util/PostToThread.hpp +++ b/src/util/PostToThread.hpp @@ -3,33 +3,9 @@ #include "debug/AssertInGuiThread.hpp" #include -#include -#include - -#include - -#define async_exec(a) \ - QThreadPool::globalInstance()->start(new LambdaRunnable(a)); namespace chatterino { -class LambdaRunnable : public QRunnable -{ -public: - LambdaRunnable(std::function action) - : action_(std::move(action)) - { - } - - void run() override - { - this->action_(); - } - -private: - std::function action_; -}; - // Taken from // https://stackoverflow.com/questions/21646467/how-to-execute-a-functor-or-a-lambda-in-a-given-thread-in-qt-gcd-style // Qt 5/4 - preferred, has least allocations diff --git a/src/util/SplitCommand.cpp b/src/util/SplitCommand.cpp deleted file mode 100644 index 3d71e040f..000000000 --- a/src/util/SplitCommand.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "SplitCommand.hpp" - -#include -#include -#include - -QStringList chatterino::splitCommand(QStringView command) -{ - QStringList args; - QString tmp; - int quoteCount = 0; - bool inQuote = false; - - // handle quoting. tokens can be surrounded by double quotes - // "hello world". three consecutive double quotes represent - // the quote character itself. - for (int i = 0; i < command.size(); ++i) - { - if (command.at(i) == QLatin1Char('"')) - { - ++quoteCount; - if (quoteCount == 3) - { - // third consecutive quote - quoteCount = 0; - tmp += command.at(i); - } - continue; - } - if (quoteCount) - { - if (quoteCount == 1) - { - inQuote = !inQuote; - } - quoteCount = 0; - } - if (!inQuote && command.at(i).isSpace()) - { - if (!tmp.isEmpty()) - { - args += tmp; - tmp.clear(); - } - } - else - { - tmp += command.at(i); - } - } - if (!tmp.isEmpty()) - { - args += tmp; - } - - return args; -} diff --git a/src/util/SplitCommand.hpp b/src/util/SplitCommand.hpp deleted file mode 100644 index 9db79c727..000000000 --- a/src/util/SplitCommand.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include -#include - -namespace chatterino { - -// Splits the string command into a list of tokens, and returns the list. -// Tokens with spaces can be surrounded by double quotes; -// three consecutive double quotes represent the quote character itself. -// -// Backported from QProcess 5.15 -QStringList splitCommand(QStringView command); - -} // namespace chatterino diff --git a/src/util/StreamLink.cpp b/src/util/StreamLink.cpp index a3596f9b4..b4e4370d2 100644 --- a/src/util/StreamLink.cpp +++ b/src/util/StreamLink.cpp @@ -7,7 +7,6 @@ #include "singletons/Settings.hpp" #include "singletons/WindowManager.hpp" #include "util/Helpers.hpp" -#include "util/SplitCommand.hpp" #include "widgets/dialogs/QualityPopup.hpp" #include "widgets/splits/Split.hpp" #include "widgets/Window.hpp" @@ -162,16 +161,16 @@ void openStreamlink(const QString &channelURL, const QString &quality, { auto *proc = createStreamlinkProcess(); auto arguments = proc->arguments() - << extraArguments << channelURL << quality; + << std::move(extraArguments) << channelURL << quality; // Remove empty arguments before appending additional streamlink options // as the options might purposely contain empty arguments arguments.removeAll(QString()); QString additionalOptions = getSettings()->streamlinkOpts.getValue(); - arguments << splitCommand(additionalOptions); + arguments << QProcess::splitCommand(additionalOptions); - proc->setArguments(std::move(arguments)); + proc->setArguments(arguments); bool res = proc->startDetached(); if (!res) diff --git a/src/widgets/settingspages/ModerationPage.cpp b/src/widgets/settingspages/ModerationPage.cpp index 95669cce9..c00c03667 100644 --- a/src/widgets/settingspages/ModerationPage.cpp +++ b/src/widgets/settingspages/ModerationPage.cpp @@ -274,17 +274,16 @@ ModerationPage::ModerationPage() }); } - this->addModerationButtonSettings(tabs); + this->addModerationButtonSettings(tabs.getElement()); // ---- misc this->itemsChangedTimer_.setSingleShot(true); } -void ModerationPage::addModerationButtonSettings( - LayoutCreator &tabs) +void ModerationPage::addModerationButtonSettings(QTabWidget *tabs) { auto timeoutLayout = - tabs.appendTab(new QVBoxLayout, "User Timeout Buttons"); + LayoutCreator{tabs}.appendTab(new QVBoxLayout, "User Timeout Buttons"); auto texts = timeoutLayout.emplace().withoutMargin(); { auto infoLabel = texts.emplace(); diff --git a/src/widgets/settingspages/ModerationPage.hpp b/src/widgets/settingspages/ModerationPage.hpp index 24662ec0d..88a251d8e 100644 --- a/src/widgets/settingspages/ModerationPage.hpp +++ b/src/widgets/settingspages/ModerationPage.hpp @@ -9,9 +9,6 @@ class QPushButton; namespace chatterino { -template -class LayoutCreator; - class ModerationPage : public SettingsPage { public: @@ -20,7 +17,7 @@ public: void selectModerationActions(); private: - void addModerationButtonSettings(LayoutCreator &); + void addModerationButtonSettings(QTabWidget *); QTimer itemsChangedTimer_; QTabWidget *tabWidget_{}; diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 66940b280..29ed3929f 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -12,7 +12,6 @@ #include "providers/twitch/TwitchIrcServer.hpp" #include "singletons/Settings.hpp" #include "singletons/Theme.hpp" -#include "util/Clamp.hpp" #include "util/Helpers.hpp" #include "util/LayoutCreator.hpp" #include "widgets/dialogs/EmotePopup.hpp" @@ -811,7 +810,7 @@ void SplitInput::updateCompletionPopup() return; } - for (int i = clamp(position, 0, (int)text.length() - 1); i >= 0; i--) + for (int i = std::clamp(position, 0, (int)text.length() - 1); i >= 0; i--) { if (text[i] == ' ') { @@ -894,7 +893,7 @@ void SplitInput::insertCompletionText(const QString &input_) const auto text = edit.toPlainText(); auto position = edit.textCursor().position() - 1; - for (int i = clamp(position, 0, (int)text.length() - 1); i >= 0; i--) + for (int i = std::clamp(position, 0, (int)text.length() - 1); i >= 0; i--) { bool done = false; if (text[i] == ':') diff --git a/tests/src/Helpers.cpp b/tests/src/Helpers.cpp index a98868bfa..4327bf51a 100644 --- a/tests/src/Helpers.cpp +++ b/tests/src/Helpers.cpp @@ -3,7 +3,7 @@ #include "Test.hpp" using namespace chatterino; -using namespace _helpers_internal; +using namespace helpers::detail; TEST(Helpers, formatUserMention) { From 4a7a5b09ceebea0da3dcf279d6ec52194e636f82 Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 20 Jul 2024 12:06:23 +0200 Subject: [PATCH 16/63] fix: disallow more characters in links (#5509) --- CHANGELOG.md | 1 + src/common/LinkParser.cpp | 15 +++++++++++++++ tests/src/LinkParser.cpp | 32 +++++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3d0e1f0f..f8b104bcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - Bugfix: Fixed user info card popups adding duplicate line to log files. (#5499) - Bugfix: Fixed `/clearmessages` not working with more than one window. (#5489) - Bugfix: Fixed splits staying paused after unfocusing Chatterino in certain configurations. (#5504) +- Bugfix: Links with invalid characters in the domain are no longer detected. (#5509) - Dev: Update Windows build from Qt 6.5.0 to Qt 6.7.1. (#5420) - Dev: Update vcpkg build Qt from 6.5.0 to 6.7.0, boost from 1.83.0 to 1.85.0, openssl from 3.1.3 to 3.3.0. (#5422) - Dev: Unsingletonize `ISoundController`. (#5462) diff --git a/src/common/LinkParser.cpp b/src/common/LinkParser.cpp index ecc8fb751..eed4f97c1 100644 --- a/src/common/LinkParser.cpp +++ b/src/common/LinkParser.cpp @@ -148,6 +148,16 @@ void strip(QStringView &source) } } +/// @brief Checks if @a c is valid in a domain +/// +/// Valid characters are 0-9, A-Z, a-z, '-', '_', and '.' (like in GFM) +/// and all non-ASCII characters (unlike in GFM). +Q_ALWAYS_INLINE bool isValidDomainChar(char16_t c) +{ + return c >= 0x80 || (u'0' <= c && c <= u'9') || (u'A' <= c && c <= u'Z') || + (u'a' <= c && c <= u'z') || c == u'_' || c == u'-' || c == u'.'; +} + } // namespace namespace chatterino::linkparser { @@ -233,6 +243,11 @@ std::optional parse(const QString &source) noexcept rest = remaining.mid(i); break; } + + if (!isValidDomainChar(currentChar)) + { + return result; + } } if (lastWasDot || lastDotPos <= 0) diff --git a/tests/src/LinkParser.cpp b/tests/src/LinkParser.cpp index 746486c97..72748d689 100644 --- a/tests/src/LinkParser.cpp +++ b/tests/src/LinkParser.cpp @@ -1,11 +1,13 @@ #include "common/LinkParser.hpp" +#include "common/Literals.hpp" #include "Test.hpp" #include #include using namespace chatterino; +using namespace literals; struct Case { // -Wmissing-field-initializers complains otherwise @@ -91,6 +93,14 @@ TEST(LinkParser, parseDomainLinks) {"", "a.com", "?("}, {"", "a.com", "#("}, {"", "a.com", "/__my_user__"}, + {"", "a.b.c.-._.1.com", ""}, + {"", "0123456789.com", ""}, + {"", "ABCDEFGHIJKLMNOPQRSTUVWXYZ.com", ""}, + {"", "abcdefghijklmnopqrstuvwxyz.com", ""}, + // non-ASCII characters are allowed + {"", u"köln.de"_s, ""}, + {"", u"ü.com"_s, ""}, + {"", u"─.com"_s, ""}, // test case-insensitiveness {"HtTpS://", "127.0.0.1.CoM"}, {"HTTP://", "XD.CHATTERINO.COM", "/#?FOO"}, @@ -168,6 +178,7 @@ TEST(LinkParser, doesntParseInvalidIpv4Links) "196.162.8.1(())", "196.162.8.1(", "196.162.8.1(!", + "127.1.1;.com", }; for (const auto &input : inputs) @@ -219,11 +230,22 @@ TEST(LinkParser, doesntParseInvalidLinks) "~~a.com()", "https://chatterino.com>", - // invalid characters are still accepted (see #4769) - // "chatterino.com>", - // "", + "chatterino.com>", + "", + "info@example.com", + "user:pass@example.com", + ":.com", + "a:.com", + "1:.com", + "[a].com", + "`a`.com", + "{a}.com", + "a.com:pass@example.com", + "@@@.com", + "%%%.com", + "*.com", }; for (const auto &input : inputs) From 0495fbca43187947ca0bf4a8ed9b0015056644b5 Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 20 Jul 2024 14:19:27 +0200 Subject: [PATCH 17/63] feat: add option to suppress live notifications on startup (#5388) --- CHANGELOG.md | 1 + src/controllers/commands/builtin/Misc.cpp | 2 +- .../notifications/NotificationController.cpp | 258 ++++++++++-------- .../notifications/NotificationController.hpp | 50 +++- src/controllers/twitch/LiveController.cpp | 10 +- src/controllers/twitch/LiveController.hpp | 7 +- src/providers/twitch/TwitchChannel.cpp | 126 +++------ src/providers/twitch/TwitchChannel.hpp | 13 +- src/singletons/Settings.hpp | 2 + src/util/QCompareCaseInsensitive.hpp | 144 ++++++++++ .../settingspages/NotificationPage.cpp | 10 +- 11 files changed, 398 insertions(+), 225 deletions(-) create mode 100644 src/util/QCompareCaseInsensitive.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index f8b104bcb..6c67b1856 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - Minor: Add channel points indication for new bits power-up redemptions. (#5471) - Minor: Added option to log streams by their ID, allowing for easier "per-stream" log analyzing. (#5507) - Minor: Added `/warn ` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474) +- Minor: Added option to suppress live notifictions on startup. (#5388) - Minor: Improve appearance of reply button. (#5491) - Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) - Minor: Support more Firefox variants for incognito link opening. (#5503) diff --git a/src/controllers/commands/builtin/Misc.cpp b/src/controllers/commands/builtin/Misc.cpp index a7fcc7662..9be6438ce 100644 --- a/src/controllers/commands/builtin/Misc.cpp +++ b/src/controllers/commands/builtin/Misc.cpp @@ -587,7 +587,7 @@ QString injectStreamUpdateNoStream(const CommandContext &ctx) return ""; } - ctx.twitchChannel->updateStreamStatus(std::nullopt); + ctx.twitchChannel->updateStreamStatus(std::nullopt, false); return ""; } diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 1e30a7497..1fe0036a7 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -13,23 +13,14 @@ #include "singletons/Toasts.hpp" #include "singletons/WindowManager.hpp" #include "util/Helpers.hpp" -#include "widgets/Window.hpp" -#ifdef Q_OS_WIN -# include -#endif - -#include -#include #include -#include - +namespace ranges = std::ranges; namespace chatterino { void NotificationController::initialize(Settings &settings, const Paths &paths) { - this->initialized_ = true; for (const QString &channelName : this->twitchSetting_.getValue()) { this->channelMap[Platform::Twitch].append(channelName); @@ -43,40 +34,33 @@ void NotificationController::initialize(Settings &settings, const Paths &paths) this->channelMap[Platform::Twitch].raw()); }); - liveStatusTimer_ = new QTimer(); - this->fetchFakeChannels(); - QObject::connect(this->liveStatusTimer_, &QTimer::timeout, [this] { + QObject::connect(&this->liveStatusTimer_, &QTimer::timeout, [this] { this->fetchFakeChannels(); }); - this->liveStatusTimer_->start(60 * 1000); + this->liveStatusTimer_.start(60 * 1000); } void NotificationController::updateChannelNotification( const QString &channelName, Platform p) { - if (isChannelNotified(channelName, p)) + if (this->isChannelNotified(channelName, p)) { - removeChannelNotification(channelName, p); + this->removeChannelNotification(channelName, p); } else { - addChannelNotification(channelName, p); + this->addChannelNotification(channelName, p); } } bool NotificationController::isChannelNotified(const QString &channelName, - Platform p) + Platform p) const { - for (const auto &channel : this->channelMap[p]) - { - if (channelName.toLower() == channel.toLower()) - { - return true; - } - } - return false; + return ranges::any_of(channelMap.at(p).raw(), [&](const auto &name) { + return name.compare(channelName, Qt::CaseInsensitive) == 0; + }); } void NotificationController::addChannelNotification(const QString &channelName, @@ -91,14 +75,16 @@ void NotificationController::removeChannelNotification( for (std::vector::size_type i = 0; i != channelMap[p].raw().size(); i++) { - if (channelMap[p].raw()[i].toLower() == channelName.toLower()) + if (channelMap[p].raw()[i].compare(channelName, Qt::CaseInsensitive) == + 0) { - channelMap[p].removeAt(i); + channelMap[p].removeAt(static_cast(i)); i--; } } } -void NotificationController::playSound() + +void NotificationController::playSound() const { QUrl highlightSoundUrl = getSettings()->notificationCustomSound @@ -112,23 +98,93 @@ void NotificationController::playSound() NotificationModel *NotificationController::createModel(QObject *parent, Platform p) { - NotificationModel *model = new NotificationModel(parent); + auto *model = new NotificationModel(parent); model->initialize(&this->channelMap[p]); return model; } +void NotificationController::notifyTwitchChannelLive( + const NotificationPayload &payload) const +{ + bool showNotification = + !(getSettings()->suppressInitialLiveNotification && + payload.isInitialUpdate) && + !(getIApp()->getStreamerMode()->isEnabled() && + getSettings()->streamerModeSuppressLiveNotifications); + bool playedSound = false; + + if (showNotification && + this->isChannelNotified(payload.channelName, Platform::Twitch)) + { + if (Toasts::isEnabled()) + { + getIApp()->getToasts()->sendChannelNotification( + payload.channelName, payload.title, Platform::Twitch); + } + if (getSettings()->notificationPlaySound) + { + this->playSound(); + playedSound = true; + } + if (getSettings()->notificationFlashTaskbar) + { + getIApp()->getWindows()->sendAlert(); + } + } + + // Message in /live channel + MessageBuilder builder; + TwitchMessageBuilder::liveMessage(payload.displayName, &builder); + builder.message().id = payload.channelId; + getIApp()->getTwitch()->getLiveChannel()->addMessage( + builder.release(), MessageContext::Original); + + // Notify on all channels with a ping sound + if (showNotification && !playedSound && + getSettings()->notificationOnAnyChannel) + { + this->playSound(); + } +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +void NotificationController::notifyTwitchChannelOffline(const QString &id) const +{ + // "delete" old 'CHANNEL is live' message + LimitedQueueSnapshot snapshot = + getIApp()->getTwitch()->getLiveChannel()->getMessageSnapshot(); + int snapshotLength = static_cast(snapshot.size()); + + int end = std::max(0, snapshotLength - 200); + + for (int i = snapshotLength - 1; i >= end; --i) + { + const auto &s = snapshot[i]; + + if (s->id == id) + { + s->flags.set(MessageFlag::Disabled); + break; + } + } +} + void NotificationController::fetchFakeChannels() { qCDebug(chatterinoNotification) << "fetching fake channels"; + QStringList channels; - for (std::vector::size_type i = 0; - i < channelMap[Platform::Twitch].raw().size(); i++) + for (size_t i = 0; i < channelMap[Platform::Twitch].raw().size(); i++) { - auto chan = getIApp()->getTwitchAbstract()->getChannelOrEmpty( - channelMap[Platform::Twitch].raw()[i]); + const auto &name = channelMap[Platform::Twitch].raw()[i]; + auto chan = getIApp()->getTwitchAbstract()->getChannelOrEmpty(name); if (chan->isEmpty()) { - channels.push_back(channelMap[Platform::Twitch].raw()[i]); + channels.push_back(name); + } + else + { + this->fakeChannels_.erase(name); } } @@ -136,17 +192,26 @@ void NotificationController::fetchFakeChannels() { getHelix()->fetchStreams( {}, batch, - [batch, this](std::vector streams) { - std::unordered_set liveStreams; + [batch, this](const auto &streams) { + std::map, + QCompareCaseInsensitive> + liveStreams; for (const auto &stream : streams) { - liveStreams.insert(stream.userLogin); + liveStreams.emplace(stream.userLogin, stream); } for (const auto &name : batch) { - auto it = liveStreams.find(name.toLower()); - this->checkStream(it != liveStreams.end(), name); + auto it = liveStreams.find(name); + if (it == liveStreams.end()) + { + this->updateFakeChannel(name, std::nullopt); + } + else + { + this->updateFakeChannel(name, it->second); + } } }, [batch]() { @@ -159,85 +224,56 @@ void NotificationController::fetchFakeChannels() }); } } -void NotificationController::checkStream(bool live, QString channelName) +void NotificationController::updateFakeChannel( + const QString &channelName, const std::optional &stream) { - qCDebug(chatterinoNotification) - << "[TwitchChannel" << channelName << "] Refreshing live status"; + bool live = stream.has_value(); + qCDebug(chatterinoNotification).nospace().noquote() + << "[FakeTwitchChannel " << channelName + << "] New live status: " << stream.has_value(); + auto channelIt = this->fakeChannels_.find(channelName); + bool isInitialUpdate = false; + if (channelIt == this->fakeChannels_.end()) + { + channelIt = this->fakeChannels_ + .emplace(channelName, + FakeChannel{ + .id = {}, + .isLive = live, + }) + .first; + isInitialUpdate = true; + } + if (channelIt->second.isLive == live && !isInitialUpdate) + { + return; // nothing changed + } + + if (live && channelIt->second.id.isNull()) + { + channelIt->second.id = stream->userId; + } + + channelIt->second.isLive = live; + + // Similar code can be found in TwitchChannel::onLiveStatusChange. + // Since this is a fake channel, we don't send a live message in the + // TwitchChannel. if (!live) { // Stream is offline - this->removeFakeChannel(channelName); + this->notifyTwitchChannelOffline(channelIt->second.id); return; } - // Stream is online - auto i = std::find(fakeTwitchChannels.begin(), fakeTwitchChannels.end(), - channelName); - - if (i != fakeTwitchChannels.end()) - { - // We have already pushed the live state of this stream - // Could not find stream in fake Twitch channels! - return; - } - - if (Toasts::isEnabled()) - { - getIApp()->getToasts()->sendChannelNotification(channelName, QString(), - Platform::Twitch); - } - bool inStreamerMode = getIApp()->getStreamerMode()->isEnabled(); - if (getSettings()->notificationPlaySound && - !(inStreamerMode && - getSettings()->streamerModeSuppressLiveNotifications)) - { - getIApp()->getNotifications()->playSound(); - } - if (getSettings()->notificationFlashTaskbar && - !(inStreamerMode && - getSettings()->streamerModeSuppressLiveNotifications)) - { - getIApp()->getWindows()->sendAlert(); - } - MessageBuilder builder; - TwitchMessageBuilder::liveMessage(channelName, &builder); - getIApp()->getTwitch()->getLiveChannel()->addMessage( - builder.release(), MessageContext::Original); - - // Indicate that we have pushed notifications for this stream - fakeTwitchChannels.push_back(channelName); -} - -void NotificationController::removeFakeChannel(const QString channelName) -{ - auto it = std::find(fakeTwitchChannels.begin(), fakeTwitchChannels.end(), - channelName); - if (it != fakeTwitchChannels.end()) - { - fakeTwitchChannels.erase(it); - // "delete" old 'CHANNEL is live' message - LimitedQueueSnapshot snapshot = - getIApp()->getTwitch()->getLiveChannel()->getMessageSnapshot(); - int snapshotLength = snapshot.size(); - - // MSVC hates this code if the parens are not there - int end = (std::max)(0, snapshotLength - 200); - // this assumes that channelName is a login name therefore will only delete messages from fake channels - auto liveMessageSearchText = QString("%1 is live!").arg(channelName); - - for (int i = snapshotLength - 1; i >= end; --i) - { - const auto &s = snapshot[i]; - - if (QString::compare(s->messageText, liveMessageSearchText, - Qt::CaseInsensitive) == 0) - { - s->flags.set(MessageFlag::Disabled); - break; - } - } - } + this->notifyTwitchChannelLive({ + .channelId = stream->userId, + .channelName = channelName, + .displayName = stream->userName, + .title = stream->title, + .isInitialUpdate = isInitialUpdate, + }); } } // namespace chatterino diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index ad70e029f..fa802c1ec 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -3,6 +3,7 @@ #include "common/ChatterinoSetting.hpp" #include "common/SignalVector.hpp" #include "common/Singleton.hpp" +#include "util/QCompareCaseInsensitive.hpp" #include @@ -10,6 +11,7 @@ namespace chatterino { class Settings; class Paths; +struct HelixStream; class NotificationModel; @@ -17,34 +19,58 @@ enum class Platform : uint8_t { Twitch, // 0 }; -class NotificationController final : public Singleton, private QObject +class NotificationController final : public Singleton { public: void initialize(Settings &settings, const Paths &paths) override; - bool isChannelNotified(const QString &channelName, Platform p); + bool isChannelNotified(const QString &channelName, Platform p) const; void updateChannelNotification(const QString &channelName, Platform p); void addChannelNotification(const QString &channelName, Platform p); void removeChannelNotification(const QString &channelName, Platform p); - void playSound(); + struct NotificationPayload { + QString channelId; + QString channelName; + QString displayName; + QString title; + bool isInitialUpdate = false; + }; - SignalVector getVector(Platform p); + /// @brief Sends out notifications for a channel that has gone live + /// + /// This doesn't check for duplicate notifications. + void notifyTwitchChannelLive(const NotificationPayload &payload) const; - std::map> channelMap; + /// @brief Sends out notifications for a channel that has gone offline + /// + /// This doesn't check for duplicate notifications. + void notifyTwitchChannelOffline(const QString &id) const; + + void playSound() const; NotificationModel *createModel(QObject *parent, Platform p); private: - bool initialized_ = false; - void fetchFakeChannels(); - void removeFakeChannel(const QString channelName); - void checkStream(bool live, QString channelName); + void removeFakeChannel(const QString &channelName); + void updateFakeChannel(const QString &channelName, + const std::optional &stream); - // fakeTwitchChannels is a list of streams who are live that we have already sent out a notification for - std::vector fakeTwitchChannels; - QTimer *liveStatusTimer_; + struct FakeChannel { + QString id; + bool isLive = false; + }; + + /// @brief This map tracks channels without an associated TwitchChannel + /// + /// These channels won't be tracked in LiveController. + /// Channels are identified by their login name (case insensitive). + std::map fakeChannels_; + + QTimer liveStatusTimer_; + + std::map> channelMap; ChatterinoSetting> twitchSetting_ = { "/notifications/twitch"}; diff --git a/src/controllers/twitch/LiveController.cpp b/src/controllers/twitch/LiveController.cpp index c531ebe6f..d574bf867 100644 --- a/src/controllers/twitch/LiveController.cpp +++ b/src/controllers/twitch/LiveController.cpp @@ -56,7 +56,7 @@ void TwitchLiveController::add(const std::shared_ptr &newChannel) { std::unique_lock lock(this->channelsMutex); - this->channels[channelID] = newChannel; + this->channels[channelID] = {.ptr = newChannel, .wasChecked = false}; } { @@ -120,9 +120,11 @@ void TwitchLiveController::request(std::optional optChannelIDs) auto it = this->channels.find(result.first); if (it != channels.end()) { - if (auto channel = it->second.lock(); channel) + if (auto channel = it->second.ptr.lock(); channel) { - channel->updateStreamStatus(result.second); + channel->updateStreamStatus( + result.second, !it->second.wasChecked); + it->second.wasChecked = true; } else { @@ -159,7 +161,7 @@ void TwitchLiveController::request(std::optional optChannelIDs) auto it = this->channels.find(helixChannel.userId); if (it != this->channels.end()) { - if (auto channel = it->second.lock(); channel) + if (auto channel = it->second.ptr.lock(); channel) { channel->updateStreamTitle(helixChannel.title); channel->updateDisplayName(helixChannel.name); diff --git a/src/controllers/twitch/LiveController.hpp b/src/controllers/twitch/LiveController.hpp index 79befd62d..94b538957 100644 --- a/src/controllers/twitch/LiveController.hpp +++ b/src/controllers/twitch/LiveController.hpp @@ -49,6 +49,11 @@ public: void add(const std::shared_ptr &newChannel) override; private: + struct ChannelEntry { + std::weak_ptr ptr; + bool wasChecked = false; + }; + /** * Run batched Helix Channels & Stream requests for channels * @@ -64,7 +69,7 @@ private: * * These channels will have their stream status updated every REFRESH_INTERVAL seconds **/ - std::unordered_map> channels; + std::unordered_map channels; std::shared_mutex channelsMutex; /** diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index cd293630d..4f553f039 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -133,86 +133,6 @@ TwitchChannel::TwitchChannel(const QString &name) }); this->threadClearTimer_.start(5 * 60 * 1000); - auto onLiveStatusChanged = [this](auto isLive) { - if (isLive) - { - qCDebug(chatterinoTwitch) - << "[TwitchChannel" << this->getName() << "] Online"; - if (getIApp()->getNotifications()->isChannelNotified( - this->getName(), Platform::Twitch)) - { - if (Toasts::isEnabled()) - { - getIApp()->getToasts()->sendChannelNotification( - this->getName(), this->accessStreamStatus()->title, - Platform::Twitch); - } - if (getSettings()->notificationPlaySound) - { - getIApp()->getNotifications()->playSound(); - } - if (getSettings()->notificationFlashTaskbar) - { - getIApp()->getWindows()->sendAlert(); - } - } - // Channel live message - MessageBuilder builder; - TwitchMessageBuilder::liveSystemMessage(this->getDisplayName(), - &builder); - builder.message().id = this->roomId(); - this->addMessage(builder.release(), MessageContext::Original); - - // Message in /live channel - MessageBuilder builder2; - TwitchMessageBuilder::liveMessage(this->getDisplayName(), - &builder2); - builder2.message().id = this->roomId(); - getIApp()->getTwitch()->getLiveChannel()->addMessage( - builder2.release(), MessageContext::Original); - - // Notify on all channels with a ping sound - if (getSettings()->notificationOnAnyChannel && - !(getIApp()->getStreamerMode()->isEnabled() && - getSettings()->streamerModeSuppressLiveNotifications)) - { - getIApp()->getNotifications()->playSound(); - } - } - else - { - qCDebug(chatterinoTwitch) - << "[TwitchChannel" << this->getName() << "] Offline"; - // Channel offline message - MessageBuilder builder; - TwitchMessageBuilder::offlineSystemMessage(this->getDisplayName(), - &builder); - this->addMessage(builder.release(), MessageContext::Original); - - // "delete" old 'CHANNEL is live' message - LimitedQueueSnapshot snapshot = - getIApp()->getTwitch()->getLiveChannel()->getMessageSnapshot(); - int snapshotLength = snapshot.size(); - - // MSVC hates this code if the parens are not there - int end = (std::max)(0, snapshotLength - 200); - - for (int i = snapshotLength - 1; i >= end; --i) - { - const auto &s = snapshot[i]; - - if (s->id == this->roomId()) - { - s->flags.set(MessageFlag::Disabled); - break; - } - } - } - }; - - this->signalHolder_.managedConnect(this->liveStatusChanged, - onLiveStatusChanged); - // debugging #if 0 for (int i = 0; i < 1000; i++) { @@ -450,7 +370,7 @@ std::optional TwitchChannel::channelPointReward( } void TwitchChannel::updateStreamStatus( - const std::optional &helixStream) + const std::optional &helixStream, bool isInitialUpdate) { if (helixStream) { @@ -483,7 +403,7 @@ void TwitchChannel::updateStreamStatus( } if (this->setLive(true)) { - this->liveStatusChanged.invoke(true); + this->onLiveStatusChanged(true, isInitialUpdate); } this->streamStatusChanged.invoke(); } @@ -491,12 +411,52 @@ void TwitchChannel::updateStreamStatus( { if (this->setLive(false)) { - this->liveStatusChanged.invoke(false); + this->onLiveStatusChanged(false, isInitialUpdate); this->streamStatusChanged.invoke(); } } } +void TwitchChannel::onLiveStatusChanged(bool isLive, bool isInitialUpdate) +{ + // Similar code exists in NotificationController::updateFakeChannel. + // Since we're a TwitchChannel, we also send a message here. + if (isLive) + { + qCDebug(chatterinoTwitch).nospace().noquote() + << "[TwitchChannel " << this->getName() << "] Online"; + + getIApp()->getNotifications()->notifyTwitchChannelLive({ + .channelId = this->roomId(), + .channelName = this->getName(), + .displayName = this->getDisplayName(), + .title = this->accessStreamStatus()->title, + .isInitialUpdate = isInitialUpdate, + }); + + // Channel live message + MessageBuilder builder; + TwitchMessageBuilder::liveSystemMessage(this->getDisplayName(), + &builder); + builder.message().id = this->roomId(); + this->addMessage(builder.release(), MessageContext::Original); + } + else + { + qCDebug(chatterinoTwitch).nospace().noquote() + << "[TwitchChannel " << this->getName() << "] Offline"; + + // Channel offline message + MessageBuilder builder; + TwitchMessageBuilder::offlineSystemMessage(this->getDisplayName(), + &builder); + this->addMessage(builder.release(), MessageContext::Original); + + getIApp()->getNotifications()->notifyTwitchChannelOffline( + this->roomId()); + } +}; + void TwitchChannel::updateStreamTitle(const QString &title) { { diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index e3d1e96d8..2617d95a6 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -238,14 +238,6 @@ public: // Only TwitchChannel may invoke this signal pajlada::Signals::NoArgSignal userStateChanged; - /** - * This signals fires whenever the live status is changed - * - * Streams are counted as offline by default, so if a stream does not go online - * this signal will never fire - **/ - pajlada::Signals::Signal liveStatusChanged; - /** * This signal fires whenever the stream status is changed * @@ -270,7 +262,8 @@ public: const QString &rewardId) const; // Live status - void updateStreamStatus(const std::optional &helixStream); + void updateStreamStatus(const std::optional &helixStream, + bool isInitialUpdate); void updateStreamTitle(const QString &title); /** @@ -338,6 +331,8 @@ private: void setDisplayName(const QString &name); void setLocalizedName(const QString &name); + void onLiveStatusChanged(bool isLive, bool isInitialUpdate); + /** * Returns the localized name of the user **/ diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 98ec53ed8..29f9cce01 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -475,6 +475,8 @@ public: "qrc:/sounds/ping3.wav"}; BoolSetting notificationOnAnyChannel = {"/notifications/onAnyChannel", false}; + BoolSetting suppressInitialLiveNotification = { + "/notifications/suppressInitialLive", false}; BoolSetting notificationToast = {"/notifications/enableToast", false}; IntSetting openFromToast = {"/notifications/openFromToast", diff --git a/src/util/QCompareCaseInsensitive.hpp b/src/util/QCompareCaseInsensitive.hpp new file mode 100644 index 000000000..70e8a1a01 --- /dev/null +++ b/src/util/QCompareCaseInsensitive.hpp @@ -0,0 +1,144 @@ +#pragma once + +#include +#include +#include +#include + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) +# include +#endif + +namespace chatterino { + +/// Case insensitive transparent comparator for Qt's string types +struct QCompareCaseInsensitive { + using is_transparent = void; + + // clang-format off + bool operator()(const QString & a, const QString & b) const noexcept; + bool operator()(QStringView a, QStringView b) const noexcept; + bool operator()(QLatin1String a, QLatin1String b) const noexcept; + + bool operator()(const QString & a, QStringView b) const noexcept; + bool operator()(const QString & a, QLatin1String b) const noexcept; + + bool operator()(QStringView a, const QString & b) const noexcept; + bool operator()(QLatin1String a, const QString & b) const noexcept; + + bool operator()(QStringView a, QLatin1String b) const noexcept; + bool operator()(QLatin1String a, QStringView b) const noexcept; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + bool operator()(QUtf8StringView a, QUtf8StringView b) const noexcept; + + bool operator()(const QString & a, QUtf8StringView b) const noexcept; + bool operator()(QStringView a, QUtf8StringView b) const noexcept; + bool operator()(QLatin1String a, QUtf8StringView b) const noexcept; + + bool operator()(QUtf8StringView a, const QString & b) const noexcept; + bool operator()(QUtf8StringView a, QStringView b) const noexcept; + bool operator()(QUtf8StringView a, QLatin1String b) const noexcept; +#endif + // clang-format on +}; + +inline bool QCompareCaseInsensitive::operator()(const QString &a, + const QString &b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(QStringView a, + QStringView b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(QLatin1String a, + QLatin1String b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(const QString &a, + QStringView b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(const QString &a, + QLatin1String b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(QStringView a, + const QString &b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(QLatin1String a, + const QString &b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(QStringView a, + QLatin1String b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(QLatin1String a, + QStringView b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) +inline bool QCompareCaseInsensitive::operator()( + QUtf8StringView a, QUtf8StringView b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()( + const QString &a, QUtf8StringView b) const noexcept +{ + return QStringView{a}.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()( + QStringView a, QUtf8StringView b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()( + QLatin1String a, QUtf8StringView b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(QUtf8StringView a, + const QString &b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(QUtf8StringView a, + QStringView b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} + +inline bool QCompareCaseInsensitive::operator()(QUtf8StringView a, + QLatin1String b) const noexcept +{ + return a.compare(b, Qt::CaseInsensitive) < 0; +} +#endif + +} // namespace chatterino diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index d5bb2f7b8..c306e7176 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -42,6 +42,10 @@ NotificationPage::NotificationPage() settings.append(this->createCheckBox( "Play sound for any channel going live", getSettings()->notificationOnAnyChannel)); + + settings.append(this->createCheckBox( + "Suppress live notifications on startup", + getSettings()->suppressInitialLiveNotification)); #ifdef Q_OS_WIN settings.append(this->createCheckBox( "Show notification", getSettings()->notificationToast)); @@ -111,10 +115,8 @@ NotificationPage::NotificationPage() // We can safely ignore this signal connection since we own the view std::ignore = view->addButtonPressed.connect([] { - getApp() - ->getNotifications() - ->channelMap[Platform::Twitch] - .append("channel"); + getApp()->getNotifications()->addChannelNotification( + "channel", Platform::Twitch); }); } } From 44abb1901fc1a9b9437e2db45ecbacea48c09541 Mon Sep 17 00:00:00 2001 From: nerix Date: Sun, 21 Jul 2024 00:49:46 +0200 Subject: [PATCH 18/63] fix: restore input layout (almost) (#5519) --- CHANGELOG.md | 2 +- src/widgets/splits/SplitInput.cpp | 55 ++++++++++++++++++------------- src/widgets/splits/SplitInput.hpp | 4 +++ 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c67b1856..14925cab2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ - Minor: Improve appearance of reply button. (#5491) - Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) - Minor: Support more Firefox variants for incognito link opening. (#5503) -- Minor: Replying to a message will now display the message being replied to. (#4350) +- Minor: Replying to a message will now display the message being replied to. (#4350, #5519) - Minor: Links can now have prefixes and suffixes such as parentheses. (#5486) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 29ed3929f..17eb40418 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -84,27 +84,26 @@ void SplitInput::initLayout() layoutCreator.setLayoutType().withoutMargin().assign( &this->ui_.vbox); layout->setSpacing(0); - auto marginPx = this->marginForTheme(); - layout->setContentsMargins(marginPx, marginPx, marginPx, marginPx); + this->applyOuterMargin(); // reply label stuff auto replyWrapper = layout.emplace().assign(&this->ui_.replyWrapper); - replyWrapper->setContentsMargins(0, 0, 0, 0); + replyWrapper->setContentsMargins(0, 0, 1, 1); auto replyVbox = replyWrapper.setLayoutType().withoutMargin().assign( &this->ui_.replyVbox); - replyVbox->setSpacing(0); + replyVbox->setSpacing(1); auto replyHbox = replyVbox.emplace().assign(&this->ui_.replyHbox); auto messageVbox = layoutCreator.setLayoutType(); this->ui_.replyMessage = new MessageView(); - messageVbox->addWidget(this->ui_.replyMessage, 1, Qt::AlignLeft); + messageVbox->addWidget(this->ui_.replyMessage, 0, Qt::AlignLeft); messageVbox->setContentsMargins(10, 0, 0, 0); - replyVbox->addLayout(messageVbox->layout(), 1); + replyVbox->addLayout(messageVbox->layout(), 0); auto replyLabel = replyHbox.emplace().assign(&this->ui_.replyLabel); replyLabel->setAlignment(Qt::AlignLeft); @@ -122,7 +121,7 @@ void SplitInput::initLayout() auto inputWrapper = layout.emplace().assign(&this->ui_.inputWrapper); - inputWrapper->setContentsMargins(0, 0, 0, 0); + inputWrapper->setContentsMargins(1, 1, 1, 1); // hbox for input, right box auto hboxLayout = @@ -231,7 +230,7 @@ void SplitInput::scaleChangedEvent(float scale) this->setMaximumHeight(this->scaledMaxHeight()); if (this->replyTarget_ != nullptr) { - this->ui_.vbox->setSpacing(this->marginForTheme() * 2); + this->ui_.vbox->setSpacing(this->marginForTheme()); } } this->ui_.textEdit->setFont( @@ -271,11 +270,10 @@ void SplitInput::themeChangedEvent() } // update vbox - auto marginPx = this->marginForTheme(); - this->ui_.vbox->setContentsMargins(marginPx, marginPx, marginPx, marginPx); + this->applyOuterMargin(); if (this->replyTarget_ != nullptr) { - this->ui_.vbox->setSpacing(this->marginForTheme() * 2); + this->ui_.vbox->setSpacing(this->marginForTheme()); } } @@ -1095,26 +1093,26 @@ void SplitInput::paintEvent(QPaintEvent * /*event*/) { QPainter painter(this); - int s = this->marginForTheme(); QColor borderColor = this->theme->isLightTheme() ? QColor("#ccc") : QColor("#333"); QRect baseRect = this->rect(); - QRect inputBoxRect = this->ui_.inputWrapper->geometry(); - inputBoxRect.setX(baseRect.x()); - inputBoxRect.setWidth(baseRect.width()); + baseRect.setWidth(baseRect.width() - 1); - painter.fillRect(inputBoxRect, this->theme->splits.input.background); + auto *inputWrap = this->ui_.inputWrapper; + auto inputBoxRect = inputWrap->geometry(); + inputBoxRect.setSize(inputBoxRect.size() - QSize{1, 1}); + + painter.setBrush({this->theme->splits.input.background}); painter.setPen(borderColor); painter.drawRect(inputBoxRect); if (this->enableInlineReplying_ && this->replyTarget_ != nullptr) { - QRect replyRect = this->ui_.replyWrapper->geometry(); - replyRect.setX(baseRect.x()); - replyRect.setWidth(baseRect.width()); + auto replyRect = this->ui_.replyWrapper->geometry(); + replyRect.setSize(replyRect.size() - QSize{1, 1}); - painter.fillRect(replyRect, this->theme->splits.input.background); + painter.setBrush(this->theme->splits.input.background); painter.setPen(borderColor); painter.drawRect(replyRect); @@ -1140,7 +1138,7 @@ void SplitInput::resizeEvent(QResizeEvent *event) this->ui_.textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } - this->ui_.replyMessage->setWidth(this->width()); + this->ui_.replyMessage->setWidth(this->replyMessageWidth()); } void SplitInput::giveFocus(Qt::FocusReason reason) @@ -1170,11 +1168,11 @@ void SplitInput::setReply(MessagePtr target) if (this->enableInlineReplying_) { + this->ui_.replyMessage->setWidth(this->replyMessageWidth()); this->ui_.replyMessage->setMessage(this->replyTarget_); - this->ui_.replyMessage->setWidth(this->width()); // add spacing between reply box and input box - this->ui_.vbox->setSpacing(this->marginForTheme() * 2); + this->ui_.vbox->setSpacing(this->marginForTheme()); if (!this->isHidden()) { // update maximum height to give space for message @@ -1274,4 +1272,15 @@ int SplitInput::marginForTheme() const } } +void SplitInput::applyOuterMargin() +{ + auto margin = std::max(this->marginForTheme() - 1, 0); + this->ui_.vbox->setContentsMargins(margin, margin, margin, margin); +} + +int SplitInput::replyMessageWidth() const +{ + return this->ui_.inputWrapper->width() - 1 - 10; +} + } // namespace chatterino diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index 8319f9f71..fe822285f 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -124,6 +124,10 @@ protected: int marginForTheme() const; + void applyOuterMargin(); + + int replyMessageWidth() const; + Split *const split_; ChannelView *const channelView_; QPointer emotePopup_; From 21186df058790ae82d087bfdb5613eabdad28922 Mon Sep 17 00:00:00 2001 From: nerix Date: Sun, 21 Jul 2024 11:40:29 +0200 Subject: [PATCH 19/63] ci: collect code coverage (#5516) https://app.codecov.io/gh/Chatterino/chatterino2 --- .codecov.yml | 7 +++++++ .github/workflows/test.yml | 20 +++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 .codecov.yml diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 000000000..db7699448 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,7 @@ +comment: false +ignore: + - "/usr/local*/**/*" + - "/usr/include/**/*" + - "lib/" + - "**/ui_*.h" + - "**/moc_*.cpp" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 45c1a291b..c79569ff3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,6 +5,10 @@ on: pull_request: workflow_dispatch: merge_group: + push: + branches: + - master + - main env: TWITCH_PUBSUB_SERVER_TAG: v1.0.7 @@ -39,11 +43,11 @@ jobs: - name: Create build directory (Ubuntu) run: mkdir build-test - - name: Install googlebench + - name: Install dependencies run: | sudo apt update - sudo apt -y install \ - libbenchmark-dev + sudo DEBIAN_FRONTEND=noninteractive apt -y --no-install-recommends install \ + libbenchmark-dev gcovr gnupg - name: Build (Ubuntu) run: | @@ -55,6 +59,8 @@ jobs: -DCMAKE_PREFIX_PATH="$Qt6_DIR/lib/cmake" \ -DBUILD_WITH_QT6="$C2_BUILD_WITH_QT6" \ -DCHATTERINO_STATIC_QT_BUILD=On \ + -DCHATTERINO_GENERATE_COVERAGE=On \ + -DCMAKE_BUILD_TYPE=Debug \ .. cmake --build . working-directory: build-test @@ -84,3 +90,11 @@ jobs: cd ../build-test ctest --repeat until-pass:4 --output-on-failure --exclude-regex ClassicEmoteNameFiltering working-directory: build-test + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4.5.0 + with: + token: ${{ secrets.CODECOV_TOKEN }} + plugin: gcov + fail_ci_if_error: true + verbose: true From 5deec1f02f0ef00bcd187d06b14ba2a43847f732 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 21 Jul 2024 15:09:59 +0200 Subject: [PATCH 20/63] chore: remove Singleton & replace getIApp with getApp (#5514) --- benchmarks/src/Highlights.cpp | 10 +- benchmarks/src/RecentMessages.cpp | 9 +- mocks/include/mocks/BaseApplication.hpp | 37 +++++ mocks/include/mocks/EmptyApplication.hpp | 13 +- src/Application.cpp | 137 +++++++++++------- src/Application.hpp | 59 +++----- src/CMakeLists.txt | 2 - src/RunGui.cpp | 2 +- src/common/Channel.cpp | 6 +- src/common/Credentials.cpp | 2 +- src/common/Singleton.hpp | 31 ---- src/common/network/NetworkPrivate.cpp | 2 +- src/common/network/NetworkTask.cpp | 2 +- .../accounts/AccountController.cpp | 2 +- .../accounts/AccountController.hpp | 8 +- .../commands/CommandController.cpp | 12 +- .../commands/CommandController.hpp | 7 +- src/controllers/commands/builtin/Misc.cpp | 23 ++- .../commands/builtin/twitch/AddModerator.cpp | 2 +- .../commands/builtin/twitch/AddVIP.cpp | 2 +- .../commands/builtin/twitch/Announce.cpp | 2 +- .../commands/builtin/twitch/Ban.cpp | 6 +- .../commands/builtin/twitch/Block.cpp | 8 +- .../commands/builtin/twitch/ChatSettings.cpp | 20 +-- .../commands/builtin/twitch/Chatters.cpp | 4 +- .../builtin/twitch/DeleteMessages.cpp | 2 +- .../commands/builtin/twitch/GetVIPs.cpp | 2 +- .../commands/builtin/twitch/Raid.cpp | 4 +- .../builtin/twitch/RemoveModerator.cpp | 2 +- .../commands/builtin/twitch/RemoveVIP.cpp | 2 +- .../commands/builtin/twitch/SendWhisper.cpp | 10 +- .../commands/builtin/twitch/ShieldMode.cpp | 2 +- .../commands/builtin/twitch/Shoutout.cpp | 2 +- .../builtin/twitch/StartCommercial.cpp | 2 +- .../commands/builtin/twitch/Unban.cpp | 2 +- .../commands/builtin/twitch/UpdateColor.cpp | 2 +- .../commands/builtin/twitch/Warn.cpp | 2 +- .../completion/TabCompletionModel.cpp | 2 +- .../completion/sources/CommandSource.cpp | 6 +- .../completion/sources/EmoteSource.cpp | 2 +- src/controllers/filters/lang/Filter.cpp | 2 +- .../highlights/BadgeHighlightModel.cpp | 2 +- .../highlights/HighlightController.cpp | 16 +- .../highlights/HighlightController.hpp | 9 +- src/controllers/highlights/HighlightModel.cpp | 2 +- .../highlights/UserHighlightModel.cpp | 2 +- src/controllers/hotkeys/Hotkey.cpp | 2 +- src/controllers/hotkeys/HotkeyController.hpp | 5 +- src/controllers/ignores/IgnoreController.cpp | 2 +- src/controllers/ignores/IgnorePhrase.cpp | 2 +- .../notifications/NotificationController.cpp | 24 +-- .../notifications/NotificationController.hpp | 8 +- src/controllers/plugins/LuaAPI.cpp | 14 +- src/controllers/plugins/Plugin.cpp | 2 +- src/controllers/plugins/PluginController.cpp | 6 +- src/controllers/plugins/PluginController.hpp | 5 +- src/controllers/plugins/api/ChannelRef.cpp | 6 +- src/controllers/plugins/api/HTTPRequest.cpp | 2 +- src/controllers/twitch/LiveController.hpp | 3 +- src/messages/Image.cpp | 6 +- src/messages/MessageBuilder.cpp | 12 +- src/messages/MessageElement.cpp | 4 +- src/messages/SharedMessageBuilder.cpp | 8 +- src/messages/layouts/MessageLayout.cpp | 4 +- .../layouts/MessageLayoutContainer.cpp | 2 +- src/providers/ffz/FfzBadges.cpp | 7 +- src/providers/ffz/FfzBadges.hpp | 6 +- src/providers/irc/Irc2.cpp | 2 +- src/providers/irc/IrcServer.cpp | 2 +- src/providers/seventv/SeventvAPI.hpp | 6 +- src/providers/seventv/SeventvBadges.hpp | 3 +- src/providers/seventv/SeventvEmotes.cpp | 6 +- src/providers/seventv/SeventvEventAPI.cpp | 6 +- src/providers/twitch/IrcMessageHandler.cpp | 53 ++++--- src/providers/twitch/TwitchAccount.cpp | 6 +- src/providers/twitch/TwitchChannel.cpp | 74 +++++----- src/providers/twitch/TwitchIrcServer.cpp | 12 +- src/providers/twitch/TwitchMessageBuilder.cpp | 29 ++-- src/singletons/Badges.cpp | 9 -- src/singletons/Badges.hpp | 13 -- src/singletons/CrashHandler.cpp | 4 - src/singletons/CrashHandler.hpp | 6 +- src/singletons/Emotes.cpp | 9 -- src/singletons/Emotes.hpp | 10 +- src/singletons/ImageUploader.cpp | 6 +- src/singletons/ImageUploader.hpp | 5 +- src/singletons/NativeMessaging.cpp | 11 +- src/singletons/StreamerMode.cpp | 4 +- src/singletons/Theme.cpp | 6 +- src/singletons/Theme.hpp | 6 +- src/singletons/Toasts.cpp | 4 +- src/singletons/Toasts.hpp | 4 +- src/singletons/WindowManager.cpp | 27 ++-- src/singletons/WindowManager.hpp | 11 +- src/singletons/helper/GifTimer.cpp | 2 +- src/singletons/helper/LoggingChannel.cpp | 2 +- src/util/InitUpdateButton.cpp | 10 +- src/util/StreamLink.cpp | 2 +- src/widgets/BaseWidget.cpp | 2 +- src/widgets/BaseWindow.cpp | 6 +- src/widgets/FramelessEmbedWindow.cpp | 2 +- src/widgets/Label.cpp | 8 +- src/widgets/Notebook.cpp | 34 ++--- src/widgets/TooltipWidget.cpp | 8 +- src/widgets/Window.cpp | 51 ++++--- src/widgets/dialogs/BadgePickerDialog.cpp | 2 +- src/widgets/dialogs/EditHotkeyDialog.cpp | 17 +-- src/widgets/dialogs/EmotePopup.cpp | 34 ++--- src/widgets/dialogs/LoginDialog.cpp | 4 +- src/widgets/dialogs/QualityPopup.cpp | 2 +- src/widgets/dialogs/ReplyThreadPopup.cpp | 8 +- src/widgets/dialogs/SelectChannelDialog.cpp | 14 +- src/widgets/dialogs/SettingsDialog.cpp | 8 +- src/widgets/dialogs/UpdateDialog.cpp | 14 +- src/widgets/dialogs/UserInfoPopup.cpp | 38 ++--- src/widgets/dialogs/switcher/NewPopupItem.cpp | 8 +- src/widgets/dialogs/switcher/NewTabItem.cpp | 6 +- .../dialogs/switcher/SwitchSplitItem.cpp | 10 +- src/widgets/helper/ChannelView.cpp | 71 +++++---- src/widgets/helper/NotebookTab.cpp | 12 +- src/widgets/helper/SearchPopup.cpp | 4 +- src/widgets/settingspages/AccountsPage.cpp | 2 +- src/widgets/settingspages/CommandPage.cpp | 6 +- src/widgets/settingspages/GeneralPage.cpp | 32 ++-- src/widgets/settingspages/GeneralPageView.cpp | 2 +- src/widgets/settingspages/GeneralPageView.hpp | 6 +- .../settingspages/KeyboardSettingsPage.cpp | 14 +- src/widgets/settingspages/ModerationPage.cpp | 26 ++-- .../settingspages/NotificationPage.cpp | 2 +- src/widgets/settingspages/PluginsPage.cpp | 8 +- src/widgets/settingspages/SettingsPage.cpp | 2 +- src/widgets/splits/Split.cpp | 45 +++--- src/widgets/splits/SplitContainer.cpp | 26 ++-- src/widgets/splits/SplitHeader.cpp | 16 +- src/widgets/splits/SplitInput.cpp | 16 +- src/widgets/splits/SplitOverlay.cpp | 4 +- tests/src/Commands.cpp | 23 ++- tests/src/Filters.cpp | 7 + tests/src/HighlightController.cpp | 49 ++----- tests/src/InputCompletion.cpp | 4 +- tests/src/MessageLayout.cpp | 14 +- tests/src/NotebookTab.cpp | 1 + tests/src/Scrollbar.cpp | 7 +- tests/src/SplitInput.cpp | 11 +- tests/src/TwitchMessageBuilder.cpp | 7 + 145 files changed, 802 insertions(+), 856 deletions(-) create mode 100644 mocks/include/mocks/BaseApplication.hpp delete mode 100644 src/common/Singleton.hpp delete mode 100644 src/singletons/Badges.cpp delete mode 100644 src/singletons/Badges.hpp diff --git a/benchmarks/src/Highlights.cpp b/benchmarks/src/Highlights.cpp index c363e508c..12b70d33a 100644 --- a/benchmarks/src/Highlights.cpp +++ b/benchmarks/src/Highlights.cpp @@ -5,7 +5,7 @@ #include "controllers/highlights/HighlightPhrase.hpp" #include "messages/Message.hpp" #include "messages/SharedMessageBuilder.hpp" -#include "mocks/EmptyApplication.hpp" +#include "mocks/BaseApplication.hpp" #include "singletons/Settings.hpp" #include "util/Helpers.hpp" @@ -47,9 +47,14 @@ public: } }; -class MockApplication : mock::EmptyApplication +class MockApplication : public mock::BaseApplication { public: + MockApplication() + : highlights(this->settings, &this->accounts) + { + } + AccountController *getAccounts() override { return &this->accounts; @@ -61,7 +66,6 @@ public: AccountController accounts; HighlightController highlights; - // TODO: Figure this out }; static void BM_HighlightTest(benchmark::State &state) diff --git a/benchmarks/src/RecentMessages.cpp b/benchmarks/src/RecentMessages.cpp index 7f2c0c7ac..24ebd127f 100644 --- a/benchmarks/src/RecentMessages.cpp +++ b/benchmarks/src/RecentMessages.cpp @@ -2,8 +2,8 @@ #include "controllers/accounts/AccountController.hpp" #include "controllers/highlights/HighlightController.hpp" #include "messages/Emote.hpp" +#include "mocks/BaseApplication.hpp" #include "mocks/DisabledStreamerMode.hpp" -#include "mocks/EmptyApplication.hpp" #include "mocks/LinkResolver.hpp" #include "mocks/TwitchIrcServer.hpp" #include "mocks/UserData.hpp" @@ -32,9 +32,14 @@ using namespace literals; namespace { -class MockApplication : mock::EmptyApplication +class MockApplication : public mock::BaseApplication { public: + MockApplication() + : highlights(this->settings, &this->accounts) + { + } + IEmotes *getEmotes() override { return &this->emotes; diff --git a/mocks/include/mocks/BaseApplication.hpp b/mocks/include/mocks/BaseApplication.hpp new file mode 100644 index 000000000..720d1f684 --- /dev/null +++ b/mocks/include/mocks/BaseApplication.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "mocks/DisabledStreamerMode.hpp" +#include "mocks/EmptyApplication.hpp" +#include "singletons/Settings.hpp" + +#include + +namespace chatterino::mock { + +/** + * BaseApplication intends to be a mock application with a few more sane defaults, but with less configurability + */ +class BaseApplication : public EmptyApplication +{ +public: + BaseApplication() + : settings(this->settingsDir.filePath("settings.json")) + { + } + + explicit BaseApplication(const QString &settingsData) + : EmptyApplication(settingsData) + , settings(this->settingsDir.filePath("settings.json")) + { + } + + IStreamerMode *getStreamerMode() override + { + return &this->streamerMode; + } + + Settings settings; + DisabledStreamerMode streamerMode; +}; + +} // namespace chatterino::mock diff --git a/mocks/include/mocks/EmptyApplication.hpp b/mocks/include/mocks/EmptyApplication.hpp index 233211bfa..e293a56e4 100644 --- a/mocks/include/mocks/EmptyApplication.hpp +++ b/mocks/include/mocks/EmptyApplication.hpp @@ -17,7 +17,17 @@ public: { } - virtual ~EmptyApplication() = default; + explicit EmptyApplication(const QString &settingsData) + : EmptyApplication() + { + QFile settingsFile(this->settingsDir.filePath("settings.json")); + settingsFile.open(QIODevice::WriteOnly | QIODevice::Text); + settingsFile.write(settingsData.toUtf8()); + settingsFile.flush(); + settingsFile.close(); + } + + ~EmptyApplication() override = default; bool isTest() const override { @@ -249,7 +259,6 @@ public: return nullptr; } -protected: QTemporaryDir settingsDir; Paths paths_; Args args_; diff --git a/src/Application.cpp b/src/Application.cpp index 30e7cdb26..6020fb865 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -118,26 +118,26 @@ Application::Application(Settings &_settings, const Paths &paths, const Args &_args, Updates &_updates) : paths_(paths) , args_(_args) - , themes(&this->emplace()) + , themes(new Theme(paths)) , fonts(new Fonts(_settings)) - , emotes(&this->emplace()) - , accounts(&this->emplace()) - , hotkeys(&this->emplace()) - , windows(&this->emplace(new WindowManager(paths))) - , toasts(&this->emplace()) - , imageUploader(&this->emplace()) - , seventvAPI(&this->emplace()) - , crashHandler(&this->emplace(new CrashHandler(paths))) + , emotes(new Emotes) + , accounts(new AccountController) + , hotkeys(new HotkeyController) + , windows(new WindowManager(paths)) + , toasts(new Toasts) + , imageUploader(new ImageUploader) + , seventvAPI(new SeventvAPI) + , crashHandler(new CrashHandler(paths)) - , commands(&this->emplace()) - , notifications(&this->emplace()) - , highlights(&this->emplace()) + , commands(new CommandController(paths)) + , notifications(new NotificationController) + , highlights(new HighlightController(_settings, this->accounts.get())) , twitch(new TwitchIrcServer) - , ffzBadges(&this->emplace()) - , seventvBadges(&this->emplace()) + , ffzBadges(new FfzBadges) + , seventvBadges(new SeventvBadges) , userData(new UserDataController(paths)) , sound(makeSoundController(_settings)) - , twitchLiveController(&this->emplace()) + , twitchLiveController(new TwitchLiveController) , twitchPubSub(new PubSub(TWITCH_PUBSUB_URL)) , twitchBadges(new TwitchBadges) , chatterinoBadges(new ChatterinoBadges) @@ -148,7 +148,7 @@ Application::Application(Settings &_settings, const Paths &paths, , linkResolver(new LinkResolver) , streamerMode(new StreamerMode) #ifdef CHATTERINO_HAVE_PLUGINS - , plugins(&this->emplace(new PluginController(paths))) + , plugins(new PluginController(paths)) #endif , updates(_updates) { @@ -165,16 +165,35 @@ Application::~Application() = default; void Application::fakeDtor() { +#ifdef CHATTERINO_HAVE_PLUGINS + this->plugins.reset(); +#endif this->twitchPubSub.reset(); this->twitchBadges.reset(); + this->twitchLiveController.reset(); this->chatterinoBadges.reset(); this->bttvEmotes.reset(); this->ffzEmotes.reset(); this->seventvEmotes.reset(); + this->notifications.reset(); + this->commands.reset(); + // If a crash happens after crashHandler has been reset, we'll assert + // This isn't super different from before, where if the app is already killed, the getApp() portion of it is already dead + this->crashHandler.reset(); + this->seventvAPI.reset(); + this->highlights.reset(); + this->seventvBadges.reset(); + this->ffzBadges.reset(); // this->twitch.reset(); + this->imageUploader.reset(); + this->hotkeys.reset(); this->fonts.reset(); this->sound.reset(); this->userData.reset(); + this->toasts.reset(); + this->accounts.reset(); + this->emotes.reset(); + this->themes.reset(); } void Application::initialize(Settings &settings, const Paths &paths) @@ -208,17 +227,24 @@ void Application::initialize(Settings &settings, const Paths &paths) } } - for (auto &singleton : this->singletons_) - { - singleton->initialize(settings, paths); - } + this->accounts->load(); + this->windows->initialize(settings); + + this->ffzBadges->load(); this->twitch->initialize(); + // Load live status + this->notifications->initialize(); + // XXX: Loading Twitch badges after Helix has been initialized, which only happens after // the AccountController initialize has been called this->twitchBadges->loadTwitchBadges(); +#ifdef CHATTERINO_HAVE_PLUGINS + this->plugins->initialize(settings); +#endif + // Show crash message. // On Windows, the crash message was already shown. #ifndef Q_OS_WIN @@ -335,8 +361,9 @@ int Application::run(QApplication &qtApp) Theme *Application::getThemes() { assertInGuiThread(); + assert(this->themes); - return this->themes; + return this->themes.get(); } Fonts *Application::getFonts() @@ -350,22 +377,25 @@ Fonts *Application::getFonts() IEmotes *Application::getEmotes() { assertInGuiThread(); + assert(this->emotes); - return this->emotes; + return this->emotes.get(); } AccountController *Application::getAccounts() { assertInGuiThread(); + assert(this->accounts); - return this->accounts; + return this->accounts.get(); } HotkeyController *Application::getHotkeys() { assertInGuiThread(); + assert(this->hotkeys); - return this->hotkeys; + return this->hotkeys.get(); } WindowManager *Application::getWindows() @@ -373,56 +403,63 @@ WindowManager *Application::getWindows() assertInGuiThread(); assert(this->windows); - return this->windows; + return this->windows.get(); } Toasts *Application::getToasts() { assertInGuiThread(); + assert(this->toasts); - return this->toasts; + return this->toasts.get(); } CrashHandler *Application::getCrashHandler() { assertInGuiThread(); + assert(this->crashHandler); - return this->crashHandler; + return this->crashHandler.get(); } CommandController *Application::getCommands() { assertInGuiThread(); + assert(this->commands); - return this->commands; + return this->commands.get(); } NotificationController *Application::getNotifications() { assertInGuiThread(); + assert(this->notifications); - return this->notifications; + return this->notifications.get(); } HighlightController *Application::getHighlights() { assertInGuiThread(); + assert(this->highlights); - return this->highlights; + return this->highlights.get(); } FfzBadges *Application::getFfzBadges() { assertInGuiThread(); + assert(this->ffzBadges); - return this->ffzBadges; + return this->ffzBadges.get(); } SeventvBadges *Application::getSeventvBadges() { // SeventvBadges handles its own locks, so we don't need to assert that this is called in the GUI thread + assert(this->seventvBadges); - return this->seventvBadges; + return this->seventvBadges.get(); } IUserDataController *Application::getUserData() @@ -442,8 +479,9 @@ ISoundController *Application::getSound() ITwitchLiveController *Application::getTwitchLiveController() { assertInGuiThread(); + assert(this->twitchLiveController); - return this->twitchLiveController; + return this->twitchLiveController.get(); } TwitchBadges *Application::getTwitchBadges() @@ -465,23 +503,26 @@ IChatterinoBadges *Application::getChatterinoBadges() ImageUploader *Application::getImageUploader() { assertInGuiThread(); + assert(this->imageUploader); - return this->imageUploader; + return this->imageUploader.get(); } SeventvAPI *Application::getSeventvAPI() { assertInGuiThread(); + assert(this->seventvAPI); - return this->seventvAPI; + return this->seventvAPI.get(); } #ifdef CHATTERINO_HAVE_PLUGINS PluginController *Application::getPlugins() { assertInGuiThread(); + assert(this->plugins); - return this->plugins; + return this->plugins.get(); } #endif @@ -551,10 +592,9 @@ SeventvEmotes *Application::getSeventvEmotes() void Application::save() { - for (auto &singleton : this->singletons_) - { - singleton->save(); - } + this->commands->save(); + this->hotkeys->save(); + this->windows->save(); } void Application::initNm(const Paths &paths) @@ -896,11 +936,11 @@ void Application::initPubSub() chan->addMessage(p.second, MessageContext::Original); - getIApp() + getApp() ->getTwitch() ->getAutomodChannel() ->addMessage(p.first, MessageContext::Original); - getIApp() + getApp() ->getTwitch() ->getAutomodChannel() ->addMessage(p.second, @@ -908,12 +948,12 @@ void Application::initPubSub() if (getSettings()->showAutomodInMentions) { - getIApp() + getApp() ->getTwitch() ->getMentionsChannel() ->addMessage(p.first, MessageContext::Original); - getIApp() + getApp() ->getTwitch() ->getMentionsChannel() ->addMessage(p.second, @@ -1124,14 +1164,7 @@ void Application::initSeventvEventAPI() seventvEventAPI->start(); } -Application *getApp() -{ - assert(Application::instance != nullptr); - - return Application::instance; -} - -IApplication *getIApp() +IApplication *getApp() { assert(IApplication::instance != nullptr); diff --git a/src/Application.hpp b/src/Application.hpp index af1c563a8..59ca9b1a3 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -1,6 +1,5 @@ #pragma once -#include "common/Singleton.hpp" #include "debug/AssertInGuiThread.hpp" #include "singletons/NativeMessaging.hpp" @@ -108,7 +107,6 @@ class Application : public IApplication { const Paths &paths_; const Args &args_; - std::vector> singletons_; int argc_{}; char **argv_{}; @@ -144,25 +142,25 @@ public: friend void test(); private: - Theme *const themes{}; - std::unique_ptr fonts{}; - Emotes *const emotes{}; - AccountController *const accounts{}; - HotkeyController *const hotkeys{}; - WindowManager *const windows{}; - Toasts *const toasts{}; - ImageUploader *const imageUploader{}; - SeventvAPI *const seventvAPI{}; - CrashHandler *const crashHandler{}; - CommandController *const commands{}; - NotificationController *const notifications{}; - HighlightController *const highlights{}; + std::unique_ptr themes; + std::unique_ptr fonts; + std::unique_ptr emotes; + std::unique_ptr accounts; + std::unique_ptr hotkeys; + std::unique_ptr windows; + std::unique_ptr toasts; + std::unique_ptr imageUploader; + std::unique_ptr seventvAPI; + std::unique_ptr crashHandler; + std::unique_ptr commands; + std::unique_ptr notifications; + std::unique_ptr highlights; std::unique_ptr twitch; - FfzBadges *const ffzBadges{}; - SeventvBadges *const seventvBadges{}; + std::unique_ptr ffzBadges; + std::unique_ptr seventvBadges; std::unique_ptr userData; std::unique_ptr sound; - TwitchLiveController *const twitchLiveController{}; + std::unique_ptr twitchLiveController; std::unique_ptr twitchPubSub; std::unique_ptr twitchBadges; std::unique_ptr chatterinoBadges; @@ -173,7 +171,7 @@ private: std::unique_ptr linkResolver; std::unique_ptr streamerMode; #ifdef CHATTERINO_HAVE_PLUGINS - PluginController *const plugins{}; + std::unique_ptr plugins; #endif public: @@ -227,36 +225,15 @@ public: IStreamerMode *getStreamerMode() override; private: - void addSingleton(Singleton *singleton); void initPubSub(); void initBttvLiveUpdates(); void initSeventvEventAPI(); void initNm(const Paths &paths); - template ::value>> - T &emplace() - { - auto t = new T; - this->singletons_.push_back(std::unique_ptr(t)); - return *t; - } - - template ::value>> - T &emplace(T *t) - { - this->singletons_.push_back(std::unique_ptr(t)); - return *t; - } - NativeMessagingServer nmServer{}; Updates &updates; }; -Application *getApp(); - -// Get an interface version of the Application class - should be preferred when possible for new code -IApplication *getIApp(); +IApplication *getApp(); } // namespace chatterino diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e6f0939b..42823b259 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -444,8 +444,6 @@ set(SOURCE_FILES providers/twitch/api/Helix.cpp providers/twitch/api/Helix.hpp - singletons/Badges.cpp - singletons/Badges.hpp singletons/CrashHandler.cpp singletons/CrashHandler.hpp singletons/Emotes.cpp diff --git a/src/RunGui.cpp b/src/RunGui.cpp index 6fba9c6af..06e9a7b94 100644 --- a/src/RunGui.cpp +++ b/src/RunGui.cpp @@ -131,7 +131,7 @@ namespace { using namespace std::chrono_literals; if (std::chrono::steady_clock::now() - signalsInitTime > 30s && - getIApp()->getCrashHandler()->shouldRecover()) + getApp()->getCrashHandler()->shouldRecover()) { QProcess proc; diff --git a/src/common/Channel.cpp b/src/common/Channel.cpp index 76dd8bb86..bbf58f0a7 100644 --- a/src/common/Channel.cpp +++ b/src/common/Channel.cpp @@ -100,9 +100,9 @@ void Channel::addMessage(MessagePtr message, MessageContext context, if (!isDoNotLogSet) { // Only log messages where the `DoNotLog` flag is not set - getIApp()->getChatLogger()->addMessage(this->name_, message, - this->platform_, - this->getCurrentStreamID()); + getApp()->getChatLogger()->addMessage(this->name_, message, + this->platform_, + this->getCurrentStreamID()); } } diff --git a/src/common/Credentials.cpp b/src/common/Credentials.cpp index 5fffe013f..68c9cdd59 100644 --- a/src/common/Credentials.cpp +++ b/src/common/Credentials.cpp @@ -56,7 +56,7 @@ bool useKeyring() // Insecure storage: QString insecurePath() { - return combinePath(getIApp()->getPaths().settingsDirectory, + return combinePath(getApp()->getPaths().settingsDirectory, "credentials.json"); } diff --git a/src/common/Singleton.hpp b/src/common/Singleton.hpp deleted file mode 100644 index f94d7152a..000000000 --- a/src/common/Singleton.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -namespace chatterino { - -class Settings; -class Paths; - -class Singleton -{ -public: - Singleton() = default; - virtual ~Singleton() = default; - - Singleton(const Singleton &) = delete; - Singleton &operator=(const Singleton &) = delete; - - Singleton(Singleton &&) = delete; - Singleton &operator=(Singleton &&) = delete; - - virtual void initialize(Settings &settings, const Paths &paths) - { - (void)(settings); - (void)(paths); - } - - virtual void save() - { - } -}; - -} // namespace chatterino diff --git a/src/common/network/NetworkPrivate.cpp b/src/common/network/NetworkPrivate.cpp index ed81dd9e6..425a1f5f2 100644 --- a/src/common/network/NetworkPrivate.cpp +++ b/src/common/network/NetworkPrivate.cpp @@ -59,7 +59,7 @@ void loadUncached(std::shared_ptr &&data) void loadCached(std::shared_ptr &&data) { - QFile cachedFile(getIApp()->getPaths().cacheDirectory() + "/" + + QFile cachedFile(getApp()->getPaths().cacheDirectory() + "/" + data->getHash()); if (!cachedFile.exists() || !cachedFile.open(QIODevice::ReadOnly)) diff --git a/src/common/network/NetworkTask.cpp b/src/common/network/NetworkTask.cpp index 256743a4f..bebe34051 100644 --- a/src/common/network/NetworkTask.cpp +++ b/src/common/network/NetworkTask.cpp @@ -118,7 +118,7 @@ void NetworkTask::logReply() void NetworkTask::writeToCache(const QByteArray &bytes) const { std::ignore = QtConcurrent::run([data = this->data_, bytes] { - QFile cachedFile(getIApp()->getPaths().cacheDirectory() + "/" + + QFile cachedFile(getApp()->getPaths().cacheDirectory() + "/" + data->getHash()); if (cachedFile.open(QIODevice::WriteOnly)) diff --git a/src/controllers/accounts/AccountController.cpp b/src/controllers/accounts/AccountController.cpp index d0643cdef..414cb8b56 100644 --- a/src/controllers/accounts/AccountController.cpp +++ b/src/controllers/accounts/AccountController.cpp @@ -47,7 +47,7 @@ AccountController::AccountController() }); } -void AccountController::initialize(Settings &settings, const Paths &paths) +void AccountController::load() { this->twitch.load(); } diff --git a/src/controllers/accounts/AccountController.hpp b/src/controllers/accounts/AccountController.hpp index 726719f5c..d84e2b9cc 100644 --- a/src/controllers/accounts/AccountController.hpp +++ b/src/controllers/accounts/AccountController.hpp @@ -1,7 +1,6 @@ #pragma once #include "common/SignalVector.hpp" -#include "common/Singleton.hpp" #include "providers/twitch/TwitchAccountManager.hpp" #include @@ -14,14 +13,17 @@ class Paths; class AccountModel; -class AccountController final : public Singleton +class AccountController final { public: AccountController(); AccountModel *createModel(QObject *parent); - void initialize(Settings &settings, const Paths &paths) override; + /** + * Load current user & send off a signal to subscribers about any potential changes + */ + void load(); TwitchAccountManager twitch; diff --git a/src/controllers/commands/CommandController.cpp b/src/controllers/commands/CommandController.cpp index 4742088e4..397e36d95 100644 --- a/src/controllers/commands/CommandController.cpp +++ b/src/controllers/commands/CommandController.cpp @@ -121,7 +121,7 @@ const std::unordered_map COMMAND_VARS{ (void)(channel); //unused (void)(message); //unused auto uid = - getIApp()->getAccounts()->twitch.getCurrent()->getUserId(); + getApp()->getAccounts()->twitch.getCurrent()->getUserId(); return uid.isEmpty() ? altText : uid; }, }, @@ -131,7 +131,7 @@ const std::unordered_map COMMAND_VARS{ (void)(channel); //unused (void)(message); //unused auto name = - getIApp()->getAccounts()->twitch.getCurrent()->getUserName(); + getApp()->getAccounts()->twitch.getCurrent()->getUserName(); return name.isEmpty() ? altText : name; }, }, @@ -263,7 +263,7 @@ const std::unordered_map COMMAND_VARS{ namespace chatterino { -void CommandController::initialize(Settings &, const Paths &paths) +CommandController::CommandController(const Paths &paths) { // Update commands map when the vector of commands has been updated auto addFirstMatchToMap = [this](auto args) { @@ -485,7 +485,7 @@ QString CommandController::execCommand(const QString &textNoEmoji, ChannelPtr channel, bool dryRun) { QString text = - getIApp()->getEmotes()->getEmojis()->replaceShortCodes(textNoEmoji); + getApp()->getEmotes()->getEmojis()->replaceShortCodes(textNoEmoji); QStringList words = text.split(' ', Qt::SkipEmptyParts); if (words.length() == 0) @@ -500,7 +500,7 @@ QString CommandController::execCommand(const QString &textNoEmoji, const auto it = this->userCommands_.find(commandName); if (it != this->userCommands_.end()) { - text = getIApp()->getEmotes()->getEmojis()->replaceShortCodes( + text = getApp()->getEmotes()->getEmojis()->replaceShortCodes( this->execCustomCommand(words, it.value(), dryRun, channel)); words = text.split(' ', Qt::SkipEmptyParts); @@ -570,7 +570,7 @@ bool CommandController::registerPluginCommand(const QString &commandName) } this->commands_[commandName] = [commandName](const CommandContext &ctx) { - return getIApp()->getPlugins()->tryExecPluginCommand(commandName, ctx); + return getApp()->getPlugins()->tryExecPluginCommand(commandName, ctx); }; this->pluginCommands_.append(commandName); return true; diff --git a/src/controllers/commands/CommandController.hpp b/src/controllers/commands/CommandController.hpp index d13197e4f..d730c671d 100644 --- a/src/controllers/commands/CommandController.hpp +++ b/src/controllers/commands/CommandController.hpp @@ -1,7 +1,6 @@ #pragma once #include "common/SignalVector.hpp" -#include "common/Singleton.hpp" #include "util/QStringHash.hpp" #include @@ -24,7 +23,7 @@ struct Command; class CommandModel; struct CommandContext; -class CommandController final : public Singleton +class CommandController final { public: SignalVector items; @@ -33,8 +32,8 @@ public: bool dryRun); QStringList getDefaultChatterinoCommandList(); - void initialize(Settings &, const Paths &paths) override; - void save() override; + CommandController(const Paths &paths); + void save(); CommandModel *createModel(QObject *parent); diff --git a/src/controllers/commands/builtin/Misc.cpp b/src/controllers/commands/builtin/Misc.cpp index 9be6438ce..0b34dc5b4 100644 --- a/src/controllers/commands/builtin/Misc.cpp +++ b/src/controllers/commands/builtin/Misc.cpp @@ -220,7 +220,7 @@ QString marker(const CommandContext &ctx) } // Avoid Helix calls without Client ID and/or OAuth Token - if (getIApp()->getAccounts()->twitch.getCurrent()->isAnon()) + if (getApp()->getAccounts()->twitch.getCurrent()->isAnon()) { ctx.channel->addSystemMessage( "You need to be logged in to create stream markers!"); @@ -367,7 +367,7 @@ QString popup(const CommandContext &ctx) if (target.isEmpty()) { auto *currentPage = - dynamic_cast(getIApp() + dynamic_cast(getApp() ->getWindows() ->getMainWindow() .getNotebook() @@ -388,9 +388,8 @@ QString popup(const CommandContext &ctx) } // Open channel passed as argument in a popup - auto targetChannel = - getIApp()->getTwitchAbstract()->getOrAddChannel(target); - getIApp()->getWindows()->openInPopup(targetChannel); + auto targetChannel = getApp()->getTwitchAbstract()->getOrAddChannel(target); + getApp()->getWindows()->openInPopup(targetChannel); return ""; } @@ -399,7 +398,7 @@ QString clearmessages(const CommandContext &ctx) { (void)ctx; - auto *currentPage = getIApp() + auto *currentPage = getApp() ->getWindows() ->getLastSelectedWindow() ->getNotebook() @@ -531,7 +530,7 @@ QString sendRawMessage(const CommandContext &ctx) if (ctx.channel->isTwitchChannel()) { - getIApp()->getTwitchAbstract()->sendRawMessage( + getApp()->getTwitchAbstract()->sendRawMessage( ctx.words.mid(1).join(" ")); } else @@ -565,7 +564,7 @@ QString injectFakeMessage(const CommandContext &ctx) } auto ircText = ctx.words.mid(1).join(" "); - getIApp()->getTwitchAbstract()->addFakeMessage(ircText); + getApp()->getTwitchAbstract()->addFakeMessage(ircText); return ""; } @@ -634,7 +633,7 @@ QString unstableSetUserClientSideColor(const CommandContext &ctx) auto color = ctx.words.value(2); - getIApp()->getUserData()->setUserColor(userID, color); + getApp()->getUserData()->setUserColor(userID, color); return ""; } @@ -664,7 +663,7 @@ QString openUsercard(const CommandContext &ctx) stripChannelName(channelName); ChannelPtr channelTemp = - getIApp()->getTwitchAbstract()->getChannelOrEmpty(channelName); + getApp()->getTwitchAbstract()->getChannelOrEmpty(channelName); if (channelTemp->isEmpty()) { @@ -679,7 +678,7 @@ QString openUsercard(const CommandContext &ctx) // try to link to current split if possible Split *currentSplit = nullptr; - auto *currentPage = dynamic_cast(getIApp() + auto *currentPage = dynamic_cast(getApp() ->getWindows() ->getMainWindow() .getNotebook() @@ -695,7 +694,7 @@ QString openUsercard(const CommandContext &ctx) { // not possible to use current split, try searching for one const auto ¬ebook = - getIApp()->getWindows()->getMainWindow().getNotebook(); + getApp()->getWindows()->getMainWindow().getNotebook(); auto count = notebook.getPageCount(); for (int i = 0; i < count; i++) { diff --git a/src/controllers/commands/builtin/twitch/AddModerator.cpp b/src/controllers/commands/builtin/twitch/AddModerator.cpp index 6d06d9f82..bedd74631 100644 --- a/src/controllers/commands/builtin/twitch/AddModerator.cpp +++ b/src/controllers/commands/builtin/twitch/AddModerator.cpp @@ -32,7 +32,7 @@ QString addModerator(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage("You must be logged in to mod someone!"); diff --git a/src/controllers/commands/builtin/twitch/AddVIP.cpp b/src/controllers/commands/builtin/twitch/AddVIP.cpp index 26d374192..9a50e8313 100644 --- a/src/controllers/commands/builtin/twitch/AddVIP.cpp +++ b/src/controllers/commands/builtin/twitch/AddVIP.cpp @@ -32,7 +32,7 @@ QString addVIP(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage("You must be logged in to VIP someone!"); diff --git a/src/controllers/commands/builtin/twitch/Announce.cpp b/src/controllers/commands/builtin/twitch/Announce.cpp index 67212858e..250b239f4 100644 --- a/src/controllers/commands/builtin/twitch/Announce.cpp +++ b/src/controllers/commands/builtin/twitch/Announce.cpp @@ -50,7 +50,7 @@ QString sendAnnouncementColor(const CommandContext &ctx, return ""; } - auto user = getIApp()->getAccounts()->twitch.getCurrent(); + auto user = getApp()->getAccounts()->twitch.getCurrent(); if (user->isAnon()) { ctx.channel->addSystemMessage( diff --git a/src/controllers/commands/builtin/twitch/Ban.cpp b/src/controllers/commands/builtin/twitch/Ban.cpp index d2a77486f..819231524 100644 --- a/src/controllers/commands/builtin/twitch/Ban.cpp +++ b/src/controllers/commands/builtin/twitch/Ban.cpp @@ -141,7 +141,7 @@ QString sendBan(const CommandContext &ctx) assert(!actions.value().empty()); - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage("You must be logged in to ban someone!"); @@ -252,7 +252,7 @@ QString sendBanById(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { channel->addSystemMessage("You must be logged in to ban someone!"); @@ -292,7 +292,7 @@ QString sendTimeout(const CommandContext &ctx) assert(!actions.value().empty()); - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage( diff --git a/src/controllers/commands/builtin/twitch/Block.cpp b/src/controllers/commands/builtin/twitch/Block.cpp index 3a0419d5a..7e0423d44 100644 --- a/src/controllers/commands/builtin/twitch/Block.cpp +++ b/src/controllers/commands/builtin/twitch/Block.cpp @@ -36,7 +36,7 @@ QString blockUser(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { @@ -52,7 +52,7 @@ QString blockUser(const CommandContext &ctx) target, [currentUser, channel{ctx.channel}, target](const HelixUser &targetUser) { - getIApp()->getAccounts()->twitch.getCurrent()->blockUser( + getApp()->getAccounts()->twitch.getCurrent()->blockUser( targetUser.id, nullptr, [channel, target, targetUser] { channel->addSystemMessage( @@ -109,7 +109,7 @@ QString unblockUser(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { @@ -124,7 +124,7 @@ QString unblockUser(const CommandContext &ctx) getHelix()->getUserByName( target, [currentUser, channel{ctx.channel}, target](const auto &targetUser) { - getIApp()->getAccounts()->twitch.getCurrent()->unblockUser( + getApp()->getAccounts()->twitch.getCurrent()->unblockUser( targetUser.id, nullptr, [channel, target, targetUser] { channel->addSystemMessage( diff --git a/src/controllers/commands/builtin/twitch/ChatSettings.cpp b/src/controllers/commands/builtin/twitch/ChatSettings.cpp index 1e166193b..cc0f311a9 100644 --- a/src/controllers/commands/builtin/twitch/ChatSettings.cpp +++ b/src/controllers/commands/builtin/twitch/ChatSettings.cpp @@ -100,7 +100,7 @@ namespace chatterino::commands { QString emoteOnly(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); @@ -130,7 +130,7 @@ QString emoteOnly(const CommandContext &ctx) QString emoteOnlyOff(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); @@ -158,7 +158,7 @@ QString emoteOnlyOff(const CommandContext &ctx) QString subscribers(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); @@ -188,7 +188,7 @@ QString subscribers(const CommandContext &ctx) QString subscribersOff(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); @@ -218,7 +218,7 @@ QString subscribersOff(const CommandContext &ctx) QString slow(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); @@ -265,7 +265,7 @@ QString slow(const CommandContext &ctx) QString slowOff(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); @@ -294,7 +294,7 @@ QString slowOff(const CommandContext &ctx) QString followers(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); @@ -342,7 +342,7 @@ QString followers(const CommandContext &ctx) QString followersOff(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); @@ -372,7 +372,7 @@ QString followersOff(const CommandContext &ctx) QString uniqueChat(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); @@ -402,7 +402,7 @@ QString uniqueChat(const CommandContext &ctx) QString uniqueChatOff(const CommandContext &ctx) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage(P_NOT_LOGGED_IN); diff --git a/src/controllers/commands/builtin/twitch/Chatters.cpp b/src/controllers/commands/builtin/twitch/Chatters.cpp index 602da9cc9..7c5f21fb8 100644 --- a/src/controllers/commands/builtin/twitch/Chatters.cpp +++ b/src/controllers/commands/builtin/twitch/Chatters.cpp @@ -77,7 +77,7 @@ QString chatters(const CommandContext &ctx) // Refresh chatter list via helix api for mods getHelix()->getChatters( ctx.twitchChannel->roomId(), - getIApp()->getAccounts()->twitch.getCurrent()->getUserId(), 1, + getApp()->getAccounts()->twitch.getCurrent()->getUserId(), 1, [channel{ctx.channel}](auto result) { channel->addSystemMessage(QString("Chatter count: %1.") .arg(localizeNumbers(result.total))); @@ -106,7 +106,7 @@ QString testChatters(const CommandContext &ctx) getHelix()->getChatters( ctx.twitchChannel->roomId(), - getIApp()->getAccounts()->twitch.getCurrent()->getUserId(), 5000, + getApp()->getAccounts()->twitch.getCurrent()->getUserId(), 5000, [channel{ctx.channel}, twitchChannel{ctx.twitchChannel}](auto result) { QStringList entries; for (const auto &username : result.chatters) diff --git a/src/controllers/commands/builtin/twitch/DeleteMessages.cpp b/src/controllers/commands/builtin/twitch/DeleteMessages.cpp index e0fe3e069..ab3b61a8e 100644 --- a/src/controllers/commands/builtin/twitch/DeleteMessages.cpp +++ b/src/controllers/commands/builtin/twitch/DeleteMessages.cpp @@ -21,7 +21,7 @@ QString deleteMessages(TwitchChannel *twitchChannel, const QString &messageID) { const auto *commandName = messageID.isEmpty() ? "/clear" : "/delete"; - auto user = getIApp()->getAccounts()->twitch.getCurrent(); + auto user = getApp()->getAccounts()->twitch.getCurrent(); // Avoid Helix calls without Client ID and/or OAuth Token if (user->isAnon()) diff --git a/src/controllers/commands/builtin/twitch/GetVIPs.cpp b/src/controllers/commands/builtin/twitch/GetVIPs.cpp index 3b6b98e01..794c5c0b9 100644 --- a/src/controllers/commands/builtin/twitch/GetVIPs.cpp +++ b/src/controllers/commands/builtin/twitch/GetVIPs.cpp @@ -81,7 +81,7 @@ QString getVIPs(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage( diff --git a/src/controllers/commands/builtin/twitch/Raid.cpp b/src/controllers/commands/builtin/twitch/Raid.cpp index 3f01f153e..57fb3c011 100644 --- a/src/controllers/commands/builtin/twitch/Raid.cpp +++ b/src/controllers/commands/builtin/twitch/Raid.cpp @@ -136,7 +136,7 @@ QString startRaid(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage("You must be logged in to start a raid!"); @@ -192,7 +192,7 @@ QString cancelRaid(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage( diff --git a/src/controllers/commands/builtin/twitch/RemoveModerator.cpp b/src/controllers/commands/builtin/twitch/RemoveModerator.cpp index 65611ff3e..3d6d8e365 100644 --- a/src/controllers/commands/builtin/twitch/RemoveModerator.cpp +++ b/src/controllers/commands/builtin/twitch/RemoveModerator.cpp @@ -32,7 +32,7 @@ QString removeModerator(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage( diff --git a/src/controllers/commands/builtin/twitch/RemoveVIP.cpp b/src/controllers/commands/builtin/twitch/RemoveVIP.cpp index 2703418f9..22e0a709c 100644 --- a/src/controllers/commands/builtin/twitch/RemoveVIP.cpp +++ b/src/controllers/commands/builtin/twitch/RemoveVIP.cpp @@ -34,7 +34,7 @@ QString removeVIP(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage( diff --git a/src/controllers/commands/builtin/twitch/SendWhisper.cpp b/src/controllers/commands/builtin/twitch/SendWhisper.cpp index 483f72853..3a33ee973 100644 --- a/src/controllers/commands/builtin/twitch/SendWhisper.cpp +++ b/src/controllers/commands/builtin/twitch/SendWhisper.cpp @@ -92,7 +92,7 @@ QString formatWhisperError(HelixWhisperError error, const QString &message) bool appendWhisperMessageWordsLocally(const QStringList &words) { - auto *app = getIApp(); + auto *app = getApp(); MessageBuilder b; @@ -102,7 +102,7 @@ bool appendWhisperMessageWordsLocally(const QStringList &words) MessageElementFlag::Text, MessageColor::Text, FontStyle::ChatMediumBold); b.emplace("->", MessageElementFlag::Text, - getIApp()->getThemes()->messages.textColors.system); + getApp()->getThemes()->messages.textColors.system); b.emplace(words[1] + ":", MessageElementFlag::Text, MessageColor::Text, FontStyle::ChatMediumBold); @@ -177,12 +177,12 @@ bool appendWhisperMessageWordsLocally(const QStringList &words) b->flags.set(MessageFlag::Whisper); auto messagexD = b.release(); - getIApp()->getTwitch()->getWhispersChannel()->addMessage( + getApp()->getTwitch()->getWhispersChannel()->addMessage( messagexD, MessageContext::Original); if (getSettings()->inlineWhispers && !(getSettings()->streamerModeSuppressInlineWhispers && - getIApp()->getStreamerMode()->isEnabled())) + getApp()->getStreamerMode()->isEnabled())) { app->getTwitchAbstract()->forEachChannel( [&messagexD](ChannelPtr _channel) { @@ -210,7 +210,7 @@ QString sendWhisper(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage( diff --git a/src/controllers/commands/builtin/twitch/ShieldMode.cpp b/src/controllers/commands/builtin/twitch/ShieldMode.cpp index 1a7bf3a32..93c3d9c68 100644 --- a/src/controllers/commands/builtin/twitch/ShieldMode.cpp +++ b/src/controllers/commands/builtin/twitch/ShieldMode.cpp @@ -22,7 +22,7 @@ QString toggleShieldMode(const CommandContext &ctx, bool isActivating) return {}; } - auto user = getIApp()->getAccounts()->twitch.getCurrent(); + auto user = getApp()->getAccounts()->twitch.getCurrent(); // Avoid Helix calls without Client ID and/or OAuth Token if (user->isAnon()) diff --git a/src/controllers/commands/builtin/twitch/Shoutout.cpp b/src/controllers/commands/builtin/twitch/Shoutout.cpp index 8d9b65617..7a79b5a3e 100644 --- a/src/controllers/commands/builtin/twitch/Shoutout.cpp +++ b/src/controllers/commands/builtin/twitch/Shoutout.cpp @@ -23,7 +23,7 @@ QString sendShoutout(const CommandContext &ctx) return ""; } - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { channel->addSystemMessage("You must be logged in to send shoutout."); diff --git a/src/controllers/commands/builtin/twitch/StartCommercial.cpp b/src/controllers/commands/builtin/twitch/StartCommercial.cpp index f09316416..15b620440 100644 --- a/src/controllers/commands/builtin/twitch/StartCommercial.cpp +++ b/src/controllers/commands/builtin/twitch/StartCommercial.cpp @@ -98,7 +98,7 @@ QString startCommercial(const CommandContext &ctx) return ""; } - auto user = getIApp()->getAccounts()->twitch.getCurrent(); + auto user = getApp()->getAccounts()->twitch.getCurrent(); // Avoid Helix calls without Client ID and/or OAuth Token if (user->isAnon()) diff --git a/src/controllers/commands/builtin/twitch/Unban.cpp b/src/controllers/commands/builtin/twitch/Unban.cpp index 950af39b9..35f29f5de 100644 --- a/src/controllers/commands/builtin/twitch/Unban.cpp +++ b/src/controllers/commands/builtin/twitch/Unban.cpp @@ -108,7 +108,7 @@ QString unbanUser(const CommandContext &ctx) assert(!actions.value().empty()); - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage( diff --git a/src/controllers/commands/builtin/twitch/UpdateColor.cpp b/src/controllers/commands/builtin/twitch/UpdateColor.cpp index b0fb8e71f..15680c276 100644 --- a/src/controllers/commands/builtin/twitch/UpdateColor.cpp +++ b/src/controllers/commands/builtin/twitch/UpdateColor.cpp @@ -25,7 +25,7 @@ QString updateUserColor(const CommandContext &ctx) "The /color command only works in Twitch channels."); return ""; } - auto user = getIApp()->getAccounts()->twitch.getCurrent(); + auto user = getApp()->getAccounts()->twitch.getCurrent(); // Avoid Helix calls without Client ID and/or OAuth Token if (user->isAnon()) diff --git a/src/controllers/commands/builtin/twitch/Warn.cpp b/src/controllers/commands/builtin/twitch/Warn.cpp index c36ab681c..2a3cb1fa5 100644 --- a/src/controllers/commands/builtin/twitch/Warn.cpp +++ b/src/controllers/commands/builtin/twitch/Warn.cpp @@ -104,7 +104,7 @@ QString sendWarn(const CommandContext &ctx) assert(!actions.value().empty()); - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (currentUser->isAnon()) { ctx.channel->addSystemMessage("You must be logged in to warn someone!"); diff --git a/src/controllers/completion/TabCompletionModel.cpp b/src/controllers/completion/TabCompletionModel.cpp index 202cc9ec8..585fe3a08 100644 --- a/src/controllers/completion/TabCompletionModel.cpp +++ b/src/controllers/completion/TabCompletionModel.cpp @@ -39,7 +39,7 @@ void TabCompletionModel::updateResults(const QString &query, // Try plugins first bool done{}; std::tie(done, results) = - getIApp()->getPlugins()->updateCustomCompletions( + getApp()->getPlugins()->updateCustomCompletions( query, fullTextContent, cursorPosition, isFirstWord); if (done) { diff --git a/src/controllers/completion/sources/CommandSource.cpp b/src/controllers/completion/sources/CommandSource.cpp index 9eedaf622..29deff932 100644 --- a/src/controllers/completion/sources/CommandSource.cpp +++ b/src/controllers/completion/sources/CommandSource.cpp @@ -71,20 +71,20 @@ void CommandSource::initializeItems() std::vector commands; #ifdef CHATTERINO_HAVE_PLUGINS - for (const auto &command : getIApp()->getCommands()->pluginCommands()) + for (const auto &command : getApp()->getCommands()->pluginCommands()) { addCommand(command, commands); } #endif // Custom Chatterino commands - for (const auto &command : getIApp()->getCommands()->items) + for (const auto &command : getApp()->getCommands()->items) { addCommand(command.name, commands); } // Default Chatterino commands - auto x = getIApp()->getCommands()->getDefaultChatterinoCommandList(); + auto x = getApp()->getCommands()->getDefaultChatterinoCommandList(); for (const auto &command : x) { addCommand(command, commands); diff --git a/src/controllers/completion/sources/EmoteSource.cpp b/src/controllers/completion/sources/EmoteSource.cpp index ded6d72be..f5d04c9e0 100644 --- a/src/controllers/completion/sources/EmoteSource.cpp +++ b/src/controllers/completion/sources/EmoteSource.cpp @@ -88,7 +88,7 @@ void EmoteSource::addToStringList(QStringList &list, size_t maxCount, void EmoteSource::initializeFromChannel(const Channel *channel) { - auto *app = getIApp(); + auto *app = getApp(); std::vector emotes; const auto *tc = dynamic_cast(channel); diff --git a/src/controllers/filters/lang/Filter.cpp b/src/controllers/filters/lang/Filter.cpp index 1a2461661..2cda8a13b 100644 --- a/src/controllers/filters/lang/Filter.cpp +++ b/src/controllers/filters/lang/Filter.cpp @@ -12,7 +12,7 @@ namespace chatterino::filters { ContextMap buildContextMap(const MessagePtr &m, chatterino::Channel *channel) { - auto watchingChannel = getIApp()->getTwitch()->getWatchingChannel().get(); + auto watchingChannel = getApp()->getTwitch()->getWatchingChannel().get(); /* * Looking to add a new identifier to filters? Here's what to do: diff --git a/src/controllers/highlights/BadgeHighlightModel.cpp b/src/controllers/highlights/BadgeHighlightModel.cpp index e1d93c3bc..3b61a01bf 100644 --- a/src/controllers/highlights/BadgeHighlightModel.cpp +++ b/src/controllers/highlights/BadgeHighlightModel.cpp @@ -53,7 +53,7 @@ void BadgeHighlightModel::getRowFromItem(const HighlightBadge &item, setFilePathItem(row[Column::SoundPath], item.getSoundUrl()); setColorItem(row[Column::Color], *item.getColor()); - getIApp()->getTwitchBadges()->getBadgeIcon( + getApp()->getTwitchBadges()->getBadgeIcon( item.badgeName(), [item, row](QString /*name*/, const QIconPtr pixmap) { row[Column::Badge]->setData(QVariant(*pixmap), Qt::DecorationRole); }); diff --git a/src/controllers/highlights/HighlightController.cpp b/src/controllers/highlights/HighlightController.cpp index 3e15d7580..78d072a32 100644 --- a/src/controllers/highlights/HighlightController.cpp +++ b/src/controllers/highlights/HighlightController.cpp @@ -183,7 +183,7 @@ void rebuildReplyThreadHighlight(Settings &settings, void rebuildMessageHighlights(Settings &settings, std::vector &checks) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); QString currentUsername = currentUser->getUserName(); if (settings.enableSelfHighlight && !currentUsername.isEmpty() && @@ -442,9 +442,11 @@ std::ostream &operator<<(std::ostream &os, const HighlightResult &result) return os; } -void HighlightController::initialize(Settings &settings, - const Paths & /*paths*/) +HighlightController::HighlightController(Settings &settings, + AccountController *accounts) { + assert(accounts != nullptr); + this->rebuildListener_.addSetting(settings.enableSelfHighlight); this->rebuildListener_.addSetting(settings.enableSelfHighlightSound); this->rebuildListener_.addSetting(settings.enableSelfHighlightTaskbar); @@ -507,12 +509,12 @@ void HighlightController::initialize(Settings &settings, this->rebuildChecks(settings); }); - getIApp()->getAccounts()->twitch.currentUserChanged.connect( - [this, &settings] { + this->bConnections.emplace_back( + accounts->twitch.currentUserChanged.connect([this, &settings] { qCDebug(chatterinoHighlights) << "Rebuild checks because user swapped accounts"; this->rebuildChecks(settings); - }); + })); this->rebuildChecks(settings); } @@ -550,7 +552,7 @@ std::pair HighlightController::check( // Access for checking const auto checks = this->checks_.accessConst(); - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); auto self = (senderName == currentUser->getUserName()); for (const auto &check : *checks) diff --git a/src/controllers/highlights/HighlightController.hpp b/src/controllers/highlights/HighlightController.hpp index e05986a0e..c217f7bb2 100644 --- a/src/controllers/highlights/HighlightController.hpp +++ b/src/controllers/highlights/HighlightController.hpp @@ -1,9 +1,10 @@ #pragma once #include "common/FlagsEnum.hpp" -#include "common/Singleton.hpp" #include "common/UniqueAccess.hpp" +#include "singletons/Settings.hpp" +#include #include #include #include @@ -20,6 +21,7 @@ class Badge; struct MessageParseArgs; enum class MessageFlag : int64_t; using MessageFlags = FlagsEnum; +class AccountController; struct HighlightResult { HighlightResult(bool _alert, bool _playSound, @@ -83,10 +85,10 @@ struct HighlightCheck { Checker cb; }; -class HighlightController final : public Singleton +class HighlightController final { public: - void initialize(Settings &settings, const Paths &paths) override; + HighlightController(Settings &settings, AccountController *accounts); /** * @brief Checks the given message parameters if it matches our internal checks, and returns a result @@ -108,6 +110,7 @@ private: pajlada::SettingListener rebuildListener_; pajlada::Signals::SignalHolder signalHolder_; + std::vector bConnections; }; } // namespace chatterino diff --git a/src/controllers/highlights/HighlightModel.cpp b/src/controllers/highlights/HighlightModel.cpp index 974653115..52f679375 100644 --- a/src/controllers/highlights/HighlightModel.cpp +++ b/src/controllers/highlights/HighlightModel.cpp @@ -519,7 +519,7 @@ void HighlightModel::customRowSetData(const std::vector &row, break; } - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); } } // namespace chatterino diff --git a/src/controllers/highlights/UserHighlightModel.cpp b/src/controllers/highlights/UserHighlightModel.cpp index b28866e6d..2c5bfec35 100644 --- a/src/controllers/highlights/UserHighlightModel.cpp +++ b/src/controllers/highlights/UserHighlightModel.cpp @@ -109,7 +109,7 @@ void UserHighlightModel::customRowSetData( break; } - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); } // row into vector item diff --git a/src/controllers/hotkeys/Hotkey.cpp b/src/controllers/hotkeys/Hotkey.cpp index 9a2392d13..557decd70 100644 --- a/src/controllers/hotkeys/Hotkey.cpp +++ b/src/controllers/hotkeys/Hotkey.cpp @@ -58,7 +58,7 @@ std::vector Hotkey::arguments() const QString Hotkey::getCategory() const { - return getIApp()->getHotkeys()->categoryDisplayName(this->category_); + return getApp()->getHotkeys()->categoryDisplayName(this->category_); } Qt::ShortcutContext Hotkey::getContext() const diff --git a/src/controllers/hotkeys/HotkeyController.hpp b/src/controllers/hotkeys/HotkeyController.hpp index 57187ca8b..f5d5842ef 100644 --- a/src/controllers/hotkeys/HotkeyController.hpp +++ b/src/controllers/hotkeys/HotkeyController.hpp @@ -1,7 +1,6 @@ #pragma once #include "common/SignalVector.hpp" -#include "common/Singleton.hpp" #include "controllers/hotkeys/HotkeyCategory.hpp" #include @@ -18,7 +17,7 @@ class Hotkey; class HotkeyModel; -class HotkeyController final : public Singleton +class HotkeyController final { public: using HotkeyFunction = std::function)>; @@ -31,7 +30,7 @@ public: HotkeyMap actionMap, QWidget *parent); - void save() override; + void save(); std::shared_ptr getHotkeyByName(QString name); /** * @brief returns a QKeySequence that perfoms the actions requested. diff --git a/src/controllers/ignores/IgnoreController.cpp b/src/controllers/ignores/IgnoreController.cpp index 8d064ca8e..7922b16dd 100644 --- a/src/controllers/ignores/IgnoreController.cpp +++ b/src/controllers/ignores/IgnoreController.cpp @@ -32,7 +32,7 @@ bool isIgnoredMessage(IgnoredMessageParameters &¶ms) { auto sourceUserID = params.twitchUserID; - bool isBlocked = getIApp() + bool isBlocked = getApp() ->getAccounts() ->twitch.getCurrent() ->blockedUserIds() diff --git a/src/controllers/ignores/IgnorePhrase.cpp b/src/controllers/ignores/IgnorePhrase.cpp index 735e87745..eacd7e4bd 100644 --- a/src/controllers/ignores/IgnorePhrase.cpp +++ b/src/controllers/ignores/IgnorePhrase.cpp @@ -95,7 +95,7 @@ bool IgnorePhrase::containsEmote() const { if (!this->emotesChecked_) { - const auto &accvec = getIApp()->getAccounts()->twitch.accounts; + const auto &accvec = getApp()->getAccounts()->twitch.accounts; for (const auto &acc : accvec) { const auto &accemotes = *acc->accessEmotes(); diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index 1fe0036a7..b3800dd21 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -17,9 +17,10 @@ #include namespace ranges = std::ranges; + namespace chatterino { -void NotificationController::initialize(Settings &settings, const Paths &paths) +NotificationController::NotificationController() { for (const QString &channelName : this->twitchSetting_.getValue()) { @@ -34,14 +35,17 @@ void NotificationController::initialize(Settings &settings, const Paths &paths) this->channelMap[Platform::Twitch].raw()); }); - this->fetchFakeChannels(); - QObject::connect(&this->liveStatusTimer_, &QTimer::timeout, [this] { this->fetchFakeChannels(); }); this->liveStatusTimer_.start(60 * 1000); } +void NotificationController::initialize() +{ + this->fetchFakeChannels(); +} + void NotificationController::updateChannelNotification( const QString &channelName, Platform p) { @@ -92,7 +96,7 @@ void NotificationController::playSound() const getSettings()->notificationPathSound.getValue()) : QUrl("qrc:/sounds/ping2.wav"); - getIApp()->getSound()->play(highlightSoundUrl); + getApp()->getSound()->play(highlightSoundUrl); } NotificationModel *NotificationController::createModel(QObject *parent, @@ -109,7 +113,7 @@ void NotificationController::notifyTwitchChannelLive( bool showNotification = !(getSettings()->suppressInitialLiveNotification && payload.isInitialUpdate) && - !(getIApp()->getStreamerMode()->isEnabled() && + !(getApp()->getStreamerMode()->isEnabled() && getSettings()->streamerModeSuppressLiveNotifications); bool playedSound = false; @@ -118,7 +122,7 @@ void NotificationController::notifyTwitchChannelLive( { if (Toasts::isEnabled()) { - getIApp()->getToasts()->sendChannelNotification( + getApp()->getToasts()->sendChannelNotification( payload.channelName, payload.title, Platform::Twitch); } if (getSettings()->notificationPlaySound) @@ -128,7 +132,7 @@ void NotificationController::notifyTwitchChannelLive( } if (getSettings()->notificationFlashTaskbar) { - getIApp()->getWindows()->sendAlert(); + getApp()->getWindows()->sendAlert(); } } @@ -136,7 +140,7 @@ void NotificationController::notifyTwitchChannelLive( MessageBuilder builder; TwitchMessageBuilder::liveMessage(payload.displayName, &builder); builder.message().id = payload.channelId; - getIApp()->getTwitch()->getLiveChannel()->addMessage( + getApp()->getTwitch()->getLiveChannel()->addMessage( builder.release(), MessageContext::Original); // Notify on all channels with a ping sound @@ -152,7 +156,7 @@ void NotificationController::notifyTwitchChannelOffline(const QString &id) const { // "delete" old 'CHANNEL is live' message LimitedQueueSnapshot snapshot = - getIApp()->getTwitch()->getLiveChannel()->getMessageSnapshot(); + getApp()->getTwitch()->getLiveChannel()->getMessageSnapshot(); int snapshotLength = static_cast(snapshot.size()); int end = std::max(0, snapshotLength - 200); @@ -177,7 +181,7 @@ void NotificationController::fetchFakeChannels() for (size_t i = 0; i < channelMap[Platform::Twitch].raw().size(); i++) { const auto &name = channelMap[Platform::Twitch].raw()[i]; - auto chan = getIApp()->getTwitchAbstract()->getChannelOrEmpty(name); + auto chan = getApp()->getTwitchAbstract()->getChannelOrEmpty(name); if (chan->isEmpty()) { channels.push_back(name); diff --git a/src/controllers/notifications/NotificationController.hpp b/src/controllers/notifications/NotificationController.hpp index fa802c1ec..e7ad1731f 100644 --- a/src/controllers/notifications/NotificationController.hpp +++ b/src/controllers/notifications/NotificationController.hpp @@ -2,7 +2,6 @@ #include "common/ChatterinoSetting.hpp" #include "common/SignalVector.hpp" -#include "common/Singleton.hpp" #include "util/QCompareCaseInsensitive.hpp" #include @@ -19,10 +18,13 @@ enum class Platform : uint8_t { Twitch, // 0 }; -class NotificationController final : public Singleton +class NotificationController final { public: - void initialize(Settings &settings, const Paths &paths) override; + NotificationController(); + + // Perform an initial load so we don't have to wait for the timer + void initialize(); bool isChannelNotified(const QString &channelName, Platform p) const; void updateChannelNotification(const QString &channelName, Platform p); diff --git a/src/controllers/plugins/LuaAPI.cpp b/src/controllers/plugins/LuaAPI.cpp index d70be6489..03d11750a 100644 --- a/src/controllers/plugins/LuaAPI.cpp +++ b/src/controllers/plugins/LuaAPI.cpp @@ -65,7 +65,7 @@ namespace chatterino::lua::api { int c2_register_command(lua_State *L) { - auto *pl = getIApp()->getPlugins()->getPluginByStatePtr(L); + auto *pl = getApp()->getPlugins()->getPluginByStatePtr(L); if (pl == nullptr) { luaL_error(L, "internal error: no plugin"); @@ -99,7 +99,7 @@ int c2_register_command(lua_State *L) int c2_register_callback(lua_State *L) { - auto *pl = getIApp()->getPlugins()->getPluginByStatePtr(L); + auto *pl = getApp()->getPlugins()->getPluginByStatePtr(L); if (pl == nullptr) { luaL_error(L, "internal error: no plugin"); @@ -133,7 +133,7 @@ int c2_register_callback(lua_State *L) int c2_log(lua_State *L) { - auto *pl = getIApp()->getPlugins()->getPluginByStatePtr(L); + auto *pl = getApp()->getPlugins()->getPluginByStatePtr(L); if (pl == nullptr) { luaL_error(L, "c2_log: internal error: no plugin?"); @@ -154,7 +154,7 @@ int c2_log(lua_State *L) int c2_later(lua_State *L) { - auto *pl = getIApp()->getPlugins()->getPluginByStatePtr(L); + auto *pl = getApp()->getPlugins()->getPluginByStatePtr(L); if (pl == nullptr) { return luaL_error(L, "c2.later: internal error: no plugin?"); @@ -257,7 +257,7 @@ int g_load(lua_State *L) int loadfile(lua_State *L, const QString &str) { - auto *pl = getIApp()->getPlugins()->getPluginByStatePtr(L); + auto *pl = getApp()->getPlugins()->getPluginByStatePtr(L); if (pl == nullptr) { return luaL_error(L, "loadfile: internal error: no plugin?"); @@ -307,7 +307,7 @@ int searcherAbsolute(lua_State *L) name = name.replace('.', QDir::separator()); QString filename; - auto *pl = getIApp()->getPlugins()->getPluginByStatePtr(L); + auto *pl = getApp()->getPlugins()->getPluginByStatePtr(L); if (pl == nullptr) { return luaL_error(L, "searcherAbsolute: internal error: no plugin?"); @@ -348,7 +348,7 @@ int searcherRelative(lua_State *L) int g_print(lua_State *L) { - auto *pl = getIApp()->getPlugins()->getPluginByStatePtr(L); + auto *pl = getApp()->getPlugins()->getPluginByStatePtr(L); if (pl == nullptr) { luaL_error(L, "c2_print: internal error: no plugin?"); diff --git a/src/controllers/plugins/Plugin.cpp b/src/controllers/plugins/Plugin.cpp index 4a8f89f09..dcf7357e8 100644 --- a/src/controllers/plugins/Plugin.cpp +++ b/src/controllers/plugins/Plugin.cpp @@ -197,7 +197,7 @@ bool Plugin::registerCommand(const QString &name, const QString &functionName) return false; } - auto ok = getIApp()->getCommands()->registerPluginCommand(name); + auto ok = getApp()->getCommands()->registerPluginCommand(name); if (!ok) { return false; diff --git a/src/controllers/plugins/PluginController.cpp b/src/controllers/plugins/PluginController.cpp index 64e2a96b0..5ca77ed40 100644 --- a/src/controllers/plugins/PluginController.cpp +++ b/src/controllers/plugins/PluginController.cpp @@ -35,10 +35,8 @@ PluginController::PluginController(const Paths &paths_) { } -void PluginController::initialize(Settings &settings, const Paths &paths) +void PluginController::initialize(Settings &settings) { - (void)paths; - // actuallyInitialize will be called by this connection settings.pluginsEnabled.connect([this](bool enabled) { if (enabled) @@ -354,7 +352,7 @@ bool PluginController::reload(const QString &id) } for (const auto &[cmd, _] : it->second->ownedCommands) { - getIApp()->getCommands()->unregisterPluginCommand(cmd); + getApp()->getCommands()->unregisterPluginCommand(cmd); } it->second->ownedCommands.clear(); QDir loadDir = it->second->loadDirectory_; diff --git a/src/controllers/plugins/PluginController.hpp b/src/controllers/plugins/PluginController.hpp index 099c40a70..50bc88c7e 100644 --- a/src/controllers/plugins/PluginController.hpp +++ b/src/controllers/plugins/PluginController.hpp @@ -2,7 +2,6 @@ #ifdef CHATTERINO_HAVE_PLUGINS -# include "common/Singleton.hpp" # include "controllers/commands/CommandContext.hpp" # include "controllers/plugins/Plugin.hpp" @@ -24,14 +23,14 @@ namespace chatterino { class Paths; -class PluginController : public Singleton +class PluginController { const Paths &paths; public: explicit PluginController(const Paths &paths_); - void initialize(Settings &settings, const Paths &paths) override; + void initialize(Settings &settings); QString tryExecPluginCommand(const QString &commandName, const CommandContext &ctx); diff --git a/src/controllers/plugins/api/ChannelRef.cpp b/src/controllers/plugins/api/ChannelRef.cpp index 64b146f55..68cf15980 100644 --- a/src/controllers/plugins/api/ChannelRef.cpp +++ b/src/controllers/plugins/api/ChannelRef.cpp @@ -174,7 +174,7 @@ int ChannelRef::send_message(lua_State *L) text = text.replace('\n', ' '); if (execcmds) { - text = getIApp()->getCommands()->execCommand(text, that, false); + text = getApp()->getCommands()->execCommand(text, that, false); } that->sendMessage(text); return 0; @@ -300,7 +300,7 @@ int ChannelRef::get_by_name(lua_State *L) lua_pushnil(L); return 1; } - auto chn = getIApp()->getTwitchAbstract()->getChannelOrEmpty(name); + auto chn = getApp()->getTwitchAbstract()->getChannelOrEmpty(name); lua::push(L, chn); return 1; } @@ -324,7 +324,7 @@ int ChannelRef::get_by_twitch_id(lua_State *L) lua_pushnil(L); return 1; } - auto chn = getIApp()->getTwitch()->getChannelOrEmptyByID(id); + auto chn = getApp()->getTwitch()->getChannelOrEmptyByID(id); lua::push(L, chn); return 1; diff --git a/src/controllers/plugins/api/HTTPRequest.cpp b/src/controllers/plugins/api/HTTPRequest.cpp index 6defabb38..eba2773ad 100644 --- a/src/controllers/plugins/api/HTTPRequest.cpp +++ b/src/controllers/plugins/api/HTTPRequest.cpp @@ -309,7 +309,7 @@ int HTTPRequest::create(lua_State *L) L, "cannot get method (1st argument of HTTPRequest.create, " "expected a string)"); } - auto *pl = getIApp()->getPlugins()->getPluginByStatePtr(L); + auto *pl = getApp()->getPlugins()->getPluginByStatePtr(L); if (!pl->hasHTTPPermissionFor(parsedurl)) { return luaL_error( diff --git a/src/controllers/twitch/LiveController.hpp b/src/controllers/twitch/LiveController.hpp index 94b538957..767004061 100644 --- a/src/controllers/twitch/LiveController.hpp +++ b/src/controllers/twitch/LiveController.hpp @@ -1,6 +1,5 @@ #pragma once -#include "common/Singleton.hpp" #include "util/QStringHash.hpp" #include @@ -26,7 +25,7 @@ public: virtual void add(const std::shared_ptr &newChannel) = 0; }; -class TwitchLiveController : public ITwitchLiveController, public Singleton +class TwitchLiveController : public ITwitchLiveController { public: // Controls how often all channels have their stream status refreshed diff --git a/src/messages/Image.cpp b/src/messages/Image.cpp index 307069691..f74bba164 100644 --- a/src/messages/Image.cpp +++ b/src/messages/Image.cpp @@ -50,7 +50,7 @@ Frames::Frames(QList &&frames) DebugCount::increase("animated images"); this->gifTimerConnection_ = - getIApp()->getEmotes()->getGIFTimer().signal.connect([this] { + getApp()->getEmotes()->getGIFTimer().signal.connect([this] { this->advance(); }); } @@ -67,7 +67,7 @@ Frames::Frames(QList &&frames) else { this->durationOffset_ = std::min( - int(getIApp()->getEmotes()->getGIFTimer().position() % totalLength), + int(getApp()->getEmotes()->getGIFTimer().position() % totalLength), 60000); } this->processOffset(); @@ -242,7 +242,7 @@ void assignFrames(std::weak_ptr weak, QList parsed) isPushQueued = true; postToThread([] { isPushQueued = false; - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); }); } }; diff --git a/src/messages/MessageBuilder.cpp b/src/messages/MessageBuilder.cpp index c7959da93..3e91d04dd 100644 --- a/src/messages/MessageBuilder.cpp +++ b/src/messages/MessageBuilder.cpp @@ -203,7 +203,7 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username, MessageBuilder::MessageBuilder(const BanAction &action, uint32_t count) : MessageBuilder() { - auto current = getIApp()->getAccounts()->twitch.getCurrent(); + auto current = getApp()->getAccounts()->twitch.getCurrent(); this->emplace(); this->message().flags.set(MessageFlag::System); @@ -676,7 +676,7 @@ void MessageBuilder::addLink(const linkparser::Parsed &parsedLink, MessageElementFlag::Text, this->textColor_); } - getIApp()->getLinkResolver()->resolve(el->linkInfo()); + getApp()->getLinkResolver()->resolve(el->linkInfo()); } void MessageBuilder::addIrcMessageText(const QString &text) @@ -686,7 +686,7 @@ void MessageBuilder::addIrcMessageText(const QString &text) auto words = text.split(' '); MessageColor defaultColorType = MessageColor::Text; const auto &defaultColor = - defaultColorType.getColor(*getIApp()->getThemes()); + defaultColorType.getColor(*getApp()->getThemes()); QColor textColor = defaultColor; int fg = -1; int bg = -1; @@ -728,7 +728,7 @@ void MessageBuilder::addIrcMessageText(const QString &text) if (fg >= 0 && fg <= 98) { textColor = IRC_COLORS[fg]; - getIApp()->getThemes()->normalizeColor(textColor); + getApp()->getThemes()->normalizeColor(textColor); } else { @@ -768,7 +768,7 @@ void MessageBuilder::addIrcMessageText(const QString &text) if (fg >= 0 && fg <= 98) { textColor = IRC_COLORS[fg]; - getIApp()->getThemes()->normalizeColor(textColor); + getApp()->getThemes()->normalizeColor(textColor); } else { @@ -810,7 +810,7 @@ void MessageBuilder::addIrcWord(const QString &text, const QColor &color, bool addSpace) { this->textColor_ = color; - for (auto &variant : getIApp()->getEmotes()->getEmojis()->parse(text)) + for (auto &variant : getApp()->getEmotes()->getEmojis()->parse(text)) { boost::apply_visitor( [&](auto &&arg) { diff --git a/src/messages/MessageElement.cpp b/src/messages/MessageElement.cpp index c49e53802..8d994ef22 100644 --- a/src/messages/MessageElement.cpp +++ b/src/messages/MessageElement.cpp @@ -454,7 +454,7 @@ TextElement::TextElement(const QString &text, MessageElementFlags flags, void TextElement::addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) { - auto *app = getIApp(); + auto *app = getApp(); if (flags.hasAny(this->getFlags())) { @@ -566,7 +566,7 @@ SingleLineTextElement::SingleLineTextElement(const QString &text, void SingleLineTextElement::addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) { - auto *app = getIApp(); + auto *app = getApp(); if (flags.hasAny(this->getFlags())) { diff --git a/src/messages/SharedMessageBuilder.cpp b/src/messages/SharedMessageBuilder.cpp index 52349107f..69a216502 100644 --- a/src/messages/SharedMessageBuilder.cpp +++ b/src/messages/SharedMessageBuilder.cpp @@ -156,7 +156,7 @@ void SharedMessageBuilder::parseHighlights() } auto badges = SharedMessageBuilder::parseBadgeTag(this->tags); - auto [highlighted, highlightResult] = getIApp()->getHighlights()->check( + auto [highlighted, highlightResult] = getApp()->getHighlights()->check( this->args, badges, this->message().loginName, this->originalMessage_, this->message().flags); @@ -203,7 +203,7 @@ void SharedMessageBuilder::triggerHighlights( const QString &channelName, bool playSound, const std::optional &customSoundUrl, bool windowAlert) { - if (getIApp()->getStreamerMode()->isEnabled() && + if (getApp()->getStreamerMode()->isEnabled() && getSettings()->streamerModeMuteMentions) { // We are in streamer mode with muting mention sounds enabled. Do nothing. @@ -232,12 +232,12 @@ void SharedMessageBuilder::triggerHighlights( { soundUrl = getFallbackHighlightSound(); } - getIApp()->getSound()->play(soundUrl); + getApp()->getSound()->play(soundUrl); } if (windowAlert) { - getIApp()->getWindows()->sendAlert(); + getApp()->getWindows()->sendAlert(); } } diff --git a/src/messages/layouts/MessageLayout.cpp b/src/messages/layouts/MessageLayout.cpp index 8a20b05cc..10397d93c 100644 --- a/src/messages/layouts/MessageLayout.cpp +++ b/src/messages/layouts/MessageLayout.cpp @@ -88,7 +88,7 @@ bool MessageLayout::layout(int width, float scale, float imageScale, this->currentLayoutWidth_ = width; // check if layout state changed - const auto layoutGeneration = getIApp()->getWindows()->getGeneration(); + const auto layoutGeneration = getApp()->getWindows()->getGeneration(); if (this->layoutState_ != layoutGeneration) { layoutRequired = true; @@ -166,7 +166,7 @@ void MessageLayout::actuallyLayout(int width, MessageElementFlags flags) { if (hideModerationActions || (getSettings()->streamerModeHideModActions && - getIApp()->getStreamerMode()->isEnabled())) + getApp()->getStreamerMode()->isEnabled())) { continue; } diff --git a/src/messages/layouts/MessageLayoutContainer.cpp b/src/messages/layouts/MessageLayoutContainer.cpp index 5c3942763..a4abee58d 100644 --- a/src/messages/layouts/MessageLayoutContainer.cpp +++ b/src/messages/layouts/MessageLayoutContainer.cpp @@ -48,7 +48,7 @@ void MessageLayoutContainer::beginLayout(int width, float scale, this->imageScale_ = imageScale; this->flags_ = flags; auto mediumFontMetrics = - getIApp()->getFonts()->getFontMetrics(FontStyle::ChatMedium, scale); + getApp()->getFonts()->getFontMetrics(FontStyle::ChatMedium, scale); this->textLineHeight_ = mediumFontMetrics.height(); this->spaceWidth_ = mediumFontMetrics.horizontalAdvance(' '); this->dotdotdotWidth_ = mediumFontMetrics.horizontalAdvance("..."); diff --git a/src/providers/ffz/FfzBadges.cpp b/src/providers/ffz/FfzBadges.cpp index 561f47ea3..574d27787 100644 --- a/src/providers/ffz/FfzBadges.cpp +++ b/src/providers/ffz/FfzBadges.cpp @@ -1,4 +1,4 @@ -#include "FfzBadges.hpp" +#include "providers/ffz/FfzBadges.hpp" #include "common/network/NetworkRequest.hpp" #include "common/network/NetworkResult.hpp" @@ -17,11 +17,6 @@ namespace chatterino { -void FfzBadges::initialize(Settings &settings, const Paths &paths) -{ - this->load(); -} - std::vector FfzBadges::getUserBadges(const UserId &id) { std::vector badges; diff --git a/src/providers/ffz/FfzBadges.hpp b/src/providers/ffz/FfzBadges.hpp index 8d021624a..d24579451 100644 --- a/src/providers/ffz/FfzBadges.hpp +++ b/src/providers/ffz/FfzBadges.hpp @@ -1,7 +1,6 @@ #pragma once #include "common/Aliases.hpp" -#include "common/Singleton.hpp" #include "util/QStringHash.hpp" #include "util/ThreadGuard.hpp" @@ -19,10 +18,9 @@ namespace chatterino { struct Emote; using EmotePtr = std::shared_ptr; -class FfzBadges : public Singleton +class FfzBadges { public: - void initialize(Settings &settings, const Paths &paths) override; FfzBadges() = default; struct Badge { @@ -33,9 +31,9 @@ public: std::vector getUserBadges(const UserId &id); std::optional getBadge(int badgeID) const; -private: void load(); +private: std::shared_mutex mutex_; // userBadges points a user ID to the list of badges they have diff --git a/src/providers/irc/Irc2.cpp b/src/providers/irc/Irc2.cpp index 385c76bae..c51a5f323 100644 --- a/src/providers/irc/Irc2.cpp +++ b/src/providers/irc/Irc2.cpp @@ -22,7 +22,7 @@ namespace { QString configPath() { - return combinePath(getIApp()->getPaths().settingsDirectory, "irc.json"); + return combinePath(getApp()->getPaths().settingsDirectory, "irc.json"); } class Model : public SignalVectorModel diff --git a/src/providers/irc/IrcServer.cpp b/src/providers/irc/IrcServer.cpp index 24b8c39e1..a5148c9c7 100644 --- a/src/providers/irc/IrcServer.cpp +++ b/src/providers/irc/IrcServer.cpp @@ -245,7 +245,7 @@ void IrcServer::privateMessageReceived(Communi::IrcPrivateMessage *message) if (highlighted && showInMentions) { - getIApp()->getTwitch()->getMentionsChannel()->addMessage( + getApp()->getTwitch()->getMentionsChannel()->addMessage( msg, MessageContext::Original); } } diff --git a/src/providers/seventv/SeventvAPI.hpp b/src/providers/seventv/SeventvAPI.hpp index c47f9dd33..5ee5d9b61 100644 --- a/src/providers/seventv/SeventvAPI.hpp +++ b/src/providers/seventv/SeventvAPI.hpp @@ -1,7 +1,5 @@ #pragma once -#include "common/Singleton.hpp" - #include class QString; @@ -11,7 +9,7 @@ namespace chatterino { class NetworkResult; -class SeventvAPI : public Singleton +class SeventvAPI final { using ErrorCallback = std::function; template @@ -19,7 +17,7 @@ class SeventvAPI : public Singleton public: SeventvAPI() = default; - ~SeventvAPI() override = default; + ~SeventvAPI() = default; SeventvAPI(const SeventvAPI &) = delete; SeventvAPI(SeventvAPI &&) = delete; diff --git a/src/providers/seventv/SeventvBadges.hpp b/src/providers/seventv/SeventvBadges.hpp index 725528916..c9d0efad5 100644 --- a/src/providers/seventv/SeventvBadges.hpp +++ b/src/providers/seventv/SeventvBadges.hpp @@ -1,7 +1,6 @@ #pragma once #include "common/Aliases.hpp" -#include "common/Singleton.hpp" #include "util/QStringHash.hpp" #include @@ -16,7 +15,7 @@ namespace chatterino { struct Emote; using EmotePtr = std::shared_ptr; -class SeventvBadges : public Singleton +class SeventvBadges { public: // Return the badge, if any, that is assigned to the user diff --git a/src/providers/seventv/SeventvEmotes.cpp b/src/providers/seventv/SeventvEmotes.cpp index ae9376c01..896a50e1b 100644 --- a/src/providers/seventv/SeventvEmotes.cpp +++ b/src/providers/seventv/SeventvEmotes.cpp @@ -217,7 +217,7 @@ void SeventvEmotes::loadGlobalEmotes() qCDebug(chatterinoSeventv) << "Loading 7TV Global Emotes"; - getIApp()->getSeventvAPI()->getEmoteSet( + getApp()->getSeventvAPI()->getEmoteSet( u"global"_s, [this](const auto &json) { QJsonArray parsedEmotes = json["emotes"].toArray(); @@ -246,7 +246,7 @@ void SeventvEmotes::loadChannelEmotes( qCDebug(chatterinoSeventv) << "Reloading 7TV Channel Emotes" << channelId << manualRefresh; - getIApp()->getSeventvAPI()->getUserByTwitchID( + getApp()->getSeventvAPI()->getUserByTwitchID( channelId, [callback = std::move(callback), channel, channelId, manualRefresh](const auto &json) { @@ -405,7 +405,7 @@ void SeventvEmotes::getEmoteSet( { qCDebug(chatterinoSeventv) << "Loading 7TV Emote Set" << emoteSetId; - getIApp()->getSeventvAPI()->getEmoteSet( + getApp()->getSeventvAPI()->getEmoteSet( emoteSetId, [callback = std::move(successCallback), emoteSetId](const auto &json) { auto parsedEmotes = json["emotes"].toArray(); diff --git a/src/providers/seventv/SeventvEventAPI.cpp b/src/providers/seventv/SeventvEventAPI.cpp index 82234a99c..294f95ee2 100644 --- a/src/providers/seventv/SeventvEventAPI.cpp +++ b/src/providers/seventv/SeventvEventAPI.cpp @@ -348,7 +348,7 @@ void SeventvEventAPI::onUserUpdate(const Dispatch &dispatch) void SeventvEventAPI::onCosmeticCreate(const CosmeticCreateDispatch &cosmetic) { - auto *badges = getIApp()->getSeventvBadges(); + auto *badges = getApp()->getSeventvBadges(); switch (cosmetic.kind) { case CosmeticKind::Badge: { @@ -363,7 +363,7 @@ void SeventvEventAPI::onCosmeticCreate(const CosmeticCreateDispatch &cosmetic) void SeventvEventAPI::onEntitlementCreate( const EntitlementCreateDeleteDispatch &entitlement) { - auto *badges = getIApp()->getSeventvBadges(); + auto *badges = getApp()->getSeventvBadges(); switch (entitlement.kind) { case CosmeticKind::Badge: { @@ -379,7 +379,7 @@ void SeventvEventAPI::onEntitlementCreate( void SeventvEventAPI::onEntitlementDelete( const EntitlementCreateDeleteDispatch &entitlement) { - auto *badges = getIApp()->getSeventvBadges(); + auto *badges = getApp()->getSeventvBadges(); switch (entitlement.kind) { case CosmeticKind::Badge: { diff --git a/src/providers/twitch/IrcMessageHandler.cpp b/src/providers/twitch/IrcMessageHandler.cpp index 74bc00035..7660cd115 100644 --- a/src/providers/twitch/IrcMessageHandler.cpp +++ b/src/providers/twitch/IrcMessageHandler.cpp @@ -132,7 +132,7 @@ void updateReplyParticipatedStatus(const QVariantMap &tags, bool isNew) { const auto ¤tLogin = - getIApp()->getAccounts()->twitch.getCurrent()->getUserName(); + getApp()->getAccounts()->twitch.getCurrent()->getUserName(); if (thread->subscribed()) { @@ -390,7 +390,7 @@ std::vector parseNoticeMessage(Communi::IrcNoticeMessage *message) { const auto linkColor = MessageColor(MessageColor::Link); const auto accountsLink = Link(Link::OpenAccountsPage, QString()); - const auto curUser = getIApp()->getAccounts()->twitch.getCurrent(); + const auto curUser = getApp()->getAccounts()->twitch.getCurrent(); const auto expirationText = QString("Login expired for user \"%1\"!") .arg(curUser->getUserName()); const auto loginPromptText = QString("Try adding your account again."); @@ -692,7 +692,7 @@ void IrcMessageHandler::handlePrivMessage(Communi::IrcPrivateMessage *message, if (twitchChannel != nullptr) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (message->tag("user-id") == currentUser->getUserId()) { auto badgesTag = message->tag("badges"); @@ -736,7 +736,7 @@ void IrcMessageHandler::handleRoomStateMessage(Communi::IrcMessage *message) { return; } - auto chan = getIApp()->getTwitchAbstract()->getChannelOrEmpty(chanName); + auto chan = getApp()->getTwitchAbstract()->getChannelOrEmpty(chanName); auto *twitchChannel = dynamic_cast(chan.get()); if (!twitchChannel) @@ -798,7 +798,7 @@ void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message) } // get channel - auto chan = getIApp()->getTwitchAbstract()->getChannelOrEmpty(chanName); + auto chan = getApp()->getTwitchAbstract()->getChannelOrEmpty(chanName); if (chan->isEmpty()) { @@ -821,10 +821,10 @@ void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message) chan->addOrReplaceTimeout(std::move(clearChat.message)); // refresh all - getIApp()->getWindows()->repaintVisibleChatWidgets(chan.get()); + getApp()->getWindows()->repaintVisibleChatWidgets(chan.get()); if (getSettings()->hideModerated) { - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); } } @@ -843,7 +843,7 @@ void IrcMessageHandler::handleClearMessageMessage(Communi::IrcMessage *message) } // get channel - auto chan = getIApp()->getTwitchAbstract()->getChannelOrEmpty(chanName); + auto chan = getApp()->getTwitchAbstract()->getChannelOrEmpty(chanName); if (chan->isEmpty()) { @@ -875,7 +875,7 @@ void IrcMessageHandler::handleClearMessageMessage(Communi::IrcMessage *message) void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); // set received emote-sets, used in TwitchAccount::loadUserstateEmotes bool emoteSetsChanged = currentUser->setUserstateEmoteSets( @@ -892,7 +892,7 @@ void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message) return; } - auto c = getIApp()->getTwitchAbstract()->getChannelOrEmpty(channelName); + auto c = getApp()->getTwitchAbstract()->getChannelOrEmpty(channelName); if (c->isEmpty()) { return; @@ -927,7 +927,7 @@ void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message) void IrcMessageHandler::handleGlobalUserStateMessage( Communi::IrcMessage *message) { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); // set received emote-sets, this time used to initially load emotes // NOTE: this should always return true unless we reconnect @@ -947,7 +947,7 @@ void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *ircMessage) args.isReceivedWhisper = true; - auto *c = getIApp()->getTwitch()->getWhispersChannel().get(); + auto *c = getApp()->getTwitch()->getWhispersChannel().get(); TwitchMessageBuilder builder( c, ircMessage, args, @@ -963,11 +963,11 @@ void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *ircMessage) MessagePtr message = builder.build(); builder.triggerHighlights(); - getIApp()->getTwitch()->setLastUserThatWhisperedMe(builder.userName); + getApp()->getTwitch()->setLastUserThatWhisperedMe(builder.userName); if (message->flags.has(MessageFlag::ShowInMentions)) { - getIApp()->getTwitch()->getMentionsChannel()->addMessage( + getApp()->getTwitch()->getMentionsChannel()->addMessage( message, MessageContext::Original); } @@ -979,13 +979,12 @@ void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *ircMessage) if (getSettings()->inlineWhispers && !(getSettings()->streamerModeSuppressInlineWhispers && - getIApp()->getStreamerMode()->isEnabled())) + getApp()->getStreamerMode()->isEnabled())) { - getIApp()->getTwitchAbstract()->forEachChannel( - [&message, overrideFlags](ChannelPtr channel) { - channel->addMessage(message, MessageContext::Repost, - overrideFlags); - }); + getApp()->getTwitchAbstract()->forEachChannel([&message, overrideFlags]( + ChannelPtr channel) { + channel->addMessage(message, MessageContext::Repost, overrideFlags); + }); } } @@ -1118,7 +1117,7 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message) { // Notice wasn't targeted at a single channel, send to all twitch // channels - getIApp()->getTwitch()->forEachChannelAndSpecialChannels( + getApp()->getTwitch()->forEachChannelAndSpecialChannels( [msg](const auto &c) { c->addMessage(msg, MessageContext::Original); }); @@ -1127,7 +1126,7 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message) } auto channel = - getIApp()->getTwitchAbstract()->getChannelOrEmpty(channelName); + getApp()->getTwitchAbstract()->getChannelOrEmpty(channelName); if (channel->isEmpty()) { @@ -1210,7 +1209,7 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message) void IrcMessageHandler::handleJoinMessage(Communi::IrcMessage *message) { - auto channel = getIApp()->getTwitchAbstract()->getChannelOrEmpty( + auto channel = getApp()->getTwitchAbstract()->getChannelOrEmpty( message->parameter(0).remove(0, 1)); auto *twitchChannel = dynamic_cast(channel.get()); @@ -1220,7 +1219,7 @@ void IrcMessageHandler::handleJoinMessage(Communi::IrcMessage *message) } if (message->nick() == - getIApp()->getAccounts()->twitch.getCurrent()->getUserName()) + getApp()->getAccounts()->twitch.getCurrent()->getUserName()) { twitchChannel->addSystemMessage("joined channel"); twitchChannel->joined.invoke(); @@ -1233,7 +1232,7 @@ void IrcMessageHandler::handleJoinMessage(Communi::IrcMessage *message) void IrcMessageHandler::handlePartMessage(Communi::IrcMessage *message) { - auto channel = getIApp()->getTwitchAbstract()->getChannelOrEmpty( + auto channel = getApp()->getTwitchAbstract()->getChannelOrEmpty( message->parameter(0).remove(0, 1)); auto *twitchChannel = dynamic_cast(channel.get()); @@ -1243,7 +1242,7 @@ void IrcMessageHandler::handlePartMessage(Communi::IrcMessage *message) } const auto selfAccountName = - getIApp()->getAccounts()->twitch.getCurrent()->getUserName(); + getApp()->getAccounts()->twitch.getCurrent()->getUserName(); if (message->nick() != selfAccountName && getSettings()->showParts.getValue()) { @@ -1296,7 +1295,7 @@ void IrcMessageHandler::setSimilarityFlags(const MessagePtr &message, { bool isMyself = message->loginName == - getIApp()->getAccounts()->twitch.getCurrent()->getUserName(); + getApp()->getAccounts()->twitch.getCurrent()->getUserName(); bool hideMyself = getSettings()->hideSimilarMyself; if (isMyself && !hideMyself) diff --git a/src/providers/twitch/TwitchAccount.cpp b/src/providers/twitch/TwitchAccount.cpp index 0fed7548d..eb07bd6ba 100644 --- a/src/providers/twitch/TwitchAccount.cpp +++ b/src/providers/twitch/TwitchAccount.cpp @@ -109,7 +109,7 @@ void TwitchAccount::loadBlocks() this->ignoresUserIds_.clear(); getHelix()->loadBlocks( - getIApp()->getAccounts()->twitch.getCurrent()->userId_, + getApp()->getAccounts()->twitch.getCurrent()->userId_, [this](const std::vector &blocks) { assertInGuiThread(); @@ -325,7 +325,7 @@ void TwitchAccount::loadUserstateEmotes(std::weak_ptr weakChannel) emoteSet->emotes.push_back(TwitchEmote{id, code}); - auto emote = getIApp() + auto emote = getApp() ->getEmotes() ->getTwitchEmotes() ->getOrCreateEmote(id, code); @@ -493,7 +493,7 @@ void TwitchAccount::loadSeventvUserID() return; } - auto *seventv = getIApp()->getSeventvAPI(); + auto *seventv = getApp()->getSeventvAPI(); if (!seventv) { qCWarning(chatterinoSeventv) diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 4f553f039..cfb046a4d 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -91,7 +91,7 @@ TwitchChannel::TwitchChannel(const QString &name) qCDebug(chatterinoTwitch) << "[TwitchChannel" << name << "] Opened"; this->bSignals_.emplace_back( - getIApp()->getAccounts()->twitch.currentUserChanged.connect([this] { + getApp()->getAccounts()->twitch.currentUserChanged.connect([this] { this->setMod(false); this->refreshPubSub(); })); @@ -143,18 +143,18 @@ TwitchChannel::TwitchChannel(const QString &name) TwitchChannel::~TwitchChannel() { - getIApp()->getTwitch()->dropSeventvChannel(this->seventvUserID_, - this->seventvEmoteSetID_); + getApp()->getTwitch()->dropSeventvChannel(this->seventvUserID_, + this->seventvEmoteSetID_); - if (getIApp()->getTwitch()->getBTTVLiveUpdates()) + if (getApp()->getTwitch()->getBTTVLiveUpdates()) { - getIApp()->getTwitch()->getBTTVLiveUpdates()->partChannel( + getApp()->getTwitch()->getBTTVLiveUpdates()->partChannel( this->roomId()); } - if (getIApp()->getTwitch()->getSeventvEventAPI()) + if (getApp()->getTwitch()->getSeventvEventAPI()) { - getIApp()->getTwitch()->getSeventvEventAPI()->unsubscribeTwitchChannel( + getApp()->getTwitch()->getSeventvEventAPI()->unsubscribeTwitchChannel( this->roomId()); } } @@ -332,7 +332,7 @@ void TwitchChannel::addChannelPointReward(const ChannelPointReward &reward) << "] Channel point reward added:" << reward.id << "," << reward.title << "," << reward.isUserInputRequired; - auto *server = getIApp()->getTwitch(); + auto *server = getApp()->getTwitch(); auto it = std::remove_if( this->waitingRedemptions_.begin(), this->waitingRedemptions_.end(), [&](const QueuedRedemption &msg) { @@ -426,7 +426,7 @@ void TwitchChannel::onLiveStatusChanged(bool isLive, bool isInitialUpdate) qCDebug(chatterinoTwitch).nospace().noquote() << "[TwitchChannel " << this->getName() << "] Online"; - getIApp()->getNotifications()->notifyTwitchChannelLive({ + getApp()->getNotifications()->notifyTwitchChannelLive({ .channelId = this->roomId(), .channelName = this->getName(), .displayName = this->getDisplayName(), @@ -452,7 +452,7 @@ void TwitchChannel::onLiveStatusChanged(bool isLive, bool isInitialUpdate) &builder); this->addMessage(builder.release(), MessageContext::Original); - getIApp()->getNotifications()->notifyTwitchChannelOffline( + getApp()->getNotifications()->notifyTwitchChannelOffline( this->roomId()); } }; @@ -509,7 +509,7 @@ void TwitchChannel::showLoginMessage() { const auto linkColor = MessageColor(MessageColor::Link); const auto accountsLink = Link(Link::OpenAccountsPage, QString()); - const auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + const auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); const auto expirationText = QStringLiteral("You need to log in to send messages. You can link your " "Twitch account"); @@ -532,7 +532,7 @@ void TwitchChannel::showLoginMessage() void TwitchChannel::roomIdChanged() { - if (getIApp()->isTest()) + if (getApp()->isTest()) { return; } @@ -544,7 +544,7 @@ void TwitchChannel::roomIdChanged() this->refreshSevenTVChannelEmotes(false); this->joinBttvChannel(); this->listenSevenTVCosmetics(); - getIApp()->getTwitchLiveController()->add( + getApp()->getTwitchLiveController()->add( std::dynamic_pointer_cast(shared_from_this())); } @@ -710,7 +710,7 @@ void TwitchChannel::setStaff(bool value) bool TwitchChannel::isBroadcaster() const { - auto *app = getIApp(); + auto *app = getApp(); return this->getName() == app->getAccounts()->twitch.getCurrent()->getUserName(); @@ -728,7 +728,7 @@ bool TwitchChannel::canReconnect() const void TwitchChannel::reconnect() { - getIApp()->getTwitchAbstract()->connect(); + getApp()->getTwitchAbstract()->connect(); } QString TwitchChannel::getCurrentStreamID() const @@ -753,7 +753,7 @@ void TwitchChannel::setRoomId(const QString &id) { *this->roomID_.access() = id; // This is intended for tests and benchmarks. See comment in constructor. - if (!getIApp()->isTest()) + if (!getApp()->isTest()) { this->roomIdChanged(); this->loadRecentMessages(); @@ -854,17 +854,17 @@ const QString &TwitchChannel::seventvEmoteSetID() const void TwitchChannel::joinBttvChannel() const { - if (getIApp()->getTwitch()->getBTTVLiveUpdates()) + if (getApp()->getTwitch()->getBTTVLiveUpdates()) { const auto currentAccount = - getIApp()->getAccounts()->twitch.getCurrent(); + getApp()->getAccounts()->twitch.getCurrent(); QString userName; if (currentAccount && !currentAccount->isAnon()) { userName = currentAccount->getUserName(); } - getIApp()->getTwitch()->getBTTVLiveUpdates()->joinChannel( - this->roomId(), userName); + getApp()->getTwitch()->getBTTVLiveUpdates()->joinChannel(this->roomId(), + userName); } } @@ -1012,14 +1012,14 @@ void TwitchChannel::updateSeventvData(const QString &newUserID, this->seventvUserID_ = newUserID; this->seventvEmoteSetID_ = newEmoteSetID; runInGuiThread([this, oldUserID, oldEmoteSetID]() { - if (getIApp()->getTwitch()->getSeventvEventAPI()) + if (getApp()->getTwitch()->getSeventvEventAPI()) { - getIApp()->getTwitch()->getSeventvEventAPI()->subscribeUser( + getApp()->getTwitch()->getSeventvEventAPI()->subscribeUser( this->seventvUserID_, this->seventvEmoteSetID_); if (oldUserID || oldEmoteSetID) { - getIApp()->getTwitch()->dropSeventvChannel( + getApp()->getTwitch()->dropSeventvChannel( oldUserID.value_or(QString()), oldEmoteSetID.value_or(QString())); } @@ -1215,7 +1215,7 @@ void TwitchChannel::loadRecentMessages() tc->addRecentChatter(msg->displayName); } - getIApp()->getTwitch()->getMentionsChannel()->fillInMissingMessages( + getApp()->getTwitch()->getMentionsChannel()->fillInMissingMessages( msgs); }, [weak]() { @@ -1303,7 +1303,7 @@ void TwitchChannel::loadRecentMessagesReconnect() void TwitchChannel::refreshPubSub() { - if (getIApp()->isTest()) + if (getApp()->isTest()) { return; } @@ -1314,17 +1314,17 @@ void TwitchChannel::refreshPubSub() return; } - auto currentAccount = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentAccount = getApp()->getAccounts()->twitch.getCurrent(); - getIApp()->getTwitchPubSub()->setAccount(currentAccount); + getApp()->getTwitchPubSub()->setAccount(currentAccount); - getIApp()->getTwitchPubSub()->listenToChannelModerationActions(roomId); + getApp()->getTwitchPubSub()->listenToChannelModerationActions(roomId); if (this->hasModRights()) { - getIApp()->getTwitchPubSub()->listenToAutomod(roomId); - getIApp()->getTwitchPubSub()->listenToLowTrustUsers(roomId); + getApp()->getTwitchPubSub()->listenToAutomod(roomId); + getApp()->getTwitchPubSub()->listenToLowTrustUsers(roomId); } - getIApp()->getTwitchPubSub()->listenToChannelPointRewards(roomId); + getApp()->getTwitchPubSub()->listenToChannelPointRewards(roomId); } void TwitchChannel::refreshChatters() @@ -1350,7 +1350,7 @@ void TwitchChannel::refreshChatters() // Get chatter list via helix api getHelix()->getChatters( this->roomId(), - getIApp()->getAccounts()->twitch.getCurrent()->getUserId(), + getApp()->getAccounts()->twitch.getCurrent()->getUserId(), MAX_CHATTERS_TO_FETCH, [this, weak = weakOf(this)](auto result) { if (auto shared = weak.lock()) @@ -1710,7 +1710,7 @@ std::vector TwitchChannel::ffzChannelBadges( std::vector badges; - const auto *ffzBadges = getIApp()->getFfzBadges(); + const auto *ffzBadges = getApp()->getFfzBadges(); for (const auto &badgeID : it->second) { @@ -1769,7 +1769,7 @@ void TwitchChannel::updateSevenTVActivity() QStringLiteral("https://7tv.io/v3/users/%1/presences"); const auto currentSeventvUserID = - getIApp()->getAccounts()->twitch.getCurrent()->getSeventvUserID(); + getApp()->getAccounts()->twitch.getCurrent()->getSeventvUserID(); if (currentSeventvUserID.isEmpty()) { return; @@ -1791,7 +1791,7 @@ void TwitchChannel::updateSevenTVActivity() qCDebug(chatterinoSeventv) << "Sending activity in" << this->getName(); - getIApp()->getSeventvAPI()->updatePresence( + getApp()->getSeventvAPI()->updatePresence( this->roomId(), currentSeventvUserID, [chan = weakOf(this)]() { const auto self = @@ -1811,9 +1811,9 @@ void TwitchChannel::updateSevenTVActivity() void TwitchChannel::listenSevenTVCosmetics() const { - if (getIApp()->getTwitch()->getSeventvEventAPI()) + if (getApp()->getTwitch()->getSeventvEventAPI()) { - getIApp()->getTwitch()->getSeventvEventAPI()->subscribeTwitchChannel( + getApp()->getTwitch()->getSeventvEventAPI()->subscribeTwitchChannel( this->roomId()); } } diff --git a/src/providers/twitch/TwitchIrcServer.cpp b/src/providers/twitch/TwitchIrcServer.cpp index 28d4ad4b4..dc12d562b 100644 --- a/src/providers/twitch/TwitchIrcServer.cpp +++ b/src/providers/twitch/TwitchIrcServer.cpp @@ -51,7 +51,7 @@ void sendHelixMessage(const std::shared_ptr &channel, { .broadcasterID = broadcasterID, .senderID = - getIApp()->getAccounts()->twitch.getCurrent()->getUserId(), + getApp()->getAccounts()->twitch.getCurrent()->getUserId(), .message = message, .replyParentMessageID = replyParentId, }, @@ -167,7 +167,7 @@ TwitchIrcServer::TwitchIrcServer() void TwitchIrcServer::initialize() { - getIApp()->getAccounts()->twitch.currentUserChanged.connect([this]() { + getApp()->getAccounts()->twitch.currentUserChanged.connect([this]() { postToThread([this] { this->connect(); }); @@ -182,7 +182,7 @@ void TwitchIrcServer::initializeConnection(IrcConnection *connection, ConnectionType type) { std::shared_ptr account = - getIApp()->getAccounts()->twitch.getCurrent(); + getApp()->getAccounts()->twitch.getCurrent(); qCDebug(chatterinoTwitch) << "logging in as" << account->getUserName(); @@ -690,7 +690,7 @@ void TwitchIrcServer::setLastUserThatWhisperedMe(const QString &user) void TwitchIrcServer::reloadBTTVGlobalEmotes() { - getIApp()->getBttvEmotes()->loadEmotes(); + getApp()->getBttvEmotes()->loadEmotes(); } void TwitchIrcServer::reloadAllBTTVChannelEmotes() @@ -705,7 +705,7 @@ void TwitchIrcServer::reloadAllBTTVChannelEmotes() void TwitchIrcServer::reloadFFZGlobalEmotes() { - getIApp()->getFfzEmotes()->loadEmotes(); + getApp()->getFfzEmotes()->loadEmotes(); } void TwitchIrcServer::reloadAllFFZChannelEmotes() @@ -720,7 +720,7 @@ void TwitchIrcServer::reloadAllFFZChannelEmotes() void TwitchIrcServer::reloadSevenTVGlobalEmotes() { - getIApp()->getSeventvEmotes()->loadGlobalEmotes(); + getApp()->getSeventvEmotes()->loadGlobalEmotes(); } void TwitchIrcServer::reloadAllSevenTVChannelEmotes() diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index a5fa340b7..066ee9bca 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -92,7 +92,7 @@ namespace { const QString &originalMessage, int messageOffset) { - auto *app = getIApp(); + auto *app = getApp(); if (!emote.contains(':')) { return; @@ -167,7 +167,7 @@ namespace { } if (auto globalBadge = - getIApp()->getTwitchBadges()->badge(badge.key_, badge.value_)) + getApp()->getTwitchBadges()->badge(badge.key_, badge.value_)) { return globalBadge; } @@ -673,7 +673,7 @@ void TwitchMessageBuilder::addWords( // 1. Add text before the emote QString preText = word.left(currentTwitchEmote.start - cursor); for (auto &variant : - getIApp()->getEmotes()->getEmojis()->parse(preText)) + getApp()->getEmotes()->getEmojis()->parse(preText)) { boost::apply_visitor( [&](auto &&arg) { @@ -693,7 +693,7 @@ void TwitchMessageBuilder::addWords( } // split words - for (auto &variant : getIApp()->getEmotes()->getEmojis()->parse(word)) + for (auto &variant : getApp()->getEmotes()->getEmojis()->parse(word)) { boost::apply_visitor( [&](auto &&arg) { @@ -937,7 +937,7 @@ void TwitchMessageBuilder::parseThread() void TwitchMessageBuilder::parseUsernameColor() { - const auto *userData = getIApp()->getUserData(); + const auto *userData = getApp()->getUserData(); assert(userData != nullptr); if (const auto &user = userData->getUser(this->userId_)) @@ -991,7 +991,7 @@ void TwitchMessageBuilder::parseUsername() } // Update current user color if this is our message - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); if (this->ircMessage->nick() == currentUser->getUserName()) { currentUser->setColor(this->usernameColor_); @@ -1000,7 +1000,7 @@ void TwitchMessageBuilder::parseUsername() void TwitchMessageBuilder::appendUsername() { - auto *app = getIApp(); + auto *app = getApp(); QString username = this->userName; this->message().loginName = username; @@ -1256,7 +1256,7 @@ void TwitchMessageBuilder::processIgnorePhrases( Outcome TwitchMessageBuilder::tryAppendEmote(const EmoteName &name) { - auto *app = getIApp(); + auto *app = getApp(); const auto *globalBttvEmotes = app->getBttvEmotes(); const auto *globalFfzEmotes = app->getFfzEmotes(); @@ -1410,8 +1410,7 @@ void TwitchMessageBuilder::appendTwitchBadges() void TwitchMessageBuilder::appendChatterinoBadges() { - if (auto badge = - getIApp()->getChatterinoBadges()->getBadge({this->userId_})) + if (auto badge = getApp()->getChatterinoBadges()->getBadge({this->userId_})) { this->emplace(*badge, MessageElementFlag::BadgeChatterino); @@ -1421,7 +1420,7 @@ void TwitchMessageBuilder::appendChatterinoBadges() void TwitchMessageBuilder::appendFfzBadges() { for (const auto &badge : - getIApp()->getFfzBadges()->getUserBadges({this->userId_})) + getApp()->getFfzBadges()->getUserBadges({this->userId_})) { this->emplace( badge.emote, MessageElementFlag::BadgeFfz, badge.color); @@ -1442,7 +1441,7 @@ void TwitchMessageBuilder::appendFfzBadges() void TwitchMessageBuilder::appendSeventvBadges() { - if (auto badge = getIApp()->getSeventvBadges()->getBadge({this->userId_})) + if (auto badge = getApp()->getSeventvBadges()->getBadge({this->userId_})) { this->emplace(*badge, MessageElementFlag::BadgeSevenTV); } @@ -1585,7 +1584,7 @@ void TwitchMessageBuilder::appendChannelPointRewardMessage( if (reward.id == "CELEBRATION") { const auto emotePtr = - getIApp()->getEmotes()->getTwitchEmotes()->getOrCreateEmote( + getApp()->getEmotes()->getTwitchEmotes()->getOrCreateEmote( EmoteId{reward.emoteId}, EmoteName{reward.emoteName}); builder->emplace(emotePtr, MessageElementFlag::ChannelPointReward, @@ -2060,7 +2059,7 @@ std::pair TwitchMessageBuilder::makeAutomodMessage( // Normally highlights would be checked & triggered during the builder parse steps // and when the message is added to the channel // We do this a bit weird since the message comes in from PubSub and not the normal message route - auto [highlighted, highlightResult] = getIApp()->getHighlights()->check( + auto [highlighted, highlightResult] = getApp()->getHighlights()->check( {}, {}, action.target.login, action.message, message2->flags); if (highlighted) { @@ -2256,7 +2255,7 @@ std::pair TwitchMessageBuilder::makeLowTrustUserMessage( else { const auto emotePtr = - getIApp()->getEmotes()->getTwitchEmotes()->getOrCreateEmote( + getApp()->getEmotes()->getTwitchEmotes()->getOrCreateEmote( EmoteId{fragment.emoteID}, EmoteName{fragment.text}); builder2.emplace( emotePtr, MessageElementFlag::TwitchEmote, MessageColor::Text); diff --git a/src/singletons/Badges.cpp b/src/singletons/Badges.cpp deleted file mode 100644 index da38def4f..000000000 --- a/src/singletons/Badges.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "Badges.hpp" - -namespace chatterino { - -Badges::Badges() -{ -} - -} // namespace chatterino diff --git a/src/singletons/Badges.hpp b/src/singletons/Badges.hpp deleted file mode 100644 index e7288ac5c..000000000 --- a/src/singletons/Badges.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "common/Singleton.hpp" - -namespace chatterino { - -class Badges : public Singleton -{ -public: - Badges(); -}; - -} // namespace chatterino diff --git a/src/singletons/CrashHandler.cpp b/src/singletons/CrashHandler.cpp index 84f19793c..ca9ea915c 100644 --- a/src/singletons/CrashHandler.cpp +++ b/src/singletons/CrashHandler.cpp @@ -130,10 +130,6 @@ using namespace std::string_literals; CrashHandler::CrashHandler(const Paths &paths_) : paths(paths_) -{ -} - -void CrashHandler::initialize(Settings & /*settings*/, const Paths &paths_) { auto optSettings = readRecoverySettings(paths); if (optSettings) diff --git a/src/singletons/CrashHandler.hpp b/src/singletons/CrashHandler.hpp index 9fbdf358c..3f2a45262 100644 --- a/src/singletons/CrashHandler.hpp +++ b/src/singletons/CrashHandler.hpp @@ -1,7 +1,5 @@ #pragma once -#include "common/Singleton.hpp" - #include #ifdef CHATTERINO_WITH_CRASHPAD @@ -15,7 +13,7 @@ namespace chatterino { class Args; class Paths; -class CrashHandler : public Singleton +class CrashHandler { const Paths &paths; @@ -30,8 +28,6 @@ public: /// Sets and saves whether Chatterino should restart on a crash void saveShouldRecover(bool value); - void initialize(Settings &settings, const Paths &paths) override; - private: bool shouldRecover_ = false; }; diff --git a/src/singletons/Emotes.cpp b/src/singletons/Emotes.cpp index 5051dab69..a5b169902 100644 --- a/src/singletons/Emotes.cpp +++ b/src/singletons/Emotes.cpp @@ -3,19 +3,10 @@ namespace chatterino { Emotes::Emotes() -{ -} - -void Emotes::initialize(Settings &settings, const Paths &paths) { this->emojis.load(); this->gifTimer.initialize(); } -bool Emotes::isIgnoredEmote(const QString &) -{ - return false; -} - } // namespace chatterino diff --git a/src/singletons/Emotes.hpp b/src/singletons/Emotes.hpp index 3ffeb6d7a..9b2520391 100644 --- a/src/singletons/Emotes.hpp +++ b/src/singletons/Emotes.hpp @@ -1,15 +1,11 @@ #pragma once -#include "common/Singleton.hpp" #include "providers/emoji/Emojis.hpp" #include "providers/twitch/TwitchEmotes.hpp" #include "singletons/helper/GifTimer.hpp" namespace chatterino { -class Settings; -class Paths; - class IEmotes { public: @@ -20,15 +16,11 @@ public: virtual GIFTimer &getGIFTimer() = 0; }; -class Emotes final : public IEmotes, public Singleton +class Emotes final : public IEmotes { public: Emotes(); - void initialize(Settings &settings, const Paths &paths) override; - - bool isIgnoredEmote(const QString &emote); - ITwitchEmotes *getTwitchEmotes() final { return &this->twitch; diff --git a/src/singletons/ImageUploader.cpp b/src/singletons/ImageUploader.cpp index b6a191e85..b5fe9c43a 100644 --- a/src/singletons/ImageUploader.cpp +++ b/src/singletons/ImageUploader.cpp @@ -54,7 +54,7 @@ void ImageUploader::logToFile(const QString &originalFilePath, { const QString logFileName = combinePath((getSettings()->logPath.getValue().isEmpty() - ? getIApp()->getPaths().messageLogDirectory + ? getApp()->getPaths().messageLogDirectory : getSettings()->logPath), "ImageUploader.json"); @@ -123,10 +123,6 @@ QString getLinkFromResponse(NetworkResult response, QString pattern) return pattern; } -void ImageUploader::save() -{ -} - void ImageUploader::sendImageUploadRequest(RawImageData imageData, ChannelPtr channel, QPointer textEdit) diff --git a/src/singletons/ImageUploader.hpp b/src/singletons/ImageUploader.hpp index 41f4c8b60..80cd4ef1c 100644 --- a/src/singletons/ImageUploader.hpp +++ b/src/singletons/ImageUploader.hpp @@ -1,7 +1,5 @@ #pragma once -#include "common/Singleton.hpp" - #include #include #include @@ -22,7 +20,7 @@ struct RawImageData { QString filePath; }; -class ImageUploader final : public Singleton +class ImageUploader final { public: /** @@ -33,7 +31,6 @@ public: std::pair, QString> getImages( const QMimeData *source) const; - void save() override; void upload(std::queue images, ChannelPtr channel, QPointer outputTextEdit); diff --git a/src/singletons/NativeMessaging.cpp b/src/singletons/NativeMessaging.cpp index 524913ef8..58dfd1b2b 100644 --- a/src/singletons/NativeMessaging.cpp +++ b/src/singletons/NativeMessaging.cpp @@ -238,11 +238,10 @@ void NativeMessagingServer::ReceiverThread::handleSelect( postToThread([=] { if (!name.isEmpty()) { - auto channel = - getIApp()->getTwitchAbstract()->getOrAddChannel(name); - if (getIApp()->getTwitch()->getWatchingChannel().get() != channel) + auto channel = getApp()->getTwitchAbstract()->getOrAddChannel(name); + if (getApp()->getTwitch()->getWatchingChannel().get() != channel) { - getIApp()->getTwitch()->setWatchingChannel(channel); + getApp()->getTwitch()->setWatchingChannel(channel); } } @@ -253,7 +252,7 @@ void NativeMessagingServer::ReceiverThread::handleSelect( if (!name.isEmpty()) { window->setChannel( - getIApp()->getTwitchAbstract()->getOrAddChannel(name)); + getApp()->getTwitchAbstract()->getOrAddChannel(name)); } #endif } @@ -305,7 +304,7 @@ void NativeMessagingServer::syncChannels(const QJsonArray &twitchChannels) } // the deduping is done on the extension side updated.emplace_back( - getIApp()->getTwitchAbstract()->getOrAddChannel(name)); + getApp()->getTwitchAbstract()->getOrAddChannel(name)); } // This will destroy channels that aren't used anymore. diff --git a/src/singletons/StreamerMode.cpp b/src/singletons/StreamerMode.cpp index 5b8b4402b..659bfd9ea 100644 --- a/src/singletons/StreamerMode.cpp +++ b/src/singletons/StreamerMode.cpp @@ -74,7 +74,7 @@ bool isBroadcasterSoftwareActive() shouldShowTimeoutWarning = false; postToThread([] { - getIApp()->getTwitchAbstract()->addGlobalSystemMessage( + getApp()->getTwitchAbstract()->addGlobalSystemMessage( "Streamer Mode is set to Automatic, but pgrep timed " "out. This can happen if your system lagged at the " "wrong moment. If Streamer Mode continues to not work, " @@ -94,7 +94,7 @@ bool isBroadcasterSoftwareActive() shouldShowWarning = false; postToThread([] { - getIApp()->getTwitchAbstract()->addGlobalSystemMessage( + getApp()->getTwitchAbstract()->addGlobalSystemMessage( "Streamer Mode is set to Automatic, but pgrep is " "missing. " "Install it to fix the issue or set Streamer Mode to " diff --git a/src/singletons/Theme.cpp b/src/singletons/Theme.cpp index 2441e3652..bbd29abf9 100644 --- a/src/singletons/Theme.cpp +++ b/src/singletons/Theme.cpp @@ -282,7 +282,7 @@ bool Theme::isSystemTheme() const return this->themeName == u"System"_s; } -void Theme::initialize(Settings &settings, const Paths &paths) +Theme::Theme(const Paths &paths) { this->themeName.connect( [this](auto themeName) { @@ -307,7 +307,7 @@ void Theme::initialize(Settings &settings, const Paths &paths) if (this->isSystemTheme()) { this->update(); - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); } }); #endif @@ -597,7 +597,7 @@ void Theme::normalizeColor(QColor &color) const Theme *getTheme() { - return getIApp()->getThemes(); + return getApp()->getThemes(); } } // namespace chatterino diff --git a/src/singletons/Theme.hpp b/src/singletons/Theme.hpp index d64172e45..cb811e2db 100644 --- a/src/singletons/Theme.hpp +++ b/src/singletons/Theme.hpp @@ -1,7 +1,7 @@ #pragma once #include "common/ChatterinoSetting.hpp" -#include "common/Singleton.hpp" +#include "singletons/Paths.hpp" #include "util/RapidJsonSerializeQString.hpp" #include @@ -33,7 +33,7 @@ struct ThemeDescriptor { bool custom{}; }; -class Theme final : public Singleton +class Theme final { public: static const std::vector builtInThemes; @@ -43,7 +43,7 @@ public: static const int AUTO_RELOAD_INTERVAL_MS = 500; - void initialize(Settings &settings, const Paths &paths) final; + Theme(const Paths &paths); bool isLightTheme() const; bool isSystemTheme() const; diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index 3ca5b6e0c..26a82543a 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -35,7 +35,7 @@ using namespace literals; QString avatarFilePath(const QString &channelName) { // TODO: cleanup channel (to be used as a file) and use combinePath - return getIApp()->getPaths().twitchProfileAvatars % '/' % channelName % + return getApp()->getPaths().twitchProfileAvatars % '/' % channelName % u".png"; } @@ -74,7 +74,7 @@ bool Toasts::isEnabled() { #ifdef Q_OS_WIN return WinToast::isCompatible() && getSettings()->notificationToast && - !(getIApp()->getStreamerMode()->isEnabled() && + !(getApp()->getStreamerMode()->isEnabled() && getSettings()->streamerModeSuppressLiveNotifications); #else return false; diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp index 83e64a081..e4c2ad234 100644 --- a/src/singletons/Toasts.hpp +++ b/src/singletons/Toasts.hpp @@ -1,7 +1,5 @@ #pragma once -#include "common/Singleton.hpp" - #include #include @@ -16,7 +14,7 @@ enum class ToastReaction { DontOpen = 3 }; -class Toasts final : public Singleton +class Toasts final { public: void sendChannelNotification(const QString &channelName, diff --git a/src/singletons/WindowManager.cpp b/src/singletons/WindowManager.cpp index 66a0f606e..cb5630c25 100644 --- a/src/singletons/WindowManager.cpp +++ b/src/singletons/WindowManager.cpp @@ -118,7 +118,7 @@ WindowManager::WindowManager(const Paths &paths) this->saveTimer->setSingleShot(true); QObject::connect(this->saveTimer, &QTimer::timeout, [] { - getIApp()->getWindows()->save(); + getApp()->getWindows()->save(); }); } @@ -341,21 +341,18 @@ void WindowManager::setEmotePopupBounds(QRect bounds) } } -void WindowManager::initialize(Settings &settings, const Paths &paths) +void WindowManager::initialize(Settings &settings) { - (void)paths; assertInGuiThread(); // We can safely ignore this signal connection since both Themes and WindowManager // share the Application state lifetime // NOTE: APPLICATION_LIFETIME std::ignore = - getIApp()->getThemes()->repaintVisibleChatWidgets_.connect([this] { + getApp()->getThemes()->repaintVisibleChatWidgets_.connect([this] { this->repaintVisibleChatWidgets(); }); - assert(!this->initialized_); - { WindowLayout windowLayout; @@ -368,7 +365,7 @@ void WindowManager::initialize(Settings &settings, const Paths &paths) windowLayout = this->loadWindowLayoutFromFile(); } - auto desired = getIApp()->getArgs().activateChannel; + auto desired = getApp()->getArgs().activateChannel; if (desired) { windowLayout.activateOrAddChannel(desired->provider, desired->name); @@ -428,8 +425,6 @@ void WindowManager::initialize(Settings &settings, const Paths &paths) settings.boldUsernames.connect([this](auto, auto) { this->forceLayoutChannelViews(); }); - - this->initialized_ = true; } void WindowManager::save() @@ -687,28 +682,28 @@ IndirectChannel WindowManager::decodeChannel(const SplitDescriptor &descriptor) if (descriptor.type_ == "twitch") { - return getIApp()->getTwitchAbstract()->getOrAddChannel( + return getApp()->getTwitchAbstract()->getOrAddChannel( descriptor.channelName_); } else if (descriptor.type_ == "mentions") { - return getIApp()->getTwitch()->getMentionsChannel(); + return getApp()->getTwitch()->getMentionsChannel(); } else if (descriptor.type_ == "watching") { - return getIApp()->getTwitch()->getWatchingChannel(); + return getApp()->getTwitch()->getWatchingChannel(); } else if (descriptor.type_ == "whispers") { - return getIApp()->getTwitch()->getWhispersChannel(); + return getApp()->getTwitch()->getWhispersChannel(); } else if (descriptor.type_ == "live") { - return getIApp()->getTwitch()->getLiveChannel(); + return getApp()->getTwitch()->getLiveChannel(); } else if (descriptor.type_ == "automod") { - return getIApp()->getTwitch()->getAutomodChannel(); + return getApp()->getTwitch()->getAutomodChannel(); } else if (descriptor.type_ == "irc") { @@ -717,7 +712,7 @@ IndirectChannel WindowManager::decodeChannel(const SplitDescriptor &descriptor) } else if (descriptor.type_ == "misc") { - return getIApp()->getTwitchAbstract()->getChannelOrEmpty( + return getApp()->getTwitchAbstract()->getChannelOrEmpty( descriptor.channelName_); } diff --git a/src/singletons/WindowManager.hpp b/src/singletons/WindowManager.hpp index 21040fab0..49c60d268 100644 --- a/src/singletons/WindowManager.hpp +++ b/src/singletons/WindowManager.hpp @@ -1,7 +1,6 @@ #pragma once #include "common/FlagsEnum.hpp" -#include "common/Singleton.hpp" #include "widgets/splits/SplitContainer.hpp" #include @@ -32,13 +31,13 @@ enum class WindowType; enum class SettingsDialogPreference; class FramelessEmbedWindow; -class WindowManager final : public Singleton +class WindowManager final { public: static const QString WINDOW_LAYOUT_FILENAME; explicit WindowManager(const Paths &paths); - ~WindowManager() override; + ~WindowManager(); WindowManager(const WindowManager &) = delete; WindowManager(WindowManager &&) = delete; @@ -102,8 +101,9 @@ public: QRect emotePopupBounds() const; void setEmotePopupBounds(QRect bounds); - void initialize(Settings &settings, const Paths &paths) override; - void save() override; + // Set up some final signals & actually show the windows + void initialize(Settings &settings); + void save(); void closeAll(); int getGeneration() const; @@ -151,7 +151,6 @@ private: // Contains the full path to the window layout file, e.g. /home/pajlada/.local/share/Chatterino/Settings/window-layout.json const QString windowLayoutFilePath; - bool initialized_ = false; bool shuttingDown_ = false; QRect emotePopupBounds_; diff --git a/src/singletons/helper/GifTimer.cpp b/src/singletons/helper/GifTimer.cpp index 9eaf1162f..564ec961c 100644 --- a/src/singletons/helper/GifTimer.cpp +++ b/src/singletons/helper/GifTimer.cpp @@ -31,7 +31,7 @@ void GIFTimer::initialize() this->position_ += GIF_FRAME_LENGTH; this->signal.invoke(); - getIApp()->getWindows()->repaintGifEmotes(); + getApp()->getWindows()->repaintGifEmotes(); }); } diff --git a/src/singletons/helper/LoggingChannel.cpp b/src/singletons/helper/LoggingChannel.cpp index ad8cfb9a2..dcce92f23 100644 --- a/src/singletons/helper/LoggingChannel.cpp +++ b/src/singletons/helper/LoggingChannel.cpp @@ -88,7 +88,7 @@ LoggingChannel::LoggingChannel(QString _channelName, QString _platform) getSettings()->logPath.connect([this](const QString &logPath, auto) { this->baseDirectory = logPath.isEmpty() - ? getIApp()->getPaths().messageLogDirectory + ? getApp()->getPaths().messageLogDirectory : logPath; this->openLogFile(); }); diff --git a/src/util/InitUpdateButton.cpp b/src/util/InitUpdateButton.cpp index 349fb78bb..8636a85f1 100644 --- a/src/util/InitUpdateButton.cpp +++ b/src/util/InitUpdateButton.cpp @@ -41,7 +41,7 @@ void initUpdateButton(Button &button, } break; case UpdateDialog::Install: { - getIApp()->getUpdates().installUpdates(); + getApp()->getUpdates().installUpdates(); } break; } @@ -53,17 +53,17 @@ void initUpdateButton(Button &button, // update image when state changes auto updateChange = [&button](auto) { - button.setVisible(getIApp()->getUpdates().shouldShowUpdateButton()); + button.setVisible(getApp()->getUpdates().shouldShowUpdateButton()); - const auto *imageUrl = getIApp()->getUpdates().isError() + const auto *imageUrl = getApp()->getUpdates().isError() ? ":/buttons/updateError.png" : ":/buttons/update.png"; button.setPixmap(QPixmap(imageUrl)); }; - updateChange(getIApp()->getUpdates().getStatus()); + updateChange(getApp()->getUpdates().getStatus()); - signalHolder.managedConnect(getIApp()->getUpdates().statusUpdated, + signalHolder.managedConnect(getApp()->getUpdates().statusUpdated, [updateChange](auto status) { updateChange(status); }); diff --git a/src/util/StreamLink.cpp b/src/util/StreamLink.cpp index b4e4370d2..f9869ce4d 100644 --- a/src/util/StreamLink.cpp +++ b/src/util/StreamLink.cpp @@ -183,7 +183,7 @@ void openStreamlinkForChannel(const QString &channel) { static const QString INFO_TEMPLATE("Opening %1 in Streamlink ..."); - auto *currentPage = dynamic_cast(getIApp() + auto *currentPage = dynamic_cast(getApp() ->getWindows() ->getMainWindow() .getNotebook() diff --git a/src/widgets/BaseWidget.cpp b/src/widgets/BaseWidget.cpp index 564ba5963..f2a6160d6 100644 --- a/src/widgets/BaseWidget.cpp +++ b/src/widgets/BaseWidget.cpp @@ -18,7 +18,7 @@ namespace chatterino { BaseWidget::BaseWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) - , theme(getIApp()->getThemes()) + , theme(getApp()->getThemes()) { this->signalHolder_.managedConnect(this->theme->updated, [this]() { this->themeChangedEvent(); diff --git a/src/widgets/BaseWindow.cpp b/src/widgets/BaseWindow.cpp index 6d636b9d6..12e87ff73 100644 --- a/src/widgets/BaseWindow.cpp +++ b/src/widgets/BaseWindow.cpp @@ -712,7 +712,7 @@ void BaseWindow::resizeEvent(QResizeEvent *) // Queue up save because: Window resized if (!flags_.has(DisableLayoutSave)) { - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); } #ifdef USEWINSDK @@ -727,7 +727,7 @@ void BaseWindow::moveEvent(QMoveEvent *event) #ifdef CHATTERINO if (!flags_.has(DisableLayoutSave)) { - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); } #endif @@ -909,7 +909,7 @@ void BaseWindow::scaleChangedEvent(float scale) #endif this->setFont( - getIApp()->getFonts()->getFont(FontStyle::UiTabs, this->scale())); + getApp()->getFonts()->getFont(FontStyle::UiTabs, this->scale())); } void BaseWindow::paintEvent(QPaintEvent *) diff --git a/src/widgets/FramelessEmbedWindow.cpp b/src/widgets/FramelessEmbedWindow.cpp index 9735edcee..109a8bd55 100644 --- a/src/widgets/FramelessEmbedWindow.cpp +++ b/src/widgets/FramelessEmbedWindow.cpp @@ -54,7 +54,7 @@ bool FramelessEmbedWindow::nativeEvent(const QByteArray &eventType, auto channelName = root.value("channel-name").toString(); this->split_->setChannel( - getIApp()->getTwitchAbstract()->getOrAddChannel( + getApp()->getTwitchAbstract()->getOrAddChannel( channelName)); } } diff --git a/src/widgets/Label.cpp b/src/widgets/Label.cpp index 529fb7575..6f56acb27 100644 --- a/src/widgets/Label.cpp +++ b/src/widgets/Label.cpp @@ -16,7 +16,7 @@ Label::Label(BaseWidget *parent, QString text, FontStyle style) , text_(std::move(text)) , fontStyle_(style) { - this->connections_.managedConnect(getIApp()->getFonts()->fontChanged, + this->connections_.managedConnect(getApp()->getFonts()->fontChanged, [this] { this->updateSize(); }); @@ -89,10 +89,10 @@ void Label::paintEvent(QPaintEvent *) { QPainter painter(this); - QFontMetrics metrics = getIApp()->getFonts()->getFontMetrics( + QFontMetrics metrics = getApp()->getFonts()->getFontMetrics( this->getFontStyle(), this->scale()); painter.setFont( - getIApp()->getFonts()->getFont(this->getFontStyle(), this->scale())); + getApp()->getFonts()->getFont(this->getFontStyle(), this->scale())); int offset = this->getOffset(); @@ -119,7 +119,7 @@ void Label::paintEvent(QPaintEvent *) void Label::updateSize() { QFontMetrics metrics = - getIApp()->getFonts()->getFontMetrics(this->fontStyle_, this->scale()); + getApp()->getFonts()->getFontMetrics(this->fontStyle_, this->scale()); int width = metrics.horizontalAdvance(this->text_) + (2 * this->getOffset()); diff --git a/src/widgets/Notebook.cpp b/src/widgets/Notebook.cpp index a3871eee9..0f4fa3597 100644 --- a/src/widgets/Notebook.cpp +++ b/src/widgets/Notebook.cpp @@ -97,7 +97,7 @@ NotebookTab *Notebook::addPageAt(QWidget *page, int position, QString title, bool select) { // Queue up save because: Tab added - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); auto *tab = new NotebookTab(this); tab->page = page; @@ -134,7 +134,7 @@ NotebookTab *Notebook::addPageAt(QWidget *page, int position, QString title, void Notebook::removePage(QWidget *page) { // Queue up save because: Tab removed - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); int removingIndex = this->indexOf(page); assert(removingIndex != -1); @@ -567,7 +567,7 @@ void Notebook::rearrangePage(QWidget *page, int index) } // Queue up save because: Tab rearranged - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); this->items_.move(this->indexOf(page), index); @@ -608,16 +608,16 @@ void Notebook::setShowTabs(bool value) void Notebook::showTabVisibilityInfoPopup() { - auto unhideSeq = getIApp()->getHotkeys()->getDisplaySequence( + auto unhideSeq = getApp()->getHotkeys()->getDisplaySequence( HotkeyCategory::Window, "setTabVisibility", {std::vector()}); if (unhideSeq.isEmpty()) { - unhideSeq = getIApp()->getHotkeys()->getDisplaySequence( + unhideSeq = getApp()->getHotkeys()->getDisplaySequence( HotkeyCategory::Window, "setTabVisibility", {{"toggle"}}); } if (unhideSeq.isEmpty()) { - unhideSeq = getIApp()->getHotkeys()->getDisplaySequence( + unhideSeq = getApp()->getHotkeys()->getDisplaySequence( HotkeyCategory::Window, "setTabVisibility", {{"on"}}); } QString hotkeyInfo = "(currently unbound)"; @@ -670,7 +670,7 @@ void Notebook::updateTabVisibility() void Notebook::updateTabVisibilityMenuAction() { - const auto *hotkeys = getIApp()->getHotkeys(); + const auto *hotkeys = getApp()->getHotkeys(); auto toggleSeq = hotkeys->getDisplaySequence( HotkeyCategory::Window, "setTabVisibility", {std::vector()}); @@ -1400,7 +1400,7 @@ SplitNotebook::SplitNotebook(Window *parent) this->signalHolder_, true); this->signalHolder_.managedConnect( - getIApp()->getWindows()->selectSplit, [this](Split *split) { + getApp()->getWindows()->selectSplit, [this](Split *split) { for (auto &&item : this->items()) { if (auto *sc = dynamic_cast(item.page)) @@ -1418,13 +1418,13 @@ SplitNotebook::SplitNotebook(Window *parent) }); this->signalHolder_.managedConnect( - getIApp()->getWindows()->selectSplitContainer, + getApp()->getWindows()->selectSplitContainer, [this](SplitContainer *sc) { this->select(sc); }); this->signalHolder_.managedConnect( - getIApp()->getWindows()->scrollToMessageSignal, + getApp()->getWindows()->scrollToMessageSignal, [this](const MessagePtr &message) { for (auto &&item : this->items()) { @@ -1515,7 +1515,7 @@ void SplitNotebook::addCustomButtons() settingsBtn->setIcon(NotebookButton::Settings); QObject::connect(settingsBtn, &NotebookButton::leftClicked, [this] { - getIApp()->getWindows()->showSettingsDialog(this); + getApp()->getWindows()->showSettingsDialog(this); }); // account @@ -1529,7 +1529,7 @@ void SplitNotebook::addCustomButtons() userBtn->setIcon(NotebookButton::User); QObject::connect(userBtn, &NotebookButton::leftClicked, [this, userBtn] { - getIApp()->getWindows()->showAccountSelectPopup( + getApp()->getWindows()->showAccountSelectPopup( this->mapToGlobal(userBtn->rect().bottomRight())); }); @@ -1542,18 +1542,18 @@ void SplitNotebook::addCustomButtons() this->streamerModeIcon_ = this->addCustomButton(); QObject::connect(this->streamerModeIcon_, &NotebookButton::leftClicked, [this] { - getIApp()->getWindows()->showSettingsDialog( + getApp()->getWindows()->showSettingsDialog( this, SettingsDialogPreference::StreamerMode); }); - QObject::connect(getIApp()->getStreamerMode(), &IStreamerMode::changed, - this, &SplitNotebook::updateStreamerModeIcon); + QObject::connect(getApp()->getStreamerMode(), &IStreamerMode::changed, this, + &SplitNotebook::updateStreamerModeIcon); this->updateStreamerModeIcon(); } void SplitNotebook::updateToggleOfflineTabsHotkey( NotebookTabVisibility newTabVisibility) { - auto *hotkeys = getIApp()->getHotkeys(); + auto *hotkeys = getApp()->getHotkeys(); auto getKeySequence = [&](auto argument) { return hotkeys->getDisplaySequence(HotkeyCategory::Window, "setTabVisibility", {{argument}}); @@ -1606,7 +1606,7 @@ void SplitNotebook::updateStreamerModeIcon() getResources().buttons.streamerModeEnabledDark); } this->streamerModeIcon_->setVisible( - getIApp()->getStreamerMode()->isEnabled()); + getApp()->getStreamerMode()->isEnabled()); } void SplitNotebook::themeChangedEvent() diff --git a/src/widgets/TooltipWidget.cpp b/src/widgets/TooltipWidget.cpp index 00f5a2bec..14328e91f 100644 --- a/src/widgets/TooltipWidget.cpp +++ b/src/widgets/TooltipWidget.cpp @@ -47,13 +47,13 @@ TooltipWidget::TooltipWidget(BaseWidget *parent) this->setLayout(this->vLayout_); this->currentStyle_ = TooltipStyle::Vertical; - this->connections_.managedConnect(getIApp()->getFonts()->fontChanged, + this->connections_.managedConnect(getApp()->getFonts()->fontChanged, [this] { this->updateFont(); }); this->updateFont(); - auto *windows = getIApp()->getWindows(); + auto *windows = getApp()->getWindows(); this->connections_.managedConnect(windows->gifRepaintRequested, [this] { if (!this->isVisible()) { @@ -300,8 +300,8 @@ void TooltipWidget::scaleChangedEvent(float) void TooltipWidget::updateFont() { - this->setFont(getIApp()->getFonts()->getFont(FontStyle::ChatMediumSmall, - this->scale())); + this->setFont(getApp()->getFonts()->getFont(FontStyle::ChatMediumSmall, + this->scale())); } void TooltipWidget::setWordWrap(bool wrap) diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index f7df6bcb0..ee836d185 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -64,7 +64,7 @@ Window::Window(WindowType type, QWidget *parent) #endif this->bSignals_.emplace_back( - getIApp()->getAccounts()->twitch.currentUserChanged.connect([this] { + getApp()->getAccounts()->twitch.currentUserChanged.connect([this] { this->onAccountSelected(); })); this->onAccountSelected(); @@ -78,7 +78,7 @@ Window::Window(WindowType type, QWidget *parent) this->resize(int(300 * this->scale()), int(500 * this->scale())); } - this->signalHolder_.managedConnect(getIApp()->getHotkeys()->onItemsUpdated, + this->signalHolder_.managedConnect(getApp()->getHotkeys()->onItemsUpdated, [this]() { this->clearShortcuts(); this->addShortcuts(); @@ -108,7 +108,7 @@ bool Window::event(QEvent *event) switch (event->type()) { case QEvent::WindowActivate: { - getIApp()->getWindows()->selectedWindow_ = this; + getApp()->getWindows()->selectedWindow_ = this; break; } @@ -145,14 +145,14 @@ void Window::closeEvent(QCloseEvent *) { if (this->type_ == WindowType::Main) { - getIApp()->getWindows()->save(); - getIApp()->getWindows()->closeAll(); + getApp()->getWindows()->save(); + getApp()->getWindows()->closeAll(); } // Ensure selectedWindow_ is never an invalid pointer. // WindowManager will return the main window if no window is pointed to by // `selectedWindow_`. - getIApp()->getWindows()->selectedWindow_ = nullptr; + getApp()->getWindows()->selectedWindow_ = nullptr; this->closed.invoke(); @@ -189,7 +189,7 @@ void Window::addCustomTitlebarButtons() // settings this->addTitleBarButton(TitleBarButtonStyle::Settings, [this] { - getIApp()->getWindows()->showSettingsDialog(this); + getApp()->getWindows()->showSettingsDialog(this); }); // updates @@ -199,7 +199,7 @@ void Window::addCustomTitlebarButtons() // account this->userLabel_ = this->addTitleBarLabel([this] { - getIApp()->getWindows()->showAccountSelectPopup( + getApp()->getWindows()->showAccountSelectPopup( this->userLabel_->mapToGlobal( this->userLabel_->rect().bottomLeft())); }); @@ -208,11 +208,11 @@ void Window::addCustomTitlebarButtons() // streamer mode this->streamerModeTitlebarIcon_ = this->addTitleBarButton(TitleBarButtonStyle::StreamerMode, [this] { - getIApp()->getWindows()->showSettingsDialog( + getApp()->getWindows()->showSettingsDialog( this, SettingsDialogPreference::StreamerMode); }); - QObject::connect(getIApp()->getStreamerMode(), &IStreamerMode::changed, - this, &Window::updateStreamerModeIcon); + QObject::connect(getApp()->getStreamerMode(), &IStreamerMode::changed, this, + &Window::updateStreamerModeIcon); // Update initial state this->updateStreamerModeIcon(); @@ -240,7 +240,7 @@ void Window::updateStreamerModeIcon() getResources().buttons.streamerModeEnabledDark); } this->streamerModeTitlebarIcon_->setVisible( - getIApp()->getStreamerMode()->isEnabled()); + getApp()->getStreamerMode()->isEnabled()); #else // clang-format off assert(false && "Streamer mode TitleBar icon should not exist on non-Windows OSes"); @@ -261,7 +261,7 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions) const auto &messages = getSampleMiscMessages(); static int index = 0; const auto &msg = messages[index++ % messages.size()]; - getIApp()->getTwitchAbstract()->addFakeMessage(msg); + getApp()->getTwitchAbstract()->addFakeMessage(msg); return ""; }); @@ -269,7 +269,7 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions) const auto &messages = getSampleCheerMessages(); static int index = 0; const auto &msg = messages[index++ % messages.size()]; - getIApp()->getTwitchAbstract()->addFakeMessage(msg); + getApp()->getTwitchAbstract()->addFakeMessage(msg); return ""; }); @@ -277,13 +277,12 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions) const auto &messages = getSampleLinkMessages(); static int index = 0; const auto &msg = messages[index++ % messages.size()]; - getIApp()->getTwitchAbstract()->addFakeMessage(msg); + getApp()->getTwitchAbstract()->addFakeMessage(msg); return ""; }); actions.emplace("addRewardMessage", [=](std::vector) -> QString { rapidjson::Document doc; - auto app = getApp(); static bool alt = true; if (alt) { @@ -293,9 +292,9 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions) oMessage->toInner() ->toInner(); - getIApp()->getTwitchAbstract()->addFakeMessage( + getApp()->getTwitchAbstract()->addFakeMessage( getSampleChannelRewardIRCMessage()); - getIApp()->getTwitchPubSub()->pointReward.redeemed.invoke( + getApp()->getTwitchPubSub()->pointReward.redeemed.invoke( oInnerMessage->data.value("redemption").toObject()); alt = !alt; } @@ -306,7 +305,7 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions) auto oInnerMessage = oMessage->toInner() ->toInner(); - getIApp()->getTwitchPubSub()->pointReward.redeemed.invoke( + getApp()->getTwitchPubSub()->pointReward.redeemed.invoke( oInnerMessage->data.value("redemption").toObject()); alt = !alt; } @@ -317,7 +316,7 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions) const auto &messages = getSampleEmoteTestMessages(); static int index = 0; const auto &msg = messages[index++ % messages.size()]; - getIApp()->getTwitchAbstract()->addFakeMessage(msg); + getApp()->getTwitchAbstract()->addFakeMessage(msg); return ""; }); @@ -325,7 +324,7 @@ void Window::addDebugStuff(HotkeyController::HotkeyMap &actions) const auto &messages = getSampleSubMessages(); static int index = 0; const auto &msg = messages[index++ % messages.size()]; - getIApp()->getTwitchAbstract()->addFakeMessage(msg); + getApp()->getTwitchAbstract()->addFakeMessage(msg); return ""; }); #endif @@ -488,7 +487,7 @@ void Window::addShortcuts() splitContainer = this->notebook_->getOrAddSelectedPage(); } Split *split = new Split(splitContainer); - split->setChannel(getIApp()->getTwitchAbstract()->getOrAddChannel( + split->setChannel(getApp()->getTwitchAbstract()->getOrAddChannel( si.channelName)); split->setFilters(si.filters); splitContainer->insertSplit(split); @@ -499,7 +498,7 @@ void Window::addShortcuts() {"toggleLocalR9K", [](std::vector) -> QString { getSettings()->hideSimilar.setValue(!getSettings()->hideSimilar); - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); return ""; }}, {"openQuickSwitcher", @@ -619,7 +618,7 @@ void Window::addShortcuts() } else if (mode == 2) { - if (getIApp()->getStreamerMode()->isEnabled()) + if (getApp()->getStreamerMode()->isEnabled()) { getSettings()->enableStreamerMode.setValue( StreamerModeSetting::Disabled); @@ -685,7 +684,7 @@ void Window::addShortcuts() this->addDebugStuff(actions); - this->shortcuts_ = getIApp()->getHotkeys()->shortcutsForCategory( + this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory( HotkeyCategory::Window, actions, this); } @@ -756,7 +755,7 @@ void Window::addMenuBar() void Window::onAccountSelected() { - auto user = getIApp()->getAccounts()->twitch.getCurrent(); + auto user = getApp()->getAccounts()->twitch.getCurrent(); // update title (also append username on Linux and MacOS) QString windowTitle = Version::instance().fullVersion(); diff --git a/src/widgets/dialogs/BadgePickerDialog.cpp b/src/widgets/dialogs/BadgePickerDialog.cpp index 143372492..f45dbbbf1 100644 --- a/src/widgets/dialogs/BadgePickerDialog.cpp +++ b/src/widgets/dialogs/BadgePickerDialog.cpp @@ -58,7 +58,7 @@ BadgePickerDialog::BadgePickerDialog(QList badges, updateBadge(0); // Set icons. - getIApp()->getTwitchBadges()->getBadgeIcons( + getApp()->getTwitchBadges()->getBadgeIcons( badges, [&dropdown = this->dropdown_](QString identifier, const QIconPtr icon) { if (!dropdown) diff --git a/src/widgets/dialogs/EditHotkeyDialog.cpp b/src/widgets/dialogs/EditHotkeyDialog.cpp index 8a43c3dba..0bf4a8148 100644 --- a/src/widgets/dialogs/EditHotkeyDialog.cpp +++ b/src/widgets/dialogs/EditHotkeyDialog.cpp @@ -26,8 +26,7 @@ EditHotkeyDialog::EditHotkeyDialog(const std::shared_ptr hotkey, this->ui_->easyArgsPicker->setVisible(false); this->ui_->easyArgsLabel->setVisible(false); // dynamically add category names to the category picker - for (const auto &[_, hotkeyCategory] : - getIApp()->getHotkeys()->categories()) + for (const auto &[_, hotkeyCategory] : getApp()->getHotkeys()->categories()) { this->ui_->categoryPicker->addItem(hotkeyCategory.displayName, hotkeyCategory.name); @@ -154,7 +153,7 @@ void EditHotkeyDialog::afterEdit() auto arguments = parseHotkeyArguments(this->ui_->argumentsEdit->toPlainText()); - auto category = getIApp()->getHotkeys()->hotkeyCategoryFromName( + auto category = getApp()->getHotkeys()->hotkeyCategoryFromName( this->ui_->categoryPicker->currentData().toString()); if (!category) { @@ -166,7 +165,7 @@ void EditHotkeyDialog::afterEdit() // check if another hotkey with this name exists, accounts for editing a hotkey bool isEditing = bool(this->data_); - if (getIApp()->getHotkeys()->getHotkeyByName(nameText)) + if (getApp()->getHotkeys()->getHotkeyByName(nameText)) { // A hotkey with this name already exists if (isEditing && this->data()->name() == nameText) @@ -243,8 +242,8 @@ void EditHotkeyDialog::afterEdit() { if (keyComboWasEdited || nameWasEdited) { - if (getIApp()->getHotkeys()->isDuplicate(hotkey, - this->data()->name())) + if (getApp()->getHotkeys()->isDuplicate(hotkey, + this->data()->name())) { this->showEditError( "Keybinding needs to be unique in the category."); @@ -254,7 +253,7 @@ void EditHotkeyDialog::afterEdit() } else { - if (getIApp()->getHotkeys()->isDuplicate(hotkey, QString())) + if (getApp()->getHotkeys()->isDuplicate(hotkey, QString())) { this->showEditError( "Keybinding needs to be unique in the category."); @@ -268,7 +267,7 @@ void EditHotkeyDialog::afterEdit() void EditHotkeyDialog::updatePossibleActions() { - const auto &hotkeys = getIApp()->getHotkeys(); + const auto &hotkeys = getApp()->getHotkeys(); auto category = hotkeys->hotkeyCategoryFromName( this->ui_->categoryPicker->currentData().toString()); if (!category) @@ -320,7 +319,7 @@ void EditHotkeyDialog::updateArgumentsInput() this->ui_->argumentsEdit->setEnabled(true); return; } - const auto &hotkeys = getIApp()->getHotkeys(); + const auto &hotkeys = getApp()->getHotkeys(); auto category = hotkeys->hotkeyCategoryFromName( this->ui_->categoryPicker->currentData().toString()); if (!category) diff --git a/src/widgets/dialogs/EmotePopup.cpp b/src/widgets/dialogs/EmotePopup.cpp index d771008ca..eb789249a 100644 --- a/src/widgets/dialogs/EmotePopup.cpp +++ b/src/widgets/dialogs/EmotePopup.cpp @@ -129,7 +129,7 @@ void addTwitchEmoteSets( { builder .emplace( - getIApp()->getEmotes()->getTwitchEmotes()->getOrCreateEmote( + getApp()->getEmotes()->getTwitchEmotes()->getOrCreateEmote( emote.id, emote.name), MessageElementFlags{MessageElementFlag::AlwaysShow, MessageElementFlag::TwitchEmote}) @@ -211,7 +211,7 @@ EmotePopup::EmotePopup(QWidget *parent) , notebook_(new Notebook(this)) { // this->setStayInScreenRect(true); - auto bounds = getIApp()->getWindows()->emotePopupBounds(); + auto bounds = getApp()->getWindows()->emotePopupBounds(); if (bounds.size().isEmpty()) { bounds.setSize(QSize{300, 500} * this->scale()); @@ -282,7 +282,7 @@ EmotePopup::EmotePopup(QWidget *parent) loadEmojis(*this->viewEmojis_, getApp()->getEmotes()->getEmojis()->getEmojis()); this->addShortcuts(); - this->signalHolder_.managedConnect(getIApp()->getHotkeys()->onItemsUpdated, + this->signalHolder_.managedConnect(getApp()->getHotkeys()->onItemsUpdated, [this]() { this->clearShortcuts(); this->addShortcuts(); @@ -380,7 +380,7 @@ void EmotePopup::addShortcuts() }}, }; - this->shortcuts_ = getIApp()->getHotkeys()->shortcutsForCategory( + this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory( HotkeyCategory::PopupWindow, actions, this); } @@ -403,12 +403,9 @@ void EmotePopup::loadChannel(ChannelPtr channel) auto channelChannel = std::make_shared("", Channel::Type::None); // twitch - addTwitchEmoteSets(getIApp() - ->getAccounts() - ->twitch.getCurrent() - ->accessEmotes() - ->emoteSets, - *globalChannel, *subChannel, this->channel_->getName()); + addTwitchEmoteSets( + getApp()->getAccounts()->twitch.getCurrent()->accessEmotes()->emoteSets, + *globalChannel, *subChannel, this->channel_->getName()); // global if (Settings::instance().enableBTTVGlobalEmotes) @@ -478,11 +475,8 @@ bool EmotePopup::eventFilter(QObject *object, QEvent *event) void EmotePopup::filterTwitchEmotes(std::shared_ptr searchChannel, const QString &searchText) { - auto twitchEmoteSets = getIApp() - ->getAccounts() - ->twitch.getCurrent() - ->accessEmotes() - ->emoteSets; + auto twitchEmoteSets = + getApp()->getAccounts()->twitch.getCurrent()->accessEmotes()->emoteSets; std::vector> twitchGlobalEmotes{}; for (const auto &set : twitchEmoteSets) @@ -503,11 +497,11 @@ void EmotePopup::filterTwitchEmotes(std::shared_ptr searchChannel, } auto bttvGlobalEmotes = - filterEmoteMap(searchText, getIApp()->getBttvEmotes()->emotes()); + filterEmoteMap(searchText, getApp()->getBttvEmotes()->emotes()); auto ffzGlobalEmotes = - filterEmoteMap(searchText, getIApp()->getFfzEmotes()->emotes()); + filterEmoteMap(searchText, getApp()->getFfzEmotes()->emotes()); auto seventvGlobalEmotes = filterEmoteMap( - searchText, getIApp()->getSeventvEmotes()->globalEmotes()); + searchText, getApp()->getSeventvEmotes()->globalEmotes()); // twitch addTwitchEmoteSets(twitchGlobalEmotes, *searchChannel, *searchChannel, @@ -580,7 +574,7 @@ void EmotePopup::filterEmotes(const QString &searchText) std::vector filteredEmojis{}; int emojiCount = 0; - const auto &emojis = getIApp()->getEmotes()->getEmojis()->getEmojis(); + const auto &emojis = getApp()->getEmotes()->getEmojis()->getEmojis(); for (const auto &emoji : emojis) { if (emoji->shortCodes[0].contains(searchText, Qt::CaseInsensitive)) @@ -603,7 +597,7 @@ void EmotePopup::filterEmotes(const QString &searchText) void EmotePopup::saveBounds() const { - getIApp()->getWindows()->setEmotePopupBounds(this->getBounds()); + getApp()->getWindows()->setEmotePopupBounds(this->getBounds()); } void EmotePopup::resizeEvent(QResizeEvent *event) diff --git a/src/widgets/dialogs/LoginDialog.cpp b/src/widgets/dialogs/LoginDialog.cpp index 34ff36776..5664acc35 100644 --- a/src/widgets/dialogs/LoginDialog.cpp +++ b/src/widgets/dialogs/LoginDialog.cpp @@ -66,8 +66,8 @@ namespace { pajlada::Settings::Setting::set(basePath + "/oauthToken", oauthToken); - getIApp()->getAccounts()->twitch.reloadUsers(); - getIApp()->getAccounts()->twitch.currentUsername = username; + getApp()->getAccounts()->twitch.reloadUsers(); + getApp()->getAccounts()->twitch.currentUsername = username; return true; } diff --git a/src/widgets/dialogs/QualityPopup.cpp b/src/widgets/dialogs/QualityPopup.cpp index 0ad5ed9c2..e08d25208 100644 --- a/src/widgets/dialogs/QualityPopup.cpp +++ b/src/widgets/dialogs/QualityPopup.cpp @@ -14,7 +14,7 @@ QualityPopup::QualityPopup(const QString &channelURL, QStringList options) BaseWindow::DisableLayoutSave, BaseWindow::BoundsCheckOnShow, }, - static_cast(&(getIApp()->getWindows()->getMainWindow()))) + static_cast(&(getApp()->getWindows()->getMainWindow()))) , channelURL_(channelURL) { this->ui_.selector = new QComboBox(this); diff --git a/src/widgets/dialogs/ReplyThreadPopup.cpp b/src/widgets/dialogs/ReplyThreadPopup.cpp index fb35e9818..ea014d078 100644 --- a/src/widgets/dialogs/ReplyThreadPopup.cpp +++ b/src/widgets/dialogs/ReplyThreadPopup.cpp @@ -77,7 +77,7 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, Split *split) {"search", nullptr}, }; - this->shortcuts_ = getIApp()->getHotkeys()->shortcutsForCategory( + this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory( HotkeyCategory::PopupWindow, actions, this); // initialize UI @@ -98,7 +98,7 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, Split *split) new SplitInput(this, this->split_, this->ui_.threadView, false); this->bSignals_.emplace_back( - getIApp()->getAccounts()->twitch.currentUserChanged.connect([this] { + getApp()->getAccounts()->twitch.currentUserChanged.connect([this] { this->updateInputUI(); })); @@ -287,7 +287,7 @@ void ReplyThreadPopup::updateInputUI() this->ui_.replyInput->setVisible(channel->isWritable()); - auto user = getIApp()->getAccounts()->twitch.getCurrent(); + auto user = getApp()->getAccounts()->twitch.getCurrent(); QString placeholderText; if (user->isAnon()) @@ -297,7 +297,7 @@ void ReplyThreadPopup::updateInputUI() else { placeholderText = QStringLiteral("Reply as %1...") - .arg(getIApp() + .arg(getApp() ->getAccounts() ->twitch.getCurrent() ->getUserName()); diff --git a/src/widgets/dialogs/SelectChannelDialog.cpp b/src/widgets/dialogs/SelectChannelDialog.cpp index d482bb121..1eb33c172 100644 --- a/src/widgets/dialogs/SelectChannelDialog.cpp +++ b/src/widgets/dialogs/SelectChannelDialog.cpp @@ -380,28 +380,28 @@ IndirectChannel SelectChannelDialog::getSelectedChannel() const case TAB_TWITCH: { if (this->ui_.twitch.channel->isChecked()) { - return getIApp()->getTwitchAbstract()->getOrAddChannel( + return getApp()->getTwitchAbstract()->getOrAddChannel( this->ui_.twitch.channelName->text().trimmed()); } else if (this->ui_.twitch.watching->isChecked()) { - return getIApp()->getTwitch()->getWatchingChannel(); + return getApp()->getTwitch()->getWatchingChannel(); } else if (this->ui_.twitch.mentions->isChecked()) { - return getIApp()->getTwitch()->getMentionsChannel(); + return getApp()->getTwitch()->getMentionsChannel(); } else if (this->ui_.twitch.whispers->isChecked()) { - return getIApp()->getTwitch()->getWhispersChannel(); + return getApp()->getTwitch()->getWhispersChannel(); } else if (this->ui_.twitch.live->isChecked()) { - return getIApp()->getTwitch()->getLiveChannel(); + return getApp()->getTwitch()->getLiveChannel(); } else if (this->ui_.twitch.automod->isChecked()) { - return getIApp()->getTwitch()->getAutomodChannel(); + return getApp()->getTwitch()->getAutomodChannel(); } } break; @@ -613,7 +613,7 @@ void SelectChannelDialog::addShortcuts() actions.emplace("openTab", nullptr); } - this->shortcuts_ = getIApp()->getHotkeys()->shortcutsForCategory( + this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory( HotkeyCategory::PopupWindow, actions, this); } diff --git a/src/widgets/dialogs/SettingsDialog.cpp b/src/widgets/dialogs/SettingsDialog.cpp index d9ad48fff..fa0d2bd55 100644 --- a/src/widgets/dialogs/SettingsDialog.cpp +++ b/src/widgets/dialogs/SettingsDialog.cpp @@ -57,7 +57,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) this->overrideBackgroundColor_ = QColor("#111111"); this->addShortcuts(); - this->signalHolder_.managedConnect(getIApp()->getHotkeys()->onItemsUpdated, + this->signalHolder_.managedConnect(getApp()->getHotkeys()->onItemsUpdated, [this]() { this->clearShortcuts(); this->addShortcuts(); @@ -81,13 +81,13 @@ void SettingsDialog::addShortcuts() {"openTab", nullptr}, }; - this->shortcuts_ = getIApp()->getHotkeys()->shortcutsForCategory( + this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory( HotkeyCategory::PopupWindow, actions, this); } void SettingsDialog::setSearchPlaceholderText() { QString searchHotkey; - auto searchSeq = getIApp()->getHotkeys()->getDisplaySequence( + auto searchSeq = getApp()->getHotkeys()->getDisplaySequence( HotkeyCategory::PopupWindow, "search"); if (!searchSeq.isEmpty()) { @@ -434,7 +434,7 @@ void SettingsDialog::onOkClicked() { if (!getApp()->getArgs().dontSaveSettings) { - getIApp()->getCommands()->save(); + getApp()->getCommands()->save(); pajlada::Settings::SettingManager::gSave(); } this->close(); diff --git a/src/widgets/dialogs/UpdateDialog.cpp b/src/widgets/dialogs/UpdateDialog.cpp index d9c6869f6..64ec27eec 100644 --- a/src/widgets/dialogs/UpdateDialog.cpp +++ b/src/widgets/dialogs/UpdateDialog.cpp @@ -27,7 +27,7 @@ UpdateDialog::UpdateDialog() auto *dismiss = buttons->addButton("Dismiss", QDialogButtonBox::RejectRole); QObject::connect(install, &QPushButton::clicked, this, [this] { - getIApp()->getUpdates().installUpdates(); + getApp()->getUpdates().installUpdates(); this->close(); }); QObject::connect(dismiss, &QPushButton::clicked, this, [this] { @@ -35,8 +35,8 @@ UpdateDialog::UpdateDialog() this->close(); }); - this->updateStatusChanged(getIApp()->getUpdates().getStatus()); - this->connections_.managedConnect(getIApp()->getUpdates().statusUpdated, + this->updateStatusChanged(getApp()->getUpdates().getStatus()); + this->connections_.managedConnect(getApp()->getUpdates().statusUpdated, [this](auto status) { this->updateStatusChanged(status); }); @@ -53,17 +53,17 @@ void UpdateDialog::updateStatusChanged(Updates::Status status) { case Updates::UpdateAvailable: { this->ui_.label->setText(( - getIApp()->getUpdates().isDowngrade() + getApp()->getUpdates().isDowngrade() ? QString( "The version online (%1) seems to be\nlower than the " "current (%2).\nEither a version was reverted or " "you are\nrunning a newer build.\n\nDo you want to " "download and install it?") - .arg(getIApp()->getUpdates().getOnlineVersion(), - getIApp()->getUpdates().getCurrentVersion()) + .arg(getApp()->getUpdates().getOnlineVersion(), + getApp()->getUpdates().getCurrentVersion()) : QString("An update (%1) is available.\n\nDo you want to " "download and install it?") - .arg(getIApp()->getUpdates().getOnlineVersion()))); + .arg(getApp()->getUpdates().getOnlineVersion()))); this->updateGeometry(); } break; diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index afd28d4fb..89d43da37 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -56,7 +56,7 @@ namespace { { button.assign(copyButton); } - button->setPixmap(getIApp()->getThemes()->buttons.copy); + button->setPixmap(getApp()->getThemes()->buttons.copy); button->setScaleIndependantSize(18, 18); button->setDim(Button::Dim::Lots); button->setToolTip(tooltip); @@ -223,7 +223,7 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) .arg(calculateTimeoutDuration(button)); } - msg = getIApp()->getCommands()->execCommand( + msg = getApp()->getCommands()->execCommand( msg, this->underlyingChannel_, false); this->underlyingChannel_->sendMessage(msg); @@ -242,7 +242,7 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) {"search", nullptr}, }; - this->shortcuts_ = getIApp()->getHotkeys()->shortcutsForCategory( + this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory( HotkeyCategory::PopupWindow, actions, this); auto layers = LayoutCreator(this->getLayoutContainer()) @@ -295,7 +295,7 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) menu->addAction( "Open channel in a new popup window", this, [loginName] { - auto *app = getIApp(); + auto *app = getApp(); auto &window = app->getWindows()->createWindow( WindowType::Popup, true); auto *split = window.getNotebook() @@ -309,7 +309,7 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) menu->addAction( "Open channel in a new tab", this, [loginName] { ChannelPtr channel = - getIApp() + getApp() ->getTwitchAbstract() ->getOrAddChannel(loginName); auto &nb = getApp() @@ -414,25 +414,25 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) QObject::connect(mod.getElement(), &Button::leftClicked, [this] { QString value = "/mod " + this->userName_; - value = getIApp()->getCommands()->execCommand( + value = getApp()->getCommands()->execCommand( value, this->underlyingChannel_, false); this->underlyingChannel_->sendMessage(value); }); QObject::connect(unmod.getElement(), &Button::leftClicked, [this] { QString value = "/unmod " + this->userName_; - value = getIApp()->getCommands()->execCommand( + value = getApp()->getCommands()->execCommand( value, this->underlyingChannel_, false); this->underlyingChannel_->sendMessage(value); }); QObject::connect(vip.getElement(), &Button::leftClicked, [this] { QString value = "/vip " + this->userName_; - value = getIApp()->getCommands()->execCommand( + value = getApp()->getCommands()->execCommand( value, this->underlyingChannel_, false); this->underlyingChannel_->sendMessage(value); }); QObject::connect(unvip.getElement(), &Button::leftClicked, [this] { QString value = "/unvip " + this->userName_; - value = getIApp()->getCommands()->execCommand( + value = getApp()->getCommands()->execCommand( value, this->underlyingChannel_, false); this->underlyingChannel_->sendMessage(value); }); @@ -450,7 +450,7 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) if (twitchChannel) { bool isMyself = - QString::compare(getIApp() + QString::compare(getApp() ->getAccounts() ->twitch.getCurrent() ->getUserName(), @@ -499,7 +499,7 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) if (this->underlyingChannel_) { QString value = "/ban " + this->userName_; - value = getIApp()->getCommands()->execCommand( + value = getApp()->getCommands()->execCommand( value, this->underlyingChannel_, false); this->underlyingChannel_->sendMessage(value); @@ -510,7 +510,7 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) if (this->underlyingChannel_) { QString value = "/unban " + this->userName_; - value = getIApp()->getCommands()->execCommand( + value = getApp()->getCommands()->execCommand( value, this->underlyingChannel_, false); this->underlyingChannel_->sendMessage(value); @@ -523,7 +523,7 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, Split *split) QString value = "/timeout " + this->userName_ + " " + QString::number(arg); - value = getIApp()->getCommands()->execCommand( + value = getApp()->getCommands()->execCommand( value, this->underlyingChannel_, false); this->underlyingChannel_->sendMessage(value); @@ -572,7 +572,7 @@ void UserInfoPopup::themeChangedEvent() for (auto &&child : this->findChildren()) { child->setFont( - getIApp()->getFonts()->getFont(FontStyle::UiMedium, this->scale())); + getApp()->getFonts()->getFont(FontStyle::UiMedium, this->scale())); } } @@ -597,7 +597,7 @@ void UserInfoPopup::installEvents() QObject::connect( this->ui_.block, &QCheckBox::stateChanged, [this](int newState) mutable { - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); const auto reenableBlockCheckbox = [this] { this->ui_.block->setEnabled(true); @@ -614,7 +614,7 @@ void UserInfoPopup::installEvents() case Qt::CheckState::Unchecked: { this->ui_.block->setEnabled(false); - getIApp()->getAccounts()->twitch.getCurrent()->unblockUser( + getApp()->getAccounts()->twitch.getCurrent()->unblockUser( this->userId_, this, [this, reenableBlockCheckbox, currentUser] { this->channel_->addSystemMessage( @@ -641,7 +641,7 @@ void UserInfoPopup::installEvents() case Qt::CheckState::Checked: { this->ui_.block->setEnabled(false); - getIApp()->getAccounts()->twitch.getCurrent()->blockUser( + getApp()->getAccounts()->twitch.getCurrent()->blockUser( this->userId_, this, [this, reenableBlockCheckbox, currentUser] { this->channel_->addSystemMessage( @@ -798,7 +798,7 @@ void UserInfoPopup::updateLatestMessages() void UserInfoPopup::updateUserData() { std::weak_ptr hack = this->lifetimeHack_; - auto currentUser = getIApp()->getAccounts()->twitch.getCurrent(); + auto currentUser = getApp()->getAccounts()->twitch.getCurrent(); const auto onUserFetchFailed = [this, hack] { if (!hack.lock()) @@ -858,7 +858,7 @@ void UserInfoPopup::updateUserData() this->ui_.userIDLabel->setText(TEXT_USER_ID + user.id); this->ui_.userIDLabel->setProperty("copy-text", user.id); - if (getIApp()->getStreamerMode()->isEnabled() && + if (getApp()->getStreamerMode()->isEnabled() && getSettings()->streamerModeHideUsercardAvatars) { this->ui_.avatarButton->setPixmap(getResources().streamerMode); diff --git a/src/widgets/dialogs/switcher/NewPopupItem.cpp b/src/widgets/dialogs/switcher/NewPopupItem.cpp index d4bc01bbd..2f79693a0 100644 --- a/src/widgets/dialogs/switcher/NewPopupItem.cpp +++ b/src/widgets/dialogs/switcher/NewPopupItem.cpp @@ -22,8 +22,8 @@ NewPopupItem::NewPopupItem(const QString &channelName) void NewPopupItem::action() { auto channel = - getIApp()->getTwitchAbstract()->getOrAddChannel(this->channelName_); - getIApp()->getWindows()->openInPopup(channel); + getApp()->getTwitchAbstract()->getOrAddChannel(this->channelName_); + getApp()->getWindows()->openInPopup(channel); } void NewPopupItem::paint(QPainter *painter, const QRect &rect) const @@ -32,10 +32,10 @@ void NewPopupItem::paint(QPainter *painter, const QRect &rect) const painter->setRenderHint(QPainter::Antialiasing, true); - painter->setPen(getIApp()->getThemes()->splits.header.text); + painter->setPen(getApp()->getThemes()->splits.header.text); painter->setBrush(Qt::SolidPattern); painter->setFont( - getIApp()->getFonts()->getFont(FontStyle::UiMediumBold, 1.0)); + getApp()->getFonts()->getFont(FontStyle::UiMediumBold, 1.0)); QRect iconRect(rect.topLeft(), ICON_SIZE); this->icon_.paint(painter, iconRect, Qt::AlignLeft | Qt::AlignVCenter); diff --git a/src/widgets/dialogs/switcher/NewTabItem.cpp b/src/widgets/dialogs/switcher/NewTabItem.cpp index 967c14aca..0ce337e15 100644 --- a/src/widgets/dialogs/switcher/NewTabItem.cpp +++ b/src/widgets/dialogs/switcher/NewTabItem.cpp @@ -27,7 +27,7 @@ void NewTabItem::action() Split *split = new Split(container); split->setChannel( - getIApp()->getTwitchAbstract()->getOrAddChannel(this->channelName_)); + getApp()->getTwitchAbstract()->getOrAddChannel(this->channelName_)); container->insertSplit(split); } @@ -38,10 +38,10 @@ void NewTabItem::paint(QPainter *painter, const QRect &rect) const painter->setRenderHint(QPainter::Antialiasing, true); // TODO(leon): Right pen/brush/font settings? - painter->setPen(getIApp()->getThemes()->splits.header.text); + painter->setPen(getApp()->getThemes()->splits.header.text); painter->setBrush(Qt::SolidPattern); painter->setFont( - getIApp()->getFonts()->getFont(FontStyle::UiMediumBold, 1.0)); + getApp()->getFonts()->getFont(FontStyle::UiMediumBold, 1.0)); QRect iconRect(rect.topLeft(), ICON_SIZE); this->icon_.paint(painter, iconRect, Qt::AlignLeft | Qt::AlignVCenter); diff --git a/src/widgets/dialogs/switcher/SwitchSplitItem.cpp b/src/widgets/dialogs/switcher/SwitchSplitItem.cpp index 63c860cc6..f3cb31c5c 100644 --- a/src/widgets/dialogs/switcher/SwitchSplitItem.cpp +++ b/src/widgets/dialogs/switcher/SwitchSplitItem.cpp @@ -21,11 +21,11 @@ void SwitchSplitItem::action() { if (this->split_) { - getIApp()->getWindows()->select(this->split_); + getApp()->getWindows()->select(this->split_); } else if (this->container_) { - getIApp()->getWindows()->select(this->container_); + getApp()->getWindows()->select(this->container_); } } @@ -36,10 +36,10 @@ void SwitchSplitItem::paint(QPainter *painter, const QRect &rect) const painter->setRenderHint(QPainter::Antialiasing, true); // TODO(leon): Right pen/brush/font settings? - painter->setPen(getIApp()->getThemes()->splits.header.text); + painter->setPen(getApp()->getThemes()->splits.header.text); painter->setBrush(Qt::SolidPattern); painter->setFont( - getIApp()->getFonts()->getFont(FontStyle::UiMediumBold, 1.0)); + getApp()->getFonts()->getFont(FontStyle::UiMediumBold, 1.0)); QRect iconRect(rect.topLeft(), ICON_SIZE); this->icon_.paint(painter, iconRect, Qt::AlignLeft | Qt::AlignVCenter); @@ -60,7 +60,7 @@ void SwitchSplitItem::paint(QPainter *painter, const QRect &rect) const QSize(0.7 * availableTextWidth, iconRect.height())); painter->setFont( - getIApp()->getFonts()->getFont(FontStyle::UiMedium, 1.0)); + getApp()->getFonts()->getFont(FontStyle::UiMedium, 1.0)); painter->drawText(rightTextRect, Qt::AlignRight | Qt::AlignVCenter, this->container_->getTab()->getTitle()); } diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 26e31c9bf..7430614a9 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -427,11 +427,11 @@ void ChannelView::initializeScrollbar() void ChannelView::initializeSignals() { - this->signalHolder_.managedConnect( - getIApp()->getWindows()->wordFlagsChanged, [this] { - this->queueLayout(); - this->update(); - }); + this->signalHolder_.managedConnect(getApp()->getWindows()->wordFlagsChanged, + [this] { + this->queueLayout(); + this->update(); + }); getSettings()->showLastMessageIndicator.connect( [this](auto, auto) { @@ -440,7 +440,7 @@ void ChannelView::initializeSignals() this->signalHolder_); this->signalHolder_.managedConnect( - getIApp()->getWindows()->gifRepaintRequested, [&] { + getApp()->getWindows()->gifRepaintRequested, [&] { if (!this->animationArea_.isEmpty()) { this->queueUpdate(this->animationArea_); @@ -448,7 +448,7 @@ void ChannelView::initializeSignals() }); this->signalHolder_.managedConnect( - getIApp()->getWindows()->layoutRequested, [&](Channel *channel) { + getApp()->getWindows()->layoutRequested, [&](Channel *channel) { if (this->isVisible() && (channel == nullptr || this->underlyingChannel_.get() == channel)) @@ -458,7 +458,7 @@ void ChannelView::initializeSignals() }); this->signalHolder_.managedConnect( - getIApp()->getWindows()->invalidateBuffersRequested, + getApp()->getWindows()->invalidateBuffersRequested, [this](Channel *channel) { if (this->isVisible() && (channel == nullptr || @@ -468,7 +468,7 @@ void ChannelView::initializeSignals() } }); - this->signalHolder_.managedConnect(getIApp()->getFonts()->fontChanged, + this->signalHolder_.managedConnect(getApp()->getFonts()->fontChanged, [this] { this->queueLayout(); }); @@ -622,7 +622,7 @@ void ChannelView::scaleChangedEvent(float scale) 0.01, this->logicalDpiX() * this->devicePixelRatioF()); #endif this->goToBottom_->getLabel().setFont( - getIApp()->getFonts()->getFont(FontStyle::UiMedium, factor)); + getApp()->getFonts()->getFont(FontStyle::UiMedium, factor)); } } @@ -1087,11 +1087,8 @@ bool ChannelView::shouldIncludeMessage(const MessagePtr &m) const if (this->channelFilters_) { if (getSettings()->excludeUserMessagesFromFilter && - getIApp() - ->getAccounts() - ->twitch.getCurrent() - ->getUserName() - .compare(m->loginName, Qt::CaseInsensitive) == 0) + getApp()->getAccounts()->twitch.getCurrent()->getUserName().compare( + m->loginName, Qt::CaseInsensitive) == 0) { return true; } @@ -1377,19 +1374,19 @@ MessageElementFlags ChannelView::getFlags() const flags.set(MessageElementFlag::ModeratorTools); } if (this->underlyingChannel_ == - getIApp()->getTwitch()->getMentionsChannel() || + getApp()->getTwitch()->getMentionsChannel() || this->underlyingChannel_ == - getIApp()->getTwitch()->getLiveChannel() || + getApp()->getTwitch()->getLiveChannel() || this->underlyingChannel_ == - getIApp()->getTwitch()->getAutomodChannel()) + getApp()->getTwitch()->getAutomodChannel()) { flags.set(MessageElementFlag::ChannelName); flags.unset(MessageElementFlag::ChannelPointReward); } } - if (this->sourceChannel_ == getIApp()->getTwitch()->getMentionsChannel() || - this->sourceChannel_ == getIApp()->getTwitch()->getAutomodChannel()) + if (this->sourceChannel_ == getApp()->getTwitch()->getMentionsChannel() || + this->sourceChannel_ == getApp()->getTwitch()->getAutomodChannel()) { flags.set(MessageElementFlag::ChannelName); } @@ -1446,7 +1443,7 @@ bool ChannelView::scrollToMessage(const MessagePtr &message) this->scrollToMessageLayout(messagesSnapshot[messageIdx].get(), messageIdx); if (this->split_) { - getIApp()->getWindows()->select(this->split_); + getApp()->getWindows()->select(this->split_); } return true; } @@ -1478,7 +1475,7 @@ bool ChannelView::scrollToMessageId(const QString &messageId) this->scrollToMessageLayout(messagesSnapshot[messageIdx].get(), messageIdx); if (this->split_) { - getIApp()->getWindows()->select(this->split_); + getApp()->getWindows()->select(this->split_); } return true; } @@ -1543,7 +1540,7 @@ void ChannelView::drawMessages(QPainter &painter, const QRect &area) .canvasWidth = this->width(), .isWindowFocused = this->window() == QApplication::activeWindow(), .isMentions = this->underlyingChannel_ == - getIApp()->getTwitch()->getMentionsChannel(), + getApp()->getTwitch()->getMentionsChannel(), .y = int(-(messagesSnapshot[start]->getHeight() * (fmod(this->scrollBar_->getRelativeCurrentValue(), 1)))), @@ -1968,7 +1965,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event) { if (linkElement->linkInfo()->isPending()) { - getIApp()->getLinkResolver()->resolve( + getApp()->getLinkResolver()->resolve( linkElement->linkInfo()); } this->setLinkInfoTooltip(linkElement->linkInfo()); @@ -2479,7 +2476,7 @@ void ChannelView::addMessageContextMenuItems(QMenu *menu, } else if (isMentions || isAutomod) { - getIApp()->getWindows()->scrollToMessage(messagePtr); + getApp()->getWindows()->scrollToMessage(messagePtr); } else if (isReplyOrUserCard) { @@ -2489,7 +2486,7 @@ void ChannelView::addMessageContextMenuItems(QMenu *menu, if (type == Channel::Type::TwitchMentions || type == Channel::Type::TwitchAutomod) { - getIApp()->getWindows()->scrollToMessage(messagePtr); + getApp()->getWindows()->scrollToMessage(messagePtr); } else { @@ -2570,7 +2567,7 @@ void ChannelView::addCommandExecutionContextMenuItems( /* Get commands to be displayed in context menu; * only those that had the showInMsgContextMenu check box marked in the Commands page */ std::vector cmds; - for (const auto &cmd : getIApp()->getCommands()->items) + for (const auto &cmd : getApp()->getCommands()->items) { if (cmd.showInMsgContextMenu) { @@ -2617,14 +2614,13 @@ void ChannelView::addCommandExecutionContextMenuItems( } // Execute command through right-clicking a message -> Execute command - QString value = getIApp()->getCommands()->execCustomCommand( + QString value = getApp()->getCommands()->execCustomCommand( inputText.split(' '), cmd, true, channel, layout->getMessage(), { {"input.text", userText}, }); - value = - getIApp()->getCommands()->execCommand(value, channel, false); + value = getApp()->getCommands()->execCommand(value, channel, false); channel->sendMessage(value); }); @@ -2703,7 +2699,7 @@ void ChannelView::showUserInfoPopup(const QString &userName, auto *userPopup = new UserInfoPopup(getSettings()->autoCloseUserPopup, this->split_); - auto contextChannel = getIApp()->getTwitchAbstract()->getChannelOrEmpty( + auto contextChannel = getApp()->getTwitchAbstract()->getChannelOrEmpty( alternativePopoutChannel); auto openingChannel = this->hasSourceChannel() ? this->sourceChannel_ : this->underlyingChannel_; @@ -2790,25 +2786,24 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link, } // Execute command clicking a moderator button - value = getIApp()->getCommands()->execCustomCommand( + value = getApp()->getCommands()->execCustomCommand( QStringList(), Command{"(modaction)", value}, true, channel, layout->getMessage()); - value = - getIApp()->getCommands()->execCommand(value, channel, false); + value = getApp()->getCommands()->execCommand(value, channel, false); channel->sendMessage(value); } break; case Link::AutoModAllow: { - getIApp()->getAccounts()->twitch.getCurrent()->autoModAllow( + getApp()->getAccounts()->twitch.getCurrent()->autoModAllow( link.value, this->channel()); } break; case Link::AutoModDeny: { - getIApp()->getAccounts()->twitch.getCurrent()->autoModDeny( + getApp()->getAccounts()->twitch.getCurrent()->autoModDeny( link.value, this->channel()); } break; @@ -2822,7 +2817,7 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link, // Get all currently open pages QList openPages; - auto &nb = getIApp()->getWindows()->getMainWindow().getNotebook(); + auto &nb = getApp()->getWindows()->getMainWindow().getNotebook(); for (int i = 0; i < nb.getPageCount(); ++i) { openPages.push_back( @@ -3095,7 +3090,7 @@ void ChannelView::setLinkInfoTooltip(LinkInfo *info) ImagePtr thumbnail; if (info->hasThumbnail() && thumbnailSize > 0) { - if (getIApp()->getStreamerMode()->isEnabled() && + if (getApp()->getStreamerMode()->isEnabled() && getSettings()->streamerModeHideLinkThumbnails) { thumbnail = Image::fromResourcePixmap(getResources().streamerMode); diff --git a/src/widgets/helper/NotebookTab.cpp b/src/widgets/helper/NotebookTab.cpp index a5d8cfb69..ea893f6ea 100644 --- a/src/widgets/helper/NotebookTab.cpp +++ b/src/widgets/helper/NotebookTab.cpp @@ -86,8 +86,8 @@ NotebookTab::NotebookTab(Notebook *notebook) [this]() { this->notebook_->removePage(this->page); }, - getIApp()->getHotkeys()->getDisplaySequence(HotkeyCategory::Window, - "removeTab")); + getApp()->getHotkeys()->getDisplaySequence(HotkeyCategory::Window, + "removeTab")); this->menu_.addAction( "Popup Tab", @@ -97,8 +97,8 @@ NotebookTab::NotebookTab(Notebook *notebook) container->popup(); } }, - getIApp()->getHotkeys()->getDisplaySequence(HotkeyCategory::Window, - "popup", {{"window"}})); + getApp()->getHotkeys()->getDisplaySequence(HotkeyCategory::Window, + "popup", {{"window"}})); this->menu_.addAction("Duplicate Tab", [this]() { this->notebook_->duplicatePage(this->page); @@ -199,7 +199,7 @@ int NotebookTab::normalTabWidthForHeight(int height) const int width = 0; QFontMetrics metrics = - getIApp()->getFonts()->getFontMetrics(FontStyle::UiTabs, scale); + getApp()->getFonts()->getFontMetrics(FontStyle::UiTabs, scale); if (this->hasXButton()) { @@ -291,7 +291,7 @@ const QString &NotebookTab::getTitle() const void NotebookTab::titleUpdated() { // Queue up save because: Tab title changed - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); this->notebook_->refresh(); this->updateSize(); this->update(); diff --git a/src/widgets/helper/SearchPopup.cpp b/src/widgets/helper/SearchPopup.cpp index fb8dfee8b..52138028a 100644 --- a/src/widgets/helper/SearchPopup.cpp +++ b/src/widgets/helper/SearchPopup.cpp @@ -103,7 +103,7 @@ void SearchPopup::addShortcuts() {"scrollPage", nullptr}, }; - this->shortcuts_ = getIApp()->getHotkeys()->shortcutsForCategory( + this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory( HotkeyCategory::PopupWindow, actions, this); } @@ -138,7 +138,7 @@ void SearchPopup::goToMessage(const MessagePtr &message) if (type == Channel::Type::TwitchMentions || type == Channel::Type::TwitchAutomod) { - getIApp()->getWindows()->scrollToMessage(message); + getApp()->getWindows()->scrollToMessage(message); return; } diff --git a/src/widgets/settingspages/AccountsPage.cpp b/src/widgets/settingspages/AccountsPage.cpp index c41b149b2..9828ce3e6 100644 --- a/src/widgets/settingspages/AccountsPage.cpp +++ b/src/widgets/settingspages/AccountsPage.cpp @@ -63,7 +63,7 @@ AccountsPage::AccountsPage() // return; // } - // getIApp()->getAccounts()->Twitch.removeUser(selectedUser); + // getApp()->getAccounts()->Twitch.removeUser(selectedUser); // }); } diff --git a/src/widgets/settingspages/CommandPage.cpp b/src/widgets/settingspages/CommandPage.cpp index de94d11d2..5aa0dc3d4 100644 --- a/src/widgets/settingspages/CommandPage.cpp +++ b/src/widgets/settingspages/CommandPage.cpp @@ -87,7 +87,7 @@ CommandPage::CommandPage() auto *view = layout .emplace( - getIApp()->getCommands()->createModel(nullptr)) + getApp()->getCommands()->createModel(nullptr)) .getElement(); view->setTitles({"Trigger", "Command", "Show In\nMessage Menu"}); @@ -95,7 +95,7 @@ CommandPage::CommandPage() 1, QHeaderView::Stretch); // We can safely ignore this signal connection since we own the view std::ignore = view->addButtonPressed.connect([] { - getIApp()->getCommands()->items.append( + getApp()->getCommands()->items.append( Command{"/command", "I made a new command HeyGuys"}); }); @@ -114,7 +114,7 @@ CommandPage::CommandPage() { if (int index = line.indexOf(' '); index != -1) { - getIApp()->getCommands()->items.insert( + getApp()->getCommands()->items.insert( Command(line.mid(0, index), line.mid(index + 1))); } } diff --git a/src/widgets/settingspages/GeneralPage.cpp b/src/widgets/settingspages/GeneralPage.cpp index 9d27b5d08..13dcb445a 100644 --- a/src/widgets/settingspages/GeneralPage.cpp +++ b/src/widgets/settingspages/GeneralPage.cpp @@ -122,7 +122,7 @@ void GeneralPage::initLayout(GeneralPageView &layout) layout.addTitle("Interface"); { - auto *themes = getIApp()->getThemes(); + auto *themes = getApp()->getThemes(); auto available = themes->availableThemes(); #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) available.emplace_back("System", "System"); @@ -273,7 +273,7 @@ void GeneralPage::initLayout(GeneralPageView &layout) layout.addCheckbox("Show message reply button", s.showReplyButton, false, "Show a reply button next to every chat message"); - auto removeTabSeq = getIApp()->getHotkeys()->getDisplaySequence( + auto removeTabSeq = getApp()->getHotkeys()->getDisplaySequence( HotkeyCategory::Window, "removeTab"); QString removeTabShortcut = "an assigned hotkey (Window -> remove tab)"; if (!removeTabSeq.isEmpty()) @@ -294,7 +294,7 @@ void GeneralPage::initLayout(GeneralPageView &layout) #endif if (!BaseWindow::supportsCustomWindowFrame()) { - auto settingsSeq = getIApp()->getHotkeys()->getDisplaySequence( + auto settingsSeq = getApp()->getHotkeys()->getDisplaySequence( HotkeyCategory::Window, "openSettings"); QString shortcut = " (no key bound to open them otherwise)"; // TODO: maybe prevent the user from locking themselves out of the settings? @@ -570,7 +570,7 @@ void GeneralPage::initLayout(GeneralPageView &layout) // as an official description from 7TV devs is best s.showUnlistedSevenTVEmotes.connect( []() { - getIApp()->getTwitch()->forEachChannelAndSpecialChannels( + getApp()->getTwitch()->forEachChannelAndSpecialChannels( [](const auto &c) { if (c->isTwitchChannel()) { @@ -824,9 +824,9 @@ void GeneralPage::initLayout(GeneralPageView &layout) layout.addButton("Open AppData directory", [] { #ifdef Q_OS_DARWIN QDesktopServices::openUrl("file://" + - getIApp()->getPaths().rootAppDataDirectory); + getApp()->getPaths().rootAppDataDirectory); #else - QDesktopServices::openUrl(getIApp()->getPaths().rootAppDataDirectory); + QDesktopServices::openUrl(getApp()->getPaths().rootAppDataDirectory); #endif }); @@ -838,7 +838,7 @@ void GeneralPage::initLayout(GeneralPageView &layout) auto *cachePathLabel = layout.addDescription("placeholder :D"); getSettings()->cachePath.connect([cachePathLabel](const auto &, auto) mutable { - QString newPath = getIApp()->getPaths().cacheDirectory(); + QString newPath = getApp()->getPaths().cacheDirectory(); QString pathShortened = "Cache saved at " + @@ -866,9 +866,9 @@ void GeneralPage::initLayout(GeneralPageView &layout) if (reply == QMessageBox::Yes) { - auto cacheDir = QDir(getIApp()->getPaths().cacheDirectory()); + auto cacheDir = QDir(getApp()->getPaths().cacheDirectory()); cacheDir.removeRecursively(); - cacheDir.mkdir(getIApp()->getPaths().cacheDirectory()); + cacheDir.mkdir(getApp()->getPaths().cacheDirectory()); } })); box->addStretch(1); @@ -890,7 +890,7 @@ void GeneralPage::initLayout(GeneralPageView &layout) "Show the stream title"); layout.addSubtitle("R9K"); - auto toggleLocalr9kSeq = getIApp()->getHotkeys()->getDisplaySequence( + auto toggleLocalr9kSeq = getApp()->getHotkeys()->getDisplaySequence( HotkeyCategory::Window, "toggleLocalR9K"); QString toggleLocalr9kShortcut = "an assigned hotkey (Window -> Toggle local R9K)"; @@ -913,7 +913,7 @@ void GeneralPage::initLayout(GeneralPageView &layout) s.shownSimilarTriggerHighlights); s.hideSimilar.connect( []() { - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); }, false); layout.addDropdown( @@ -981,15 +981,15 @@ void GeneralPage::initLayout(GeneralPageView &layout) layout.addCustomCheckbox( "Restart on crash (requires restart)", [] { - return getIApp()->getCrashHandler()->shouldRecover(); + return getApp()->getCrashHandler()->shouldRecover(); }, [](bool on) { - return getIApp()->getCrashHandler()->saveShouldRecover(on); + return getApp()->getCrashHandler()->saveShouldRecover(on); }, "When possible, restart Chatterino if the program crashes"); #if defined(Q_OS_LINUX) && !defined(NO_QTKEYCHAIN) - if (!getIApp()->getPaths().isPortable()) + if (!getApp()->getPaths().isPortable()) { layout.addCheckbox( "Use libsecret/KWallet/Gnome keychain to secure passwords", @@ -1196,7 +1196,7 @@ void GeneralPage::initExtra() { getSettings()->cachePath.connect( [cachePath = this->cachePath_](const auto &, auto) mutable { - QString newPath = getIApp()->getPaths().cacheDirectory(); + QString newPath = getApp()->getPaths().cacheDirectory(); QString pathShortened = "Current location: " + @@ -1216,7 +1216,7 @@ QString GeneralPage::getFont(const DropdownArgs &args) const auto ok = bool(); auto previousFont = - getIApp()->getFonts()->getFont(FontStyle::ChatMedium, 1.); + getApp()->getFonts()->getFont(FontStyle::ChatMedium, 1.); auto font = QFontDialog::getFont(&ok, previousFont, this->window()); if (ok) diff --git a/src/widgets/settingspages/GeneralPageView.cpp b/src/widgets/settingspages/GeneralPageView.cpp index 94ec3d23c..293992581 100644 --- a/src/widgets/settingspages/GeneralPageView.cpp +++ b/src/widgets/settingspages/GeneralPageView.cpp @@ -197,7 +197,7 @@ ComboBox *GeneralPageView::addDropdown( QObject::connect(combo, &QComboBox::currentTextChanged, [&setting](const QString &newValue) { setting = newValue; - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); }); return combo; diff --git a/src/widgets/settingspages/GeneralPageView.hpp b/src/widgets/settingspages/GeneralPageView.hpp index 7e1625a70..4ce1c5b4e 100644 --- a/src/widgets/settingspages/GeneralPageView.hpp +++ b/src/widgets/settingspages/GeneralPageView.hpp @@ -204,7 +204,7 @@ public: .index = combo->currentIndex(), .combobox = combo, }); - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); }; if (listenToActivated) @@ -268,7 +268,7 @@ public: setValue = std::move(setValue)](const int newIndex) { setting = setValue(DropdownArgs{combo->itemText(newIndex), combo->currentIndex(), combo}); - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); }); return combo; @@ -312,7 +312,7 @@ public: // Instead, it's up to the getters to make sure that the setting is legic - see the enum_cast above // You could also use the settings `getEnum` function setting = newText; - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); }); return combo; diff --git a/src/widgets/settingspages/KeyboardSettingsPage.cpp b/src/widgets/settingspages/KeyboardSettingsPage.cpp index 04bc80abb..9f9ae24e5 100644 --- a/src/widgets/settingspages/KeyboardSettingsPage.cpp +++ b/src/widgets/settingspages/KeyboardSettingsPage.cpp @@ -22,7 +22,7 @@ using namespace chatterino; void tableCellClicked(const QModelIndex &clicked, EditableModelView *view, HotkeyModel *model) { - auto hotkey = getIApp()->getHotkeys()->getHotkeyByName( + auto hotkey = getApp()->getHotkeys()->getHotkeyByName( clicked.siblingAtColumn(0).data(Qt::EditRole).toString()); if (!hotkey) { @@ -34,8 +34,8 @@ void tableCellClicked(const QModelIndex &clicked, EditableModelView *view, if (wasAccepted) { auto newHotkey = dialog.data(); - getIApp()->getHotkeys()->replaceHotkey(hotkey->name(), newHotkey); - getIApp()->getHotkeys()->save(); + getApp()->getHotkeys()->replaceHotkey(hotkey->name(), newHotkey); + getApp()->getHotkeys()->save(); } } @@ -48,7 +48,7 @@ KeyboardSettingsPage::KeyboardSettingsPage() LayoutCreator layoutCreator(this); auto layout = layoutCreator.emplace(); - auto *model = getIApp()->getHotkeys()->createModel(nullptr); + auto *model = getApp()->getHotkeys()->createModel(nullptr); EditableModelView *view = layout.emplace(model).getElement(); @@ -68,8 +68,8 @@ KeyboardSettingsPage::KeyboardSettingsPage() if (wasAccepted) { auto newHotkey = dialog.data(); - getIApp()->getHotkeys()->hotkeys_.append(newHotkey); - getIApp()->getHotkeys()->save(); + getApp()->getHotkeys()->hotkeys_.append(newHotkey); + getApp()->getHotkeys()->save(); } }); @@ -87,7 +87,7 @@ KeyboardSettingsPage::KeyboardSettingsPage() if (reply == QMessageBox::Yes) { - getIApp()->getHotkeys()->resetToDefaults(); + getApp()->getHotkeys()->resetToDefaults(); } }); view->addCustomButton(resetEverything); diff --git a/src/widgets/settingspages/ModerationPage.cpp b/src/widgets/settingspages/ModerationPage.cpp index c00c03667..cb68e825c 100644 --- a/src/widgets/settingspages/ModerationPage.cpp +++ b/src/widgets/settingspages/ModerationPage.cpp @@ -58,7 +58,7 @@ QString formatSize(qint64 size) QString fetchLogDirectorySize() { QString logsDirectoryPath = getSettings()->logPath.getValue().isEmpty() - ? getIApp()->getPaths().messageLogDirectory + ? getApp()->getPaths().messageLogDirectory : getSettings()->logPath; auto logsSize = dirSize(logsDirectoryPath); @@ -83,20 +83,20 @@ ModerationPage::ModerationPage() auto logsPathLabel = logs.emplace(); // Logs (copied from LoggingMananger) - getSettings()->logPath.connect([logsPathLabel](const QString &logPath, - auto) mutable { - QString pathOriginal = - logPath.isEmpty() ? getIApp()->getPaths().messageLogDirectory - : logPath; + getSettings()->logPath.connect( + [logsPathLabel](const QString &logPath, auto) mutable { + QString pathOriginal = + logPath.isEmpty() ? getApp()->getPaths().messageLogDirectory + : logPath; - QString pathShortened = - "Logs are saved at " + - shortenString(pathOriginal, 50) + ""; + QString pathShortened = + "Logs are saved at " + + shortenString(pathOriginal, 50) + ""; - logsPathLabel->setText(pathShortened); - logsPathLabel->setToolTip(pathOriginal); - }); + logsPathLabel->setText(pathShortened); + logsPathLabel->setToolTip(pathOriginal); + }); logsPathLabel->setTextFormat(Qt::RichText); logsPathLabel->setTextInteractionFlags(Qt::TextBrowserInteraction | diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index c306e7176..5d354633b 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -97,7 +97,7 @@ NotificationPage::NotificationPage() EditableModelView *view = twitchChannels .emplace( - getIApp()->getNotifications()->createModel( + getApp()->getNotifications()->createModel( nullptr, Platform::Twitch)) .getElement(); view->setTitles({"Twitch channels"}); diff --git a/src/widgets/settingspages/PluginsPage.cpp b/src/widgets/settingspages/PluginsPage.cpp index 05c80a37c..5d87e3ff9 100644 --- a/src/widgets/settingspages/PluginsPage.cpp +++ b/src/widgets/settingspages/PluginsPage.cpp @@ -55,7 +55,7 @@ PluginsPage::PluginsPage() auto *description = new QLabel("You can load plugins by putting them into " + formatRichNamedLink( - "file:///" + getIApp()->getPaths().pluginsDirectory, + "file:///" + getApp()->getPaths().pluginsDirectory, "the Plugins directory") + ". Each one is a new directory."); description->setOpenExternalLinks(true); @@ -95,7 +95,7 @@ void PluginsPage::rebuildContent() this->scrollAreaWidget_.append(this->dataFrame_); auto layout = frame.setLayoutType(); layout->setParent(this->dataFrame_); - for (const auto &[id, plugin] : getIApp()->getPlugins()->plugins()) + for (const auto &[id, plugin] : getApp()->getPlugins()->plugins()) { auto groupHeaderText = QString("%1 (%2, from %3)") @@ -214,7 +214,7 @@ void PluginsPage::rebuildContent() val.push_back(name); } getSettings()->enabledPlugins.setValue(val); - getIApp()->getPlugins()->reload(name); + getApp()->getPlugins()->reload(name); this->rebuildContent(); }); pluginEntry->addRow(toggleButton); @@ -223,7 +223,7 @@ void PluginsPage::rebuildContent() auto *reloadButton = new QPushButton("Reload", this->dataFrame_); QObject::connect(reloadButton, &QPushButton::pressed, [name = id, this]() { - getIApp()->getPlugins()->reload(name); + getApp()->getPlugins()->reload(name); this->rebuildContent(); }); pluginEntry->addRow(reloadButton); diff --git a/src/widgets/settingspages/SettingsPage.cpp b/src/widgets/settingspages/SettingsPage.cpp index 4acf26791..6f2150f1c 100644 --- a/src/widgets/settingspages/SettingsPage.cpp +++ b/src/widgets/settingspages/SettingsPage.cpp @@ -103,7 +103,7 @@ QCheckBox *SettingsPage::createCheckBox( QObject::connect(checkbox, &QCheckBox::toggled, this, [&setting](bool state) { setting = state; - getIApp()->getWindows()->forceLayoutChannelViews(); + getApp()->getWindows()->forceLayoutChannelViews(); }); return checkbox; diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index 9d4ff5ed4..f3cfe6422 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -242,7 +242,7 @@ Split::Split(QWidget *parent) // update placeholder text on Twitch account change and channel change this->bSignals_.emplace_back( - getIApp()->getAccounts()->twitch.currentUserChanged.connect([this] { + getApp()->getAccounts()->twitch.currentUserChanged.connect([this] { this->updateInputPlaceholder(); })); this->signalHolder_.managedConnect(channelChanged, [this] { @@ -272,7 +272,7 @@ Split::Split(QWidget *parent) std::ignore = this->view_->openChannelIn.connect( [this](QString twitchChannel, FromTwitchLinkOpenChannelIn openIn) { ChannelPtr channel = - getIApp()->getTwitchAbstract()->getOrAddChannel(twitchChannel); + getApp()->getTwitchAbstract()->getOrAddChannel(twitchChannel); switch (openIn) { case FromTwitchLinkOpenChannelIn::Split: @@ -387,7 +387,7 @@ Split::Split(QWidget *parent) } auto channel = this->getChannel(); - auto *imageUploader = getIApp()->getImageUploader(); + auto *imageUploader = getApp()->getImageUploader(); auto [images, imageProcessError] = imageUploader->getImages(original); @@ -452,7 +452,7 @@ Split::Split(QWidget *parent) }, this->signalHolder_); this->addShortcuts(); - this->signalHolder_.managedConnect(getIApp()->getHotkeys()->onItemsUpdated, + this->signalHolder_.managedConnect(getApp()->getHotkeys()->onItemsUpdated, [this]() { this->clearShortcuts(); this->addShortcuts(); @@ -708,14 +708,14 @@ void Split::addShortcuts() QString requestedText = arguments.at(0).replace('\n', ' '); QString inputText = this->getInput().getInputText(); - QString message = getIApp()->getCommands()->execCustomCommand( + QString message = getApp()->getCommands()->execCustomCommand( requestedText.split(' '), Command{"(hotkey)", requestedText}, true, this->getChannel(), nullptr, { {"input.text", inputText}, }); - message = getIApp()->getCommands()->execCommand( + message = getApp()->getCommands()->execCommand( message, this->getChannel(), false); this->getChannel()->sendMessage(message); return ""; @@ -750,24 +750,24 @@ void Split::addShortcuts() if (mode == 0) { - getIApp()->getNotifications()->removeChannelNotification( + getApp()->getNotifications()->removeChannelNotification( this->getChannel()->getName(), Platform::Twitch); } else if (mode == 1) { - getIApp()->getNotifications()->addChannelNotification( + getApp()->getNotifications()->addChannelNotification( this->getChannel()->getName(), Platform::Twitch); } else { - getIApp()->getNotifications()->updateChannelNotification( + getApp()->getNotifications()->updateChannelNotification( this->getChannel()->getName(), Platform::Twitch); } return ""; }}, }; - this->shortcuts_ = getIApp()->getHotkeys()->shortcutsForCategory( + this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory( HotkeyCategory::Split, actions, this); } @@ -796,7 +796,7 @@ void Split::updateInputPlaceholder() return; } - auto user = getIApp()->getAccounts()->twitch.getCurrent(); + auto user = getApp()->getAccounts()->twitch.getCurrent(); QString placeholderText; if (user->isAnon()) @@ -806,7 +806,7 @@ void Split::updateInputPlaceholder() else { placeholderText = QString("Send message as %1...") - .arg(getIApp() + .arg(getApp() ->getAccounts() ->twitch.getCurrent() ->getUserName()); @@ -817,7 +817,7 @@ void Split::updateInputPlaceholder() void Split::joinChannelInNewTab(ChannelPtr channel) { - auto &nb = getIApp()->getWindows()->getMainWindow().getNotebook(); + auto &nb = getApp()->getWindows()->getMainWindow().getNotebook(); SplitContainer *container = nb.addPage(true); Split *split = new Split(container); @@ -907,7 +907,7 @@ void Split::setChannel(IndirectChannel newChannel) this->actionRequested.invoke(Action::RefreshTab); // Queue up save because: Split channel changed - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); } void Split::setModerationMode(bool value) @@ -1001,7 +1001,7 @@ void Split::keyReleaseEvent(QKeyEvent *event) void Split::resizeEvent(QResizeEvent *event) { // Queue up save because: Split resized - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); BaseWidget::resizeEvent(event); @@ -1122,8 +1122,7 @@ void Split::openInBrowser() void Split::openWhispersInBrowser() { - auto userName = - getIApp()->getAccounts()->twitch.getCurrent()->getUserName(); + auto userName = getApp()->getAccounts()->twitch.getCurrent()->getUserName(); QDesktopServices::openUrl("https://twitch.tv/popout/moderator/" + userName + "/whispers"); } @@ -1211,7 +1210,7 @@ void Split::showChatterList() auto *item = new QListWidgetItem(); item->setText(text); item->setFont( - getIApp()->getFonts()->getFont(FontStyle::ChatMedium, 1.0)); + getApp()->getFonts()->getFont(FontStyle::ChatMedium, 1.0)); return item; }; @@ -1261,7 +1260,7 @@ void Split::showChatterList() auto loadChatters = [=](auto modList, auto vipList, bool isBroadcaster) { getHelix()->getChatters( twitchChannel->roomId(), - getIApp()->getAccounts()->twitch.getCurrent()->getUserId(), 50000, + getApp()->getAccounts()->twitch.getCurrent()->getUserId(), 50000, [=](auto chatters) { auto broadcaster = channel->getName().toLower(); QStringList chatterList; @@ -1426,8 +1425,8 @@ void Split::showChatterList() }}, }; - getIApp()->getHotkeys()->shortcutsForCategory(HotkeyCategory::PopupWindow, - actions, chatterDock); + getApp()->getHotkeys()->shortcutsForCategory(HotkeyCategory::PopupWindow, + actions, chatterDock); dockVbox->addWidget(searchBar); dockVbox->addWidget(loadingLabel); @@ -1490,7 +1489,7 @@ void Split::showSearch(bool singleChannel) } // Pass every ChannelView for every Split across the app to the search popup - auto ¬ebook = getIApp()->getWindows()->getMainWindow().getNotebook(); + auto ¬ebook = getApp()->getWindows()->getMainWindow().getNotebook(); for (int i = 0; i < notebook.getPageCount(); ++i) { auto *container = dynamic_cast(notebook.getPageAt(i)); @@ -1509,7 +1508,7 @@ void Split::showSearch(bool singleChannel) void Split::reloadChannelAndSubscriberEmotes() { auto channel = this->getChannel(); - getIApp()->getAccounts()->twitch.getCurrent()->loadEmotes(channel); + getApp()->getAccounts()->twitch.getCurrent()->loadEmotes(channel); if (auto *twitchChannel = dynamic_cast(channel.get())) { diff --git a/src/widgets/splits/SplitContainer.cpp b/src/widgets/splits/SplitContainer.cpp index bee31cd11..57b129931 100644 --- a/src/widgets/splits/SplitContainer.cpp +++ b/src/widgets/splits/SplitContainer.cpp @@ -134,7 +134,7 @@ Split *SplitContainer::appendNewSplit(bool openChannelNameDialog) void SplitContainer::insertSplit(Split *split, InsertOptions &&options) { // Queue up save because: Split added - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); assertInGuiThread(); @@ -348,7 +348,7 @@ SplitContainer::Position SplitContainer::releaseSplit(Split *split) SplitContainer::Position SplitContainer::deleteSplit(Split *split) { // Queue up save because: Split removed - getIApp()->getWindows()->queueSave(); + getApp()->getWindows()->queueSave(); assertInGuiThread(); assert(split != nullptr); @@ -617,8 +617,8 @@ void SplitContainer::paintEvent(QPaintEvent * /*event*/) painter.setPen(this->theme->splits.header.text); - const auto font = getIApp()->getFonts()->getFont(FontStyle::ChatMedium, - this->scale()); + const auto font = + getApp()->getFonts()->getFont(FontStyle::ChatMedium, this->scale()); painter.setFont(font); QString text = "Click to add a split"; @@ -637,7 +637,7 @@ void SplitContainer::paintEvent(QPaintEvent * /*event*/) } else { - if (getIApp()->getThemes()->isLightTheme()) + if (getApp()->getThemes()->isLightTheme()) { painter.fillRect(rect(), QColor("#999")); } @@ -649,8 +649,8 @@ void SplitContainer::paintEvent(QPaintEvent * /*event*/) for (DropRect &dropRect : this->dropRects_) { - QColor border = getIApp()->getThemes()->splits.dropTargetRectBorder; - QColor background = getIApp()->getThemes()->splits.dropTargetRect; + QColor border = getApp()->getThemes()->splits.dropTargetRectBorder; + QColor background = getApp()->getThemes()->splits.dropTargetRect; if (!dropRect.rect.contains(this->mouseOverPoint_)) { @@ -782,7 +782,7 @@ void SplitContainer::applyFromDescriptor(const NodeDescriptor &rootNode) void SplitContainer::popup() { - Window &window = getIApp()->getWindows()->createWindow(WindowType::Popup); + Window &window = getApp()->getWindows()->createWindow(WindowType::Popup); auto *popupContainer = window.getNotebook().getOrAddSelectedPage(); QJsonObject encodedTab; @@ -1494,15 +1494,15 @@ void SplitContainer::DropOverlay::paintEvent(QPaintEvent * /*event*/) { if (!foundMover && rect.rect.contains(this->mouseOverPoint_)) { - painter.setBrush(getIApp()->getThemes()->splits.dropPreview); - painter.setPen(getIApp()->getThemes()->splits.dropPreviewBorder); + painter.setBrush(getApp()->getThemes()->splits.dropPreview); + painter.setPen(getApp()->getThemes()->splits.dropPreviewBorder); foundMover = true; } else { painter.setBrush(QColor(0, 0, 0, 0)); painter.setPen(QColor(0, 0, 0, 0)); - // painter.setPen(getIApp()->getThemes()->splits.dropPreviewBorder); + // painter.setPen(getApp()->getThemes()->splits.dropPreviewBorder); } painter.drawRect(rect.rect); @@ -1584,10 +1584,10 @@ SplitContainer::ResizeHandle::ResizeHandle(SplitContainer *_parent) void SplitContainer::ResizeHandle::paintEvent(QPaintEvent * /*event*/) { QPainter painter(this); - painter.setPen(QPen(getIApp()->getThemes()->splits.resizeHandle, 2)); + painter.setPen(QPen(getApp()->getThemes()->splits.resizeHandle, 2)); painter.fillRect(this->rect(), - getIApp()->getThemes()->splits.resizeHandleBackground); + getApp()->getThemes()->splits.resizeHandleBackground); if (this->vertical_) { diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index 35fb1dbde..4d7842125 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -140,7 +140,7 @@ auto formatTooltip(const TwitchChannel::StreamStatus &s, QString thumbnail) }(); auto extraStreamData = [&s]() -> QString { - if (getIApp()->getStreamerMode()->isEnabled() && + if (getApp()->getStreamerMode()->isEnabled() && getSettings()->streamerModeHideViewerCountAndDuration) { return QStringLiteral( @@ -246,7 +246,7 @@ SplitHeader::SplitHeader(Split *split) }); this->bSignals_.emplace_back( - getIApp()->getAccounts()->twitch.currentUserChanged.connect([this] { + getApp()->getAccounts()->twitch.currentUserChanged.connect([this] { this->updateIcons(); })); @@ -311,7 +311,7 @@ void SplitHeader::initializeLayout() case Qt::LeftButton: if (getSettings()->moderationActions.empty()) { - getIApp()->getWindows()->showSettingsDialog( + getApp()->getWindows()->showSettingsDialog( this, SettingsDialogPreference:: ModerationActions); this->split_->setModerationMode(true); @@ -329,7 +329,7 @@ void SplitHeader::initializeLayout() case Qt::RightButton: case Qt::MiddleButton: - getIApp()->getWindows()->showSettingsDialog( + getApp()->getWindows()->showSettingsDialog( this, SettingsDialogPreference::ModerationActions); break; @@ -379,7 +379,7 @@ void SplitHeader::initializeLayout() std::unique_ptr SplitHeader::createMainMenu() { // top level menu - const auto &h = getIApp()->getHotkeys(); + const auto &h = getApp()->getHotkeys(); auto menu = std::make_unique(); menu->addAction( "Change channel", this->split_, &Split::changeChannel, @@ -552,11 +552,11 @@ std::unique_ptr SplitHeader::createMainMenu() action->setShortcut(notifySeq); QObject::connect(moreMenu, &QMenu::aboutToShow, this, [action, this]() { - action->setChecked(getIApp()->getNotifications()->isChannelNotified( + action->setChecked(getApp()->getNotifications()->isChannelNotified( this->split_->getChannel()->getName(), Platform::Twitch)); }); QObject::connect(action, &QAction::triggered, this, [this]() { - getIApp()->getNotifications()->updateChannelNotification( + getApp()->getNotifications()->updateChannelNotification( this->split_->getChannel()->getName(), Platform::Twitch); }); @@ -1078,7 +1078,7 @@ void SplitHeader::reloadSubscriberEmotes() this->lastReloadedSubEmotes_ = now; auto channel = this->split_->getChannel(); - getIApp()->getAccounts()->twitch.getCurrent()->loadEmotes(channel); + getApp()->getAccounts()->twitch.getCurrent()->loadEmotes(channel); } void SplitHeader::reconnect() diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 17eb40418..85c421be9 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -68,7 +68,7 @@ SplitInput::SplitInput(QWidget *parent, Split *_chatWidget, this->hideCompletionPopup(); }); this->scaleChangedEvent(this->scale()); - this->signalHolder_.managedConnect(getIApp()->getHotkeys()->onItemsUpdated, + this->signalHolder_.managedConnect(getApp()->getHotkeys()->onItemsUpdated, [this]() { this->clearShortcuts(); this->addShortcuts(); @@ -77,7 +77,7 @@ SplitInput::SplitInput(QWidget *parent, Split *_chatWidget, void SplitInput::initLayout() { - auto *app = getIApp(); + auto *app = getApp(); LayoutCreator layoutCreator(this); auto layout = @@ -219,7 +219,7 @@ void SplitInput::initLayout() void SplitInput::scaleChangedEvent(float scale) { - auto *app = getIApp(); + auto *app = getApp(); // update the icon size of the buttons this->updateEmoteButton(); this->updateCancelReplyButton(); @@ -352,7 +352,7 @@ QString SplitInput::handleSendMessage(const std::vector &arguments) message = message.replace('\n', ' '); QString sendMessage = - getIApp()->getCommands()->execCommand(message, c, false); + getApp()->getCommands()->execCommand(message, c, false); c->sendMessage(sendMessage); @@ -388,7 +388,7 @@ QString SplitInput::handleSendMessage(const std::vector &arguments) message = message.replace('\n', ' '); QString sendMessage = - getIApp()->getCommands()->execCommand(message, c, false); + getApp()->getCommands()->execCommand(message, c, false); // Reply within TwitchChannel tc->sendReply(sendMessage, this->replyTarget_->id); @@ -413,7 +413,7 @@ QString SplitInput::handleSendMessage(const std::vector &arguments) message = message.replace('\n', ' '); QString sendMessage = - getIApp()->getCommands()->execCommand(message, c, false); + getApp()->getCommands()->execCommand(message, c, false); // Reply within TwitchChannel tc->sendReply(sendMessage, this->replyTarget_->id); @@ -698,7 +698,7 @@ void SplitInput::addShortcuts() }}, }; - this->shortcuts_ = getIApp()->getHotkeys()->shortcutsForCategory( + this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory( HotkeyCategory::SplitInput, actions, this->parentWidget()); } @@ -983,7 +983,7 @@ void SplitInput::setInputText(const QString &newInputText) void SplitInput::editTextChanged() { - auto *app = getIApp(); + auto *app = getApp(); // set textLengthLabel value QString text = this->ui_.textEdit->toPlainText(); diff --git a/src/widgets/splits/SplitOverlay.cpp b/src/widgets/splits/SplitOverlay.cpp index e6721d654..f9be1af93 100644 --- a/src/widgets/splits/SplitOverlay.cpp +++ b/src/widgets/splits/SplitOverlay.cpp @@ -268,8 +268,8 @@ void SplitOverlay::paintEvent(QPaintEvent *event) { rect.setRight(rect.right() - 1); rect.setBottom(rect.bottom() - 1); - painter.setPen(getIApp()->getThemes()->splits.dropPreviewBorder); - painter.setBrush(getIApp()->getThemes()->splits.dropPreview); + painter.setPen(getApp()->getThemes()->splits.dropPreviewBorder); + painter.setBrush(getApp()->getThemes()->splits.dropPreview); painter.drawRect(rect); } } diff --git a/tests/src/Commands.cpp b/tests/src/Commands.cpp index f180a7180..2a4d259aa 100644 --- a/tests/src/Commands.cpp +++ b/tests/src/Commands.cpp @@ -27,6 +27,7 @@ class MockApplication : mock::EmptyApplication public: MockApplication() : settings(this->settingsDir.filePath("settings.json")) + , commands(this->paths_) { } @@ -833,8 +834,6 @@ TEST(Commands, E2E) ::testing::InSequence seq; MockApplication app; - app.commands.initialize(*getSettings(), getIApp()->getPaths()); - QJsonObject pajlada; pajlada["id"] = "11148817"; pajlada["login"] = "pajlada"; @@ -879,10 +878,10 @@ TEST(Commands, E2E) auto account = std::make_shared( testaccount420["login"].toString(), "token", "oauthclient", testaccount420["id"].toString()); - getIApp()->getAccounts()->twitch.accounts.append(account); - getIApp()->getAccounts()->twitch.currentUsername = + getApp()->getAccounts()->twitch.accounts.append(account); + getApp()->getAccounts()->twitch.currentUsername = testaccount420["login"].toString(); - getIApp()->getAccounts()->twitch.load(); + getApp()->getAccounts()->twitch.load(); // Simple single-channel ban EXPECT_CALL(mockHelix, fetchUsers(QStringList{"11148817"}, @@ -901,7 +900,7 @@ TEST(Commands, E2E) QString(""), _, _)) .Times(1); - getIApp()->getCommands()->execCommand("/ban forsen", channel, false); + getApp()->getCommands()->execCommand("/ban forsen", channel, false); // Multi-channel ban EXPECT_CALL(mockHelix, fetchUsers(QStringList{"11148817"}, @@ -937,7 +936,7 @@ TEST(Commands, E2E) std::optional{}, QString(""), _, _)) .Times(1); - getIApp()->getCommands()->execCommand( + getApp()->getCommands()->execCommand( "/ban --channel id:11148817 --channel testaccount_420 forsen", channel, false); @@ -948,7 +947,7 @@ TEST(Commands, E2E) QString(""), _, _)) .Times(1); - getIApp()->getCommands()->execCommand("/ban id:22484632", channel, false); + getApp()->getCommands()->execCommand("/ban id:22484632", channel, false); // ID-based redirected ban EXPECT_CALL(mockHelix, @@ -957,7 +956,7 @@ TEST(Commands, E2E) QString(""), _, _)) .Times(1); - getIApp()->getCommands()->execCommand( + getApp()->getCommands()->execCommand( "/ban --channel id:117166826 id:22484632", channel, false); // name-based redirected ban @@ -976,7 +975,7 @@ TEST(Commands, E2E) QString(""), _, _)) .Times(1); - getIApp()->getCommands()->execCommand( + getApp()->getCommands()->execCommand( "/ban --channel testaccount_420 id:22484632", channel, false); // Multi-channel timeout @@ -1013,7 +1012,7 @@ TEST(Commands, E2E) std::optional{600}, QString(""), _, _)) .Times(1); - getIApp()->getCommands()->execCommand( + getApp()->getCommands()->execCommand( "/timeout --channel id:11148817 --channel testaccount_420 forsen", channel, false); @@ -1049,7 +1048,7 @@ TEST(Commands, E2E) forsen["id"].toString(), _, _)) .Times(1); - getIApp()->getCommands()->execCommand( + getApp()->getCommands()->execCommand( "/unban --channel id:11148817 --channel testaccount_420 forsen", channel, false); } diff --git a/tests/src/Filters.cpp b/tests/src/Filters.cpp index 89c0a510f..cb8c07c74 100644 --- a/tests/src/Filters.cpp +++ b/tests/src/Filters.cpp @@ -29,6 +29,12 @@ namespace { class MockApplication : mock::EmptyApplication { public: + MockApplication() + : settings(this->settingsDir.filePath("settings.json")) + , highlights(this->settings, &this->accounts) + { + } + IEmotes *getEmotes() override { return &this->emotes; @@ -69,6 +75,7 @@ public: return &this->highlights; } + Settings settings; AccountController accounts; Emotes emotes; mock::UserDataController userData; diff --git a/tests/src/HighlightController.cpp b/tests/src/HighlightController.cpp index 090acf37b..76f92db18 100644 --- a/tests/src/HighlightController.cpp +++ b/tests/src/HighlightController.cpp @@ -8,7 +8,6 @@ #include "mocks/UserData.hpp" #include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchBadge.hpp" // for Badge -#include "singletons/Paths.hpp" #include "singletons/Settings.hpp" #include "Test.hpp" @@ -23,9 +22,16 @@ using ::testing::Exactly; namespace { -class MockApplication : mock::EmptyApplication +class MockApplication : public mock::EmptyApplication { public: + MockApplication(const QString &settingsBody) + : mock::EmptyApplication(settingsBody) + , settings(this->settingsDir.path()) + , highlights(this->settings, &this->accounts) + { + } + AccountController *getAccounts() override { return &this->accounts; @@ -41,10 +47,10 @@ public: return &this->userData; } + Settings settings; AccountController accounts; HighlightController highlights; mock::UserDataController userData; - // TODO: Figure this out }; } // namespace @@ -180,13 +186,7 @@ protected: void configure(const QString &settings, bool isAnon) { // Write default settings to the mock settings json file - this->settingsDir_ = std::make_unique(); - - QFile settingsFile(this->settingsDir_->filePath("settings.json")); - ASSERT_TRUE(settingsFile.open(QIODevice::WriteOnly | QIODevice::Text)); - ASSERT_GT(settingsFile.write(settings.toUtf8()), 0); - ASSERT_TRUE(settingsFile.flush()); - settingsFile.close(); + this->mockApplication = std::make_unique(settings); this->mockHelix = new mock::Helix; @@ -195,24 +195,17 @@ protected: EXPECT_CALL(*this->mockHelix, loadBlocks).Times(Exactly(1)); EXPECT_CALL(*this->mockHelix, update).Times(Exactly(isAnon ? 0 : 1)); - this->mockApplication = std::make_unique(); - this->settings = std::make_unique(this->settingsDir_->path()); - this->paths = std::make_unique(); - - this->controller = std::make_unique(); - - this->mockApplication->accounts.initialize(*this->settings, - *this->paths); - this->controller->initialize(*this->settings, *this->paths); + this->mockApplication->accounts.load(); } void runTests(const std::vector &tests) { for (const auto &[input, expected] : tests) { - auto [isMatch, matchResult] = this->controller->check( - input.args, input.badges, input.senderName, - input.originalMessage, input.flags); + auto [isMatch, matchResult] = + this->mockApplication->getHighlights()->check( + input.args, input.badges, input.senderName, + input.originalMessage, input.flags); EXPECT_EQ(isMatch, expected.state) << input.senderName << ": " << input.originalMessage; @@ -224,23 +217,11 @@ protected: void TearDown() override { this->mockApplication.reset(); - this->settings.reset(); - this->paths.reset(); - - this->controller.reset(); - - this->settingsDir_.reset(); delete this->mockHelix; } - std::unique_ptr settingsDir_; - std::unique_ptr mockApplication; - std::unique_ptr settings; - std::unique_ptr paths; - - std::unique_ptr controller; mock::Helix *mockHelix; }; diff --git a/tests/src/InputCompletion.cpp b/tests/src/InputCompletion.cpp index 22c42b31c..2b987a5e1 100644 --- a/tests/src/InputCompletion.cpp +++ b/tests/src/InputCompletion.cpp @@ -129,9 +129,7 @@ protected: this->settings = std::make_unique(this->settingsDir_->path()); this->paths = std::make_unique(); - this->mockApplication->accounts.initialize(*this->settings, - *this->paths); - this->mockApplication->emotes.initialize(*this->settings, *this->paths); + this->mockApplication->accounts.load(); this->channelPtr = std::make_shared("icelys"); diff --git a/tests/src/MessageLayout.cpp b/tests/src/MessageLayout.cpp index 8533b87b8..55db48c3b 100644 --- a/tests/src/MessageLayout.cpp +++ b/tests/src/MessageLayout.cpp @@ -4,7 +4,7 @@ #include "controllers/accounts/AccountController.hpp" #include "messages/MessageBuilder.hpp" #include "messages/MessageElement.hpp" -#include "mocks/EmptyApplication.hpp" +#include "mocks/BaseApplication.hpp" #include "singletons/Emotes.hpp" #include "singletons/Fonts.hpp" #include "singletons/Settings.hpp" @@ -21,15 +21,16 @@ using namespace chatterino; namespace { -class MockApplication : mock::EmptyApplication +class MockApplication : mock::BaseApplication { public: MockApplication() - : settings(this->settingsDir.filePath("settings.json")) + : theme(this->paths_) , fonts(this->settings) , windowManager(this->paths_) { } + Theme *getThemes() override { return &this->theme; @@ -45,7 +46,12 @@ public: return &this->windowManager; } - Settings settings; + AccountController *getAccounts() override + { + return &this->accounts; + } + + AccountController accounts; Theme theme; Fonts fonts; WindowManager windowManager; diff --git a/tests/src/NotebookTab.cpp b/tests/src/NotebookTab.cpp index 36133b648..2c6287ba2 100644 --- a/tests/src/NotebookTab.cpp +++ b/tests/src/NotebookTab.cpp @@ -23,6 +23,7 @@ class MockApplication : mock::EmptyApplication public: MockApplication() : settings(this->settingsDir.filePath("settings.json")) + , theme(this->paths_) , fonts(this->settings) { } diff --git a/tests/src/Scrollbar.cpp b/tests/src/Scrollbar.cpp index 98ca9a640..ee143351e 100644 --- a/tests/src/Scrollbar.cpp +++ b/tests/src/Scrollbar.cpp @@ -1,7 +1,7 @@ #include "widgets/Scrollbar.hpp" #include "Application.hpp" -#include "mocks/EmptyApplication.hpp" +#include "mocks/BaseApplication.hpp" #include "singletons/Fonts.hpp" #include "singletons/Settings.hpp" #include "singletons/Theme.hpp" @@ -17,11 +17,11 @@ using namespace chatterino; namespace { -class MockApplication : mock::EmptyApplication +class MockApplication : mock::BaseApplication { public: MockApplication() - : settings(this->settingsDir.filePath("settings.json")) + : theme(this->paths_) , fonts(this->settings) , windowManager(this->paths_) { @@ -41,7 +41,6 @@ public: return &this->windowManager; } - Settings settings; Theme theme; Fonts fonts; WindowManager windowManager; diff --git a/tests/src/SplitInput.cpp b/tests/src/SplitInput.cpp index d84da8118..d09739dcf 100644 --- a/tests/src/SplitInput.cpp +++ b/tests/src/SplitInput.cpp @@ -5,7 +5,7 @@ #include "controllers/commands/Command.hpp" #include "controllers/commands/CommandController.hpp" #include "controllers/hotkeys/HotkeyController.hpp" -#include "mocks/EmptyApplication.hpp" +#include "mocks/BaseApplication.hpp" #include "singletons/Emotes.hpp" #include "singletons/Fonts.hpp" #include "singletons/Paths.hpp" @@ -24,13 +24,14 @@ using ::testing::Exactly; namespace { -class MockApplication : mock::EmptyApplication +class MockApplication : public mock::BaseApplication { public: MockApplication() - : settings(this->settingsDir.filePath("settings.json")) + : theme(this->paths_) , fonts(this->settings) - , windowManager(this->paths) + , windowManager(this->paths_) + , commands(this->paths_) { } Theme *getThemes() override @@ -68,11 +69,9 @@ public: return &this->emotes; } - Settings settings; Theme theme; HotkeyController hotkeys; Fonts fonts; - Paths paths; WindowManager windowManager; AccountController accounts; CommandController commands; diff --git a/tests/src/TwitchMessageBuilder.cpp b/tests/src/TwitchMessageBuilder.cpp index d9d1d5a62..7c29a4ae4 100644 --- a/tests/src/TwitchMessageBuilder.cpp +++ b/tests/src/TwitchMessageBuilder.cpp @@ -32,6 +32,12 @@ namespace { class MockApplication : mock::EmptyApplication { public: + MockApplication() + : settings(this->settingsDir.filePath("settings.json")) + , highlights(this->settings, &this->accounts) + { + } + IEmotes *getEmotes() override { return &this->emotes; @@ -92,6 +98,7 @@ public: return &this->streamerMode; } + Settings settings; AccountController accounts; Emotes emotes; mock::UserDataController userData; From 847e4f0932c4de2557522feb2f551127d8859be4 Mon Sep 17 00:00:00 2001 From: nerix Date: Sun, 21 Jul 2024 16:00:12 +0200 Subject: [PATCH 21/63] fix: count parentheses in links (#5515) --- CHANGELOG.md | 2 +- src/common/LinkParser.cpp | 45 ++++++++++++++++++++++++++++++++++++--- src/common/LinkParser.hpp | 5 +++-- tests/src/LinkParser.cpp | 19 ++++++++++++----- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14925cab2..131f20168 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ - Minor: Introduce HTTP API for plugins. (#5383, #5492, #5494) - Minor: Support more Firefox variants for incognito link opening. (#5503) - Minor: Replying to a message will now display the message being replied to. (#4350, #5519) -- Minor: Links can now have prefixes and suffixes such as parentheses. (#5486) +- Minor: Links can now have prefixes and suffixes such as parentheses. (#5486, #5515) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) - Bugfix: Fixed restricted users usernames not being clickable. (#5405) diff --git a/src/common/LinkParser.cpp b/src/common/LinkParser.cpp index eed4f97c1..6858ff902 100644 --- a/src/common/LinkParser.cpp +++ b/src/common/LinkParser.cpp @@ -118,10 +118,12 @@ bool startsWithPort(QStringView string) /// As per https://github.github.com/gfm/#autolinks-extension-: /// /// '<', '*', '_', '~', and '(' are ignored at the beginning -/// '>', '?', '!', '.', ',', ':', '*', '~', and ')' are ignored at the end +/// '>', '?', '!', '.', ',', ':', '*', '~', and ')' are ignored at the end. /// -/// A difference to GFM is that the source isn't scanned for parentheses and '_' -/// isn't a valid suffix. +/// A difference to GFM is that '_' isn't a valid suffix. +/// +/// This might remove more than desired (e.g. "(a.com/(foo))" -> "a.com/(foo"). +/// Parentheses are counted after recognizing a valid IP/host. void strip(QStringView &source) { while (!source.isEmpty()) @@ -259,6 +261,43 @@ std::optional parse(const QString &source) noexcept if ((nDots == 3 && isValidIpv4(host)) || isValidTld(host.mid(lastDotPos + 1))) { + // scan for parentheses (only if there were characters excluded) + if (link.end() != source.end() && !rest.empty()) + { + size_t nestingLevel = 0; + // position after the last closing brace (i.e. the minimum characters to include) + const auto *lastClose = link.end(); + + // scan source from rest until the end: + // lastClose + // v + // (example.com/foo/bar/#baz_(qox)), + // ▏╌╌rest (before)╌ ▏ + // ▏╌╌╌╌╌╌╌link (before)╌╌╌╌╌╌╌ ▏ + // ▏╌╌rest (after)╌╌╌ ▏ + // ▏╌╌╌╌╌╌╌link (after)╌╌╌╌╌╌╌╌╌ ▏ + // ▏╌╌╌╌╌╌╌╌╌╌╌╌╌source╌╌╌╌╌╌╌╌╌╌╌╌ ▏ + // ▏╌╌╌╌╌╌╌search╌╌╌╌╌╌ ▏ + for (const auto *it = rest.begin(); it < source.end(); it++) + { + if (it->unicode() == u'(') + { + nestingLevel++; + continue; + } + + if (nestingLevel != 0 && it->unicode() == u')') + { + nestingLevel--; + if (nestingLevel == 0) + { + lastClose = it + 1; + } + } + } + link = QStringView{link.begin(), std::max(link.end(), lastClose)}; + rest = QStringView{rest.begin(), std::max(rest.end(), lastClose)}; + } result = Parsed{ .protocol = protocol, .host = host, diff --git a/src/common/LinkParser.hpp b/src/common/LinkParser.hpp index 12976b25d..151fb0834 100644 --- a/src/common/LinkParser.hpp +++ b/src/common/LinkParser.hpp @@ -16,8 +16,9 @@ namespace chatterino::linkparser { /// /// Prefixes and suffixes are almost identical to the ones in GitHub Flavored /// Markdown (GFM - https://github.github.com/gfm/#autolinks-extension-). -/// The main differences are that '_' isn't a valid suffix and parentheses -/// aren't counted (e.g. "(a.com/(foo)! would result in "a.com/(foo"). +/// The main difference is that '_' isn't a valid suffix. +/// Parentheses are counted inside the @a rest: parsing "(a.com/(foo))" would +/// result in the link "a.com/(foo)". /// Matching is done case insensitive (e.g. "HTTp://a.com" would be valid). /// /// A @a protocol can either be empty, "http://", or "https://". diff --git a/tests/src/LinkParser.cpp b/tests/src/LinkParser.cpp index 72748d689..67fdff0b0 100644 --- a/tests/src/LinkParser.cpp +++ b/tests/src/LinkParser.cpp @@ -23,8 +23,8 @@ struct Case { "", "_", "__", "<", "<<", "<_<", "(((", "<*_~(", "**", "~~", }; QStringList suffixes{ - "", ">", "?", "!", ".", ",", ":", - "*", "~", ">>", "?!.", "~~,*!?", "**", + "", ">", "?", "!", ".", ",", ":", "*", "~", + ">>", "?!.", "~~,*!?", "**", ").", "),", ",)", ")),.", ")?", }; for (const auto &prefix : prefixes) @@ -89,14 +89,21 @@ TEST(LinkParser, parseDomainLinks) {"", "https.cat"}, {"", "httpsd.cat"}, {"", "http.cat", "/200"}, - {"", "http.cat", "/200("}, - {"", "a.com", "?("}, - {"", "a.com", "#("}, + {"", "http.cat", "/200()"}, + {"", "a.com", "?()"}, + {"", "a.com", "#()"}, {"", "a.com", "/__my_user__"}, {"", "a.b.c.-._.1.com", ""}, {"", "0123456789.com", ""}, {"", "ABCDEFGHIJKLMNOPQRSTUVWXYZ.com", ""}, {"", "abcdefghijklmnopqrstuvwxyz.com", ""}, + {"", "example.com", "/foo(bar)"}, + {"", "example.com", "/foo((bar))"}, + {"", "example.com", "/(f)(o)(o)(b)(a)r"}, + {"", "example.com", "/foobar()()"}, + {"", "example.com", "/foobar()(())baz"}, + {"", "example.com", "/(foo)"}, + {"", "example.com", "/()"}, // non-ASCII characters are allowed {"", u"köln.de"_s, ""}, {"", u"ü.com"_s, ""}, @@ -246,6 +253,8 @@ TEST(LinkParser, doesntParseInvalidLinks) "@@@.com", "%%%.com", "*.com", + "example.com(foo)", + "example.com()", }; for (const auto &input : inputs) From 3133293700271f17a7383aa655d00788dcdeeebc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 14:31:35 +0000 Subject: [PATCH 22/63] chore(deps): bump lib/expected-lite from `182165b` to `5d3c8d3` (#5484) Bumps [lib/expected-lite](https://github.com/martinmoene/expected-lite) from `182165b` to `5d3c8d3`. - [Release notes](https://github.com/martinmoene/expected-lite/releases) - [Commits](https://github.com/martinmoene/expected-lite/compare/182165b584dad130afaf4bcd25b8629799baea38...5d3c8d38fb2bc0ccfc410f9d20033701057c400b) --- updated-dependencies: - dependency-name: lib/expected-lite dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: pajlada --- lib/expected-lite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/expected-lite b/lib/expected-lite index 182165b58..5d3c8d38f 160000 --- a/lib/expected-lite +++ b/lib/expected-lite @@ -1 +1 @@ -Subproject commit 182165b584dad130afaf4bcd25b8629799baea38 +Subproject commit 5d3c8d38fb2bc0ccfc410f9d20033701057c400b From a0b70b8c5e1ee60f2d746ca5234dffd1e2b8a4c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 15:39:59 +0000 Subject: [PATCH 23/63] chore(deps): bump lib/WinToast from `821c481` to `a78ce46` (#5331) Bumps [lib/WinToast](https://github.com/mohabouje/WinToast) from `821c481` to `a78ce46`. - [Release notes](https://github.com/mohabouje/WinToast/releases) - [Commits](https://github.com/mohabouje/WinToast/compare/821c4818ade1aa4da56ac753285c159ce26fd597...a78ce469b456c06103b3b30d4bd37e7bb80da30c) --- updated-dependencies: - dependency-name: lib/WinToast dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: pajlada --- lib/WinToast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/WinToast b/lib/WinToast index 821c4818a..a78ce469b 160000 --- a/lib/WinToast +++ b/lib/WinToast @@ -1 +1 @@ -Subproject commit 821c4818ade1aa4da56ac753285c159ce26fd597 +Subproject commit a78ce469b456c06103b3b30d4bd37e7bb80da30c From a2cbe6377dabd59c025d5bdf46c956a334b274a6 Mon Sep 17 00:00:00 2001 From: nerix Date: Tue, 23 Jul 2024 23:38:17 +0200 Subject: [PATCH 24/63] chore: improve link parser and its tests a bit (#5522) --- src/common/LinkParser.cpp | 34 ++++++++++++++++++---------------- tests/src/LinkParser.cpp | 11 +++++++++++ 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/common/LinkParser.cpp b/src/common/LinkParser.cpp index 6858ff902..c6ec1ab2d 100644 --- a/src/common/LinkParser.cpp +++ b/src/common/LinkParser.cpp @@ -1,17 +1,24 @@ #define QT_NO_CAST_FROM_ASCII // avoids unexpected implicit casts #include "common/LinkParser.hpp" +#include "util/QCompareCaseInsensitive.hpp" + #include -#include #include #include #include +#include + namespace { -QSet &tlds() +using namespace chatterino; + +using TldSet = std::set; + +TldSet &tlds() { - static QSet tlds = [] { + static TldSet tlds = [] { QFile file(QStringLiteral(":/tlds.txt")); file.open(QFile::ReadOnly); QTextStream stream(&file); @@ -21,19 +28,12 @@ QSet &tlds() #else stream.setCodec("UTF-8"); #endif - int safetyMax = 20000; - QSet set; + TldSet set; while (!stream.atEnd()) { - auto line = stream.readLine(); - set.insert(line); - - if (safetyMax-- == 0) - { - break; - } + set.emplace(stream.readLine()); } return set; @@ -43,7 +43,7 @@ QSet &tlds() bool isValidTld(QStringView tld) { - return tlds().contains(tld.toString().toLower()); + return tlds().contains(tld); } bool isValidIpv4(QStringView host) @@ -166,6 +166,8 @@ namespace chatterino::linkparser { std::optional parse(const QString &source) noexcept { + using SizeType = QString::size_type; + std::optional result; // This is not implemented with a regex to increase performance. @@ -201,11 +203,11 @@ std::optional parse(const QString &source) noexcept QStringView host = remaining; QStringView rest; bool lastWasDot = true; - int lastDotPos = -1; - int nDots = 0; + SizeType lastDotPos = -1; + SizeType nDots = 0; // Extract the host - for (int i = 0; i < remaining.size(); i++) + for (SizeType i = 0; i < remaining.size(); i++) { char16_t currentChar = remaining[i].unicode(); if (currentChar == u'.') diff --git a/tests/src/LinkParser.cpp b/tests/src/LinkParser.cpp index 67fdff0b0..32a5ad340 100644 --- a/tests/src/LinkParser.cpp +++ b/tests/src/LinkParser.cpp @@ -72,6 +72,8 @@ TEST(LinkParser, parseDomainLinks) {"", "chatterino.com", ":80"}, {"", "wiki.chatterino.com", ":80"}, {"", "wiki.chatterino.com", ":80/foo/bar"}, + {"", "wiki.chatterino.com", ":80?foo"}, + {"", "wiki.chatterino.com", ":80#foo"}, {"", "wiki.chatterino.com", "/:80?foo/bar"}, {"", "wiki.chatterino.com", "/127.0.0.1"}, {"", "a.b.c.chatterino.com"}, @@ -156,6 +158,7 @@ TEST(LinkParser, parseIpv4Links) TEST(LinkParser, doesntParseInvalidIpv4Links) { const QStringList inputs = { + "196.162.a.1", // U+0660 - in category "number digits" QStringLiteral("٠.٠.٠.٠"), "https://127.0.0.", @@ -186,6 +189,10 @@ TEST(LinkParser, doesntParseInvalidIpv4Links) "196.162.8.1(", "196.162.8.1(!", "127.1.1;.com", + "127.0.-.1", + "127...", + "1.1.1.", + "1.1.1.:80", }; for (const auto &input : inputs) @@ -223,6 +230,10 @@ TEST(LinkParser, doesntParseInvalidLinks) "https://pn./", "pn./", "pn.", + "pn.:80", + "pn./foo", + "pn.#foo", + "pn.?foo", "http/chatterino.com", "http/wiki.chatterino.com", "http:cat.com", From ff7cc09f8b6acf6156a9a3f925520380d8a15cf7 Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 27 Jul 2024 13:19:26 +0200 Subject: [PATCH 25/63] chore: cleanup, document, and test some RTL code (#5473) --- CHANGELOG.md | 1 + src/messages/Image.cpp | 35 +-- src/messages/MessageElement.cpp | 2 - src/messages/layouts/MessageLayout.hpp | 4 +- .../layouts/MessageLayoutContainer.cpp | 132 +++++----- .../layouts/MessageLayoutContainer.hpp | 105 ++++++-- tests/CMakeLists.txt | 1 + tests/src/MessageLayoutContainer.cpp | 237 ++++++++++++++++++ 8 files changed, 413 insertions(+), 104 deletions(-) create mode 100644 tests/src/MessageLayoutContainer.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 131f20168..714681d09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ - Dev: Deprecate Qt 5.12. (#5396) - Dev: The running Qt version is now shown in the about page if it differs from the compiled version. (#5501) - Dev: `FlagsEnum` is now `constexpr`. (#5510) +- Dev: Documented and added tests to RTL handling. (#5473) ## 2.5.1 diff --git a/src/messages/Image.cpp b/src/messages/Image.cpp index f74bba164..59be19957 100644 --- a/src/messages/Image.cpp +++ b/src/messages/Image.cpp @@ -53,24 +53,27 @@ Frames::Frames(QList &&frames) getApp()->getEmotes()->getGIFTimer().signal.connect([this] { this->advance(); }); + + auto totalLength = + std::accumulate(this->items_.begin(), this->items_.end(), 0UL, + [](auto init, auto &&frame) { + return init + frame.duration; + }); + + if (totalLength == 0) + { + this->durationOffset_ = 0; + } + else + { + this->durationOffset_ = std::min( + int(getApp()->getEmotes()->getGIFTimer().position() % + totalLength), + 60000); + } + this->processOffset(); } - auto totalLength = std::accumulate(this->items_.begin(), this->items_.end(), - 0UL, [](auto init, auto &&frame) { - return init + frame.duration; - }); - - if (totalLength == 0) - { - this->durationOffset_ = 0; - } - else - { - this->durationOffset_ = std::min( - int(getApp()->getEmotes()->getGIFTimer().position() % totalLength), - 60000); - } - this->processOffset(); DebugCount::increase("image bytes", this->memoryUsage()); DebugCount::increase("image bytes (ever loaded)", this->memoryUsage()); } diff --git a/src/messages/MessageElement.cpp b/src/messages/MessageElement.cpp index 8d994ef22..a8beed9c0 100644 --- a/src/messages/MessageElement.cpp +++ b/src/messages/MessageElement.cpp @@ -593,8 +593,6 @@ void SingleLineTextElement::addToContainer(MessageLayoutContainer &container, // once we encounter an emote or reach the end of the message text. */ QString currentText; - container.first = FirstWord::Neutral; - bool firstIteration = true; for (Word &word : this->words_) { diff --git a/src/messages/layouts/MessageLayout.hpp b/src/messages/layouts/MessageLayout.hpp index 01958ddf2..12a8b153a 100644 --- a/src/messages/layouts/MessageLayout.hpp +++ b/src/messages/layouts/MessageLayout.hpp @@ -119,9 +119,9 @@ private: QPixmap *ensureBuffer(QPainter &painter, int width); // variables - MessagePtr message_; + const MessagePtr message_; MessageLayoutContainer container_; - std::unique_ptr buffer_{}; + std::unique_ptr buffer_; bool bufferValid_ = false; int height_ = 0; diff --git a/src/messages/layouts/MessageLayoutContainer.cpp b/src/messages/layouts/MessageLayoutContainer.cpp index a4abee58d..3c2bd122d 100644 --- a/src/messages/layouts/MessageLayoutContainer.cpp +++ b/src/messages/layouts/MessageLayoutContainer.cpp @@ -1,4 +1,4 @@ -#include "MessageLayoutContainer.hpp" +#include "messages/layouts/MessageLayoutContainer.hpp" #include "Application.hpp" #include "messages/layouts/MessageLayoutContext.hpp" @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -55,7 +56,6 @@ void MessageLayoutContainer::beginLayout(int width, float scale, this->currentWordId_ = 0; this->canAddMessages_ = true; this->isCollapsed_ = false; - this->wasPrevReversed_ = false; } void MessageLayoutContainer::endLayout() @@ -71,7 +71,7 @@ void MessageLayoutContainer::endLayout() QSize(this->dotdotdotWidth_, this->textLineHeight_), QColor("#00D80A"), FontStyle::ChatMediumBold, this->scale_); - if (this->first == FirstWord::RTL) + if (this->isRTL()) { // Shift all elements in the next line to the left for (auto i = this->lines_.back().startIndex; @@ -125,9 +125,9 @@ void MessageLayoutContainer::addElementNoLineBreak( void MessageLayoutContainer::breakLine() { - if (this->containsRTL) + if (this->lineContainsRTL_ || this->isRTL()) { - for (int i = 0; i < this->elements_.size(); i++) + for (size_t i = 0; i < this->elements_.size(); i++) { if (this->elements_[i]->getFlags().has( MessageElementFlag::Username)) @@ -136,6 +136,7 @@ void MessageLayoutContainer::breakLine() break; } } + this->lineContainsRTL_ = false; } int xOffset = 0; @@ -404,7 +405,7 @@ size_t MessageLayoutContainer::getSelectionIndex(QPoint point) const size_t index = 0; - for (auto i = 0; i < lineEnd; i++) + for (size_t i = 0; i < lineEnd; i++) { auto &&element = this->elements_[i]; @@ -565,30 +566,37 @@ int MessageLayoutContainer::nextWordId() void MessageLayoutContainer::addElement(MessageLayoutElement *element, const bool forceAdd, - const int prevIndex) + const qsizetype prevIndex) { if (!this->canAddElements() && !forceAdd) { + assert(prevIndex == -2 && + "element is still referenced in this->elements_"); delete element; return; } - bool isRTLMode = this->first == FirstWord::RTL && prevIndex != -2; bool isAddingMode = prevIndex == -2; + bool isRTLAdjusting = this->isRTL() && !isAddingMode; - // This lambda contains the logic for when to step one 'space width' back for compact x emotes - auto shouldRemoveSpaceBetweenEmotes = [this, prevIndex]() -> bool { + /// Returns `true` if a previously added `spaceWidth_` should be removed + /// before the to be added emote. The space was inserted by the + /// previous element but isn't desired as "removeSpacesBetweenEmotes" is + /// enabled and both elements are emotes. + auto shouldRemoveSpaceBetweenEmotes = [this, prevIndex, + isAddingMode]() -> bool { if (prevIndex == -1 || this->elements_.empty()) { // No previous element found return false; } - const auto &lastElement = prevIndex == -2 ? this->elements_.back() - : this->elements_[prevIndex]; + const auto &lastElement = + isAddingMode ? this->elements_.back() : this->elements_[prevIndex]; if (!lastElement) { + assert(false && "Empty element in container found"); return false; } @@ -608,23 +616,24 @@ void MessageLayoutContainer::addElement(MessageLayoutElement *element, return lastElement->getFlags().has(MessageElementFlag::EmoteImages); }; - if (element->getText().isRightToLeft()) + bool isRTLElement = element->getText().isRightToLeft(); + if (isRTLElement) { - this->containsRTL = true; + this->lineContainsRTL_ = true; } // check the first non-neutral word to see if we should render RTL or LTR - if (isAddingMode && this->first == FirstWord::Neutral && + if (isAddingMode && this->isNeutral() && element->getFlags().has(MessageElementFlag::Text) && !element->getFlags().has(MessageElementFlag::RepliedMessage)) { - if (element->getText().isRightToLeft()) + if (isRTLElement) { - this->first = FirstWord::RTL; + this->textDirection_ = TextDirection::RTL; } - else if (!isNeutral(element->getText())) + else if (!chatterino::isNeutral(element->getText())) { - this->first = FirstWord::LTR; + this->textDirection_ = TextDirection::LTR; } } @@ -665,7 +674,7 @@ void MessageLayoutContainer::addElement(MessageLayoutElement *element, shouldRemoveSpaceBetweenEmotes()) { // Move cursor one 'space width' to the left (right in case of RTL) to combine hug the previous emote - if (isRTLMode) + if (isRTLAdjusting) { this->currentX_ += this->spaceWidth_; } @@ -675,7 +684,7 @@ void MessageLayoutContainer::addElement(MessageLayoutElement *element, } } - if (isRTLMode) + if (isRTLAdjusting) { // shift by width since we are calculating according to top right in RTL mode // but setPosition wants top left @@ -697,7 +706,7 @@ void MessageLayoutContainer::addElement(MessageLayoutElement *element, } // set current x - if (isRTLMode) + if (isRTLAdjusting) { this->currentX_ -= element->getRect().width(); } @@ -708,7 +717,7 @@ void MessageLayoutContainer::addElement(MessageLayoutElement *element, if (element->hasTrailingSpace()) { - if (isRTLMode) + if (isRTLAdjusting) { this->currentX_ -= this->spaceWidth_; } @@ -719,15 +728,15 @@ void MessageLayoutContainer::addElement(MessageLayoutElement *element, } } -void MessageLayoutContainer::reorderRTL(int firstTextIndex) +void MessageLayoutContainer::reorderRTL(size_t firstTextIndex) { if (this->elements_.empty()) { return; } - int startIndex = static_cast(this->lineStart_); - int endIndex = static_cast(this->elements_.size()) - 1; + size_t startIndex = this->lineStart_; + size_t endIndex = this->elements_.size() - 1; if (firstTextIndex >= endIndex || startIndex >= this->elements_.size()) { @@ -735,64 +744,53 @@ void MessageLayoutContainer::reorderRTL(int firstTextIndex) } startIndex = std::max(startIndex, firstTextIndex); - std::vector correctSequence; - std::stack swappedSequence; + QVarLengthArray correctSequence; + // temporary buffer to store elements in opposite order + QVarLengthArray swappedSequence; - // we reverse a sequence of words if it's opposite to the text direction - // the second condition below covers the possible three cases: - // 1 - if we are in RTL mode (first non-neutral word is RTL) - // we render RTL, reversing LTR sequences, - // 2 - if we are in LTR mode (first non-neutral word is LTR or all words are neutral) - // we render LTR, reversing RTL sequences - // 3 - neutral words follow previous words, we reverse a neutral word when the previous word was reversed - - // the first condition checks if a neutral word is treated as a RTL word - // this is used later to add U+202B (RTL embedding) character signal to - // fix punctuation marks and mixing embedding LTR in an RTL word - // this can happen in two cases: - // 1 - in RTL mode, the previous word should be RTL (i.e. not reversed) - // 2 - in LTR mode, the previous word should be RTL (i.e. reversed) - for (int i = startIndex; i <= endIndex; i++) + bool isReversing = false; + for (size_t i = startIndex; i <= endIndex; i++) { auto &element = this->elements_[i]; - const auto neutral = isNeutral(element->getText()); + const auto neutral = chatterino::isNeutral(element->getText()); const auto neutralOrUsername = neutral || element->getFlags().has(MessageElementFlag::Mention); + // check if neutral words are treated as RTL to add U+202B (RTL + // embedding) which fixes punctuation marks if (neutral && - ((this->first == FirstWord::RTL && !this->wasPrevReversed_) || - (this->first == FirstWord::LTR && this->wasPrevReversed_))) + ((this->isRTL() && !isReversing) || (this->isLTR() && isReversing))) { element->reversedNeutral = true; } - if (((element->getText().isRightToLeft() != - (this->first == FirstWord::RTL)) && + + if ((element->getText().isRightToLeft() != this->isRTL() && !neutralOrUsername) || - (neutralOrUsername && this->wasPrevReversed_)) + (neutralOrUsername && isReversing)) { - swappedSequence.push(i); - this->wasPrevReversed_ = true; + swappedSequence.append(i); + isReversing = true; } else { while (!swappedSequence.empty()) { - correctSequence.push_back(swappedSequence.top()); - swappedSequence.pop(); + correctSequence.push_back(swappedSequence.last()); + swappedSequence.pop_back(); } correctSequence.push_back(i); - this->wasPrevReversed_ = false; + isReversing = false; } } while (!swappedSequence.empty()) { - correctSequence.push_back(swappedSequence.top()); - swappedSequence.pop(); + correctSequence.push_back(swappedSequence.last()); + swappedSequence.pop_back(); } // render right to left if we are in RTL mode, otherwise LTR - if (this->first == FirstWord::RTL) + if (this->isRTL()) { this->currentX_ = this->elements_[endIndex]->getRect().right(); } @@ -806,10 +804,11 @@ void MessageLayoutContainer::reorderRTL(int firstTextIndex) this->addElement(this->elements_[correctSequence[0]].get(), false, -1); } - for (int i = 1; i < correctSequence.size() && this->canAddElements(); i++) + for (qsizetype i = 1; i < correctSequence.size() && this->canAddElements(); + i++) { this->addElement(this->elements_[correctSequence[i]].get(), false, - correctSequence[i - 1]); + static_cast(correctSequence[i - 1])); } } @@ -992,4 +991,19 @@ bool MessageLayoutContainer::canCollapse() const this->flags_.has(MessageFlag::Collapsed); } +bool MessageLayoutContainer::isRTL() const noexcept +{ + return this->textDirection_ == TextDirection::RTL; +} + +bool MessageLayoutContainer::isLTR() const noexcept +{ + return this->textDirection_ == TextDirection::LTR; +} + +bool MessageLayoutContainer::isNeutral() const noexcept +{ + return this->textDirection_ == TextDirection::Neutral; +} + } // namespace chatterino diff --git a/src/messages/layouts/MessageLayoutContainer.hpp b/src/messages/layouts/MessageLayoutContainer.hpp index dde3f4d45..7cbcaf9fb 100644 --- a/src/messages/layouts/MessageLayoutContainer.hpp +++ b/src/messages/layouts/MessageLayoutContainer.hpp @@ -10,12 +10,21 @@ #include #include +#if __has_include() +# include +#endif + class QPainter; namespace chatterino { +enum class TextDirection : uint8_t { + Neutral, + RTL, + LTR, +}; + enum class MessageFlag : int64_t; -enum class FirstWord { Neutral, RTL, LTR }; using MessageFlags = FlagsEnum; class MessageLayoutElement; struct Selection; @@ -24,8 +33,6 @@ struct MessagePaintContext; struct MessageLayoutContainer { MessageLayoutContainer() = default; - FirstWord first = FirstWord::Neutral; - /** * Begin the layout process of this message * @@ -212,24 +219,54 @@ private: QRect rect; }; - /* - addElement is called at two stages. first stage is the normal one where we want to add message layout elements to the container. - If we detect an RTL word in the message, reorderRTL will be called, which is the second stage, where we call _addElement - again for each layout element, but in the correct order this time, without adding the elemnt to the this->element_ vector. - Due to compact emote logic, we need the previous element to check if we should change the spacing or not. - in stage one, this is simply elements_.back(), but in stage 2 that's not the case due to the reordering, and we need to pass the - index of the reordered previous element. - In stage one we don't need that and we pass -2 to indicate stage one (i.e. adding mode) - In stage two, we pass -1 for the first element, and the index of the oredered privous element for the rest. - */ + /// @brief Attempts to add @a element to this container + /// + /// This can be called in two scenarios. + /// + /// 1. **Regular**: In this scenario, @a element is positioned and added + /// to the internal container. + /// This is active iff @a prevIndex is `-2`. + /// During this stage, if there isn't any @a textDirection_ detected yet, + /// the added element is checked if it contains RTL/LTR text to infer the + /// direction. Only upon calling @a breakLine, the elements will be + /// visually reorderd. + /// + /// 2. **Repositioning**: In this scenario, @a element is already added to + /// the container thus it's only repositioned. + /// This is active iff @a prevIndex is not `-2`. + /// @a prevIndex is used to handle compact emotes. `-1` is used to + /// indicate no predecessor. + /// + /// @param element[in] The element to add. This must be non-null and + /// allocated with `new`. Ownership is transferred + /// into this container. + /// @param forceAdd When enabled, @a element will be added regardless of + /// `canAddElements`. If @a element won't be added it will + /// be `delete`d. + /// @param prevIndex Controls the "scenario" (see above). `-2` indicates + /// "regular" mode; other values indicate "repositioning". + /// In case of repositioning, this contains the index of + /// the precesding element (visually, according to + /// @a textDirection_ [RTL/LTR]). void addElement(MessageLayoutElement *element, bool forceAdd, - int prevIndex); + qsizetype prevIndex); - // this method is called when a message has an RTL word - // we need to reorder the words to be shown properly - // however we don't we to reorder non-text elements like badges, timestamps, username - // firstTextIndex is the index of the first text element that we need to start the reordering from - void reorderRTL(int firstTextIndex); + /// @brief Reorders the last line according to @a textDirection_ + /// + /// If a line contains RTL or the text direction is RTL, elements need to be + /// reordered (see @a lineContainsRTL_ and @a isRTL respectively). + /// This method reverses sequences of text in the opposite direction for it + /// to remain in its intended direction when rendered. Non-text elements + /// won't be reordered. + /// + /// For example, in an RTL container, the sequence + /// "1_R 2_R 3_N 4_R 5_L 6_L 7_N 8_R" will be (visually) reordered to + /// "8_R 5_L 6_L 7_N 4_R 3_N 2_R 1_R" (x_{L,N,R} indicates the element with + /// id x which is in the direction {LTR,Neutral,RTL}). + /// + /// @param firstTextIndex The index of the first element of the message + /// (i.e. the index after the username). + void reorderRTL(size_t firstTextIndex); /** * Paint a selection rectangle over the given line @@ -274,6 +311,15 @@ private: */ bool canCollapse() const; + /// @returns true, if @a textDirection_ is RTL + [[nodiscard]] bool isRTL() const noexcept; + + /// @returns true, if @a textDirection_ is LTR + [[nodiscard]] bool isLTR() const noexcept; + + /// @returns true, if @a textDirection_ is Neutral + [[nodiscard]] bool isNeutral() const noexcept; + // variables float scale_ = 1.F; /** @@ -304,13 +350,18 @@ private: int currentWordId_ = 0; bool canAddMessages_ = true; bool isCollapsed_ = false; - bool wasPrevReversed_ = false; - /** - * containsRTL indicates whether or not any of the text in this message - * contains any right-to-left characters (e.g. arabic) - */ - bool containsRTL = false; + /// @brief True if the current line contains any RTL text. + /// + /// If the line contains any RTL, it needs to be reordered after a + /// linebreak after which it's reset to `false`. + bool lineContainsRTL_ = false; + + /// @brief The direction of the text in this container. + /// + /// This starts off as neutral until an element is encountered that is + /// either LTR or RTL (afterwards this remains constant). + TextDirection textDirection_ = TextDirection::Neutral; std::vector> elements_; @@ -320,6 +371,10 @@ private: * These lines hold no relation to the elements that are in this */ std::vector lines_; + +#ifdef FRIEND_TEST + FRIEND_TEST(MessageLayoutContainerTest, RtlReordering); +#endif }; } // namespace chatterino diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 79c490fa9..9f79b77eb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -46,6 +46,7 @@ set(test_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/Scrollbar.cpp ${CMAKE_CURRENT_LIST_DIR}/src/Commands.cpp ${CMAKE_CURRENT_LIST_DIR}/src/FlagsEnum.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/MessageLayoutContainer.cpp # Add your new file above this line! ) diff --git a/tests/src/MessageLayoutContainer.cpp b/tests/src/MessageLayoutContainer.cpp new file mode 100644 index 000000000..b72934c76 --- /dev/null +++ b/tests/src/MessageLayoutContainer.cpp @@ -0,0 +1,237 @@ +#include "messages/layouts/MessageLayoutContainer.hpp" + +#include "common/Literals.hpp" +#include "messages/Emote.hpp" +#include "messages/layouts/MessageLayoutElement.hpp" +#include "messages/Message.hpp" +#include "messages/MessageElement.hpp" +#include "mocks/BaseApplication.hpp" +#include "singletons/Fonts.hpp" +#include "singletons/Resources.hpp" +#include "singletons/Theme.hpp" +#include "Test.hpp" + +#include +#include + +using namespace chatterino; +using namespace literals; + +namespace { + +class MockApplication : mock::BaseApplication +{ +public: + MockApplication() + : theme(this->paths_) + , fonts(this->settings) + { + } + Theme *getThemes() override + { + return &this->theme; + } + + Fonts *getFonts() override + { + return &this->fonts; + } + + Theme theme; + Fonts fonts; +}; + +std::vector> makeElements(const QString &text) +{ + std::vector> elements; + bool seenUsername = false; + for (const auto &word : text.split(' ')) + { + if (word.startsWith('@')) + { + if (seenUsername) + { + elements.emplace_back(std::make_shared( + word, word, MessageColor{}, MessageColor{})); + } + else + { + elements.emplace_back(std::make_shared( + word, MessageElementFlag::Username, MessageColor{}, + FontStyle::ChatMediumBold)); + seenUsername = true; + } + continue; + } + + if (word.startsWith('!')) + { + auto emote = std::make_shared(Emote{ + .name = EmoteName{word}, + .images = ImageSet{Image::fromResourcePixmap( + getResources().buttons.addSplit)}, + .tooltip = {}, + .homePage = {}, + .id = {}, + .author = {}, + .baseName = {}, + }); + elements.emplace_back(std::make_shared( + emote, MessageElementFlag::TwitchEmote)); + continue; + } + + elements.emplace_back(std::make_shared( + word, MessageElementFlag::Text, MessageColor{}, + FontStyle::ChatMedium)); + } + + return elements; +} + +using TestParam = std::tuple; + +} // namespace + +namespace chatterino { + +class MessageLayoutContainerTest : public ::testing::TestWithParam +{ +public: + MessageLayoutContainerTest() = default; + + MockApplication mockApplication; +}; + +TEST_P(MessageLayoutContainerTest, RtlReordering) +{ + auto [inputText, expected, expectedDirection] = GetParam(); + MessageLayoutContainer container; + container.beginLayout(10000, 1.0F, 1.0F, {MessageFlag::Collapsed}); + + auto elements = makeElements(inputText); + for (const auto &element : elements) + { + element->addToContainer(container, { + MessageElementFlag::Text, + MessageElementFlag::Username, + MessageElementFlag::TwitchEmote, + }); + } + container.breakLine(); + ASSERT_EQ(container.line_, 1) << "unexpected linebreak"; + + // message layout elements ordered by x position + std::vector ordered; + ordered.reserve(container.elements_.size()); + for (const auto &el : container.elements_) + { + ordered.push_back(el.get()); + } + + std::ranges::sort(ordered, [](auto *a, auto *b) { + return a->getRect().x() < b->getRect().x(); + }); + + QString got; + for (const auto &el : ordered) + { + if (!got.isNull()) + { + got.append(' '); + } + + if (dynamic_cast(el)) + { + el->addCopyTextToString(got); + ASSERT_TRUE(got.endsWith(' ')); + got.chop(1); + } + else + { + got.append(el->getText()); + } + } + + ASSERT_EQ(got, expected) << got; + ASSERT_EQ(container.textDirection_, expectedDirection) << got; +} + +INSTANTIATE_TEST_SUITE_P( + MessageLayoutContainer, MessageLayoutContainerTest, + testing::Values( + TestParam{ + u"@aliens foo bar baz @foo qox !emote1 !emote2"_s, + u"@aliens foo bar baz @foo qox !emote1 !emote2"_s, + TextDirection::LTR, + }, + TestParam{ + u"@aliens ! foo bar baz @foo qox !emote1 !emote2"_s, + u"@aliens ! foo bar baz @foo qox !emote1 !emote2"_s, + TextDirection::LTR, + }, + TestParam{ + u"@aliens ."_s, + u"@aliens ."_s, + TextDirection::Neutral, + }, + // RTL + TestParam{ + u"@aliens و غير دارت إعادة, بل كما وقام قُدُماً. قام تم الجوي بوابة, خلاف أراض هو بلا. عن وحتّى ميناء غير"_s, + u"@aliens غير ميناء وحتّى عن بلا. هو أراض خلاف بوابة, الجوي تم قام قُدُماً. وقام كما بل إعادة, دارت غير و"_s, + TextDirection::RTL, + }, + TestParam{ + u"@aliens و غير دارت إعادة, بل ض هو my LTR 123 بلا. عن 123 456 وحتّى ميناء غير"_s, + u"@aliens غير ميناء وحتّى 456 123 عن بلا. my LTR 123 هو ض بل إعادة, دارت غير و"_s, + TextDirection::RTL, + }, + TestParam{ + u"@aliens ور دارت إ @user baz bar عاد هو my LTR 123 بلا. عن 123 456 وحتّ غير"_s, + u"@aliens غير وحتّ 456 123 عن بلا. my LTR 123 هو عاد baz bar @user إ دارت ور"_s, + TextDirection::RTL, + }, + TestParam{ + u"@aliens ور !emote1 !emote2 !emote3 دارت إ @user baz bar عاد هو my LTR 123 بلا. عن 123 456 وحتّ غير"_s, + u"@aliens غير وحتّ 456 123 عن بلا. my LTR 123 هو عاد baz bar @user إ دارت !emote3 !emote2 !emote1 ور"_s, + TextDirection::RTL, + }, + TestParam{ + u"@aliens ور !emote1 !emote2 LTR text !emote3 !emote4 غير"_s, + u"@aliens غير LTR text !emote3 !emote4 !emote2 !emote1 ور"_s, + TextDirection::RTL, + }, + + TestParam{ + u"@aliens !!! ور !emote1 !emote2 LTR text !emote3 !emote4 غير"_s, + u"@aliens غير LTR text !emote3 !emote4 !emote2 !emote1 ور !!!"_s, + TextDirection::RTL, + }, + // LTR + TestParam{ + u"@aliens LTR و غير دا ميناء غير"_s, + u"@aliens LTR غير ميناء دا غير و"_s, + TextDirection::LTR, + }, + TestParam{ + u"@aliens LTR و غير د ض هو my LTR 123 بلا. عن 123 456 وحتّى مير"_s, + u"@aliens LTR هو ض د غير و my LTR 123 مير وحتّى 456 123 عن بلا."_s, + TextDirection::LTR, + }, + TestParam{ + u"@aliens LTR ور دارت إ @user baz bar عاد هو my LTR 123 بلا. عن 123 456 وحتّ غير"_s, + u"@aliens LTR @user إ دارت ور baz bar هو عاد my LTR 123 غير وحتّ 456 123 عن بلا."_s, + TextDirection::LTR, + }, + TestParam{ + u"@aliens LTR ور !emote1 !emote2 !emote3 دارت إ @user baz bar عاد هو my LTR 123 بلا. عن 123 456 وحتّ غير"_s, + u"@aliens LTR @user إ دارت !emote3 !emote2 !emote1 ور baz bar هو عاد my LTR 123 غير وحتّ 456 123 عن بلا."_s, + TextDirection::LTR, + }, + TestParam{ + u"@aliens LTR غير وحتّ !emote1 !emote2 LTR text !emote3 !emote4 عاد هو"_s, + u"@aliens LTR !emote2 !emote1 وحتّ غير LTR text !emote3 !emote4 هو عاد"_s, + TextDirection::LTR, + })); + +} // namespace chatterino From 5fc4309e0efe2013445947839a1a841b816dc55b Mon Sep 17 00:00:00 2001 From: cmp Date: Sun, 28 Jul 2024 05:02:20 -0500 Subject: [PATCH 26/63] Handle panning touch gestures (#5524) --- CHANGELOG.md | 1 + src/widgets/helper/ChannelView.cpp | 66 ++++++++++++++++++++++++++++++ src/widgets/helper/ChannelView.hpp | 5 +++ 3 files changed, 72 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 714681d09..deec23cb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - Minor: Support more Firefox variants for incognito link opening. (#5503) - Minor: Replying to a message will now display the message being replied to. (#4350, #5519) - Minor: Links can now have prefixes and suffixes such as parentheses. (#5486, #5515) +- Minor: Added support for scrolling in splits with touchscreen panning gestures. (#5524) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) - Bugfix: Fixed restricted users usernames not being clickable. (#5405) diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 7430614a9..be91e2342 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -369,6 +370,8 @@ ChannelView::ChannelView(InternalCtor /*tag*/, QWidget *parent, Split *split, this->scrollUpdateRequested(); }); + this->grabGesture(Qt::PanGesture); + // TODO: Figure out if we need this, and if so, why // StrongFocus means we can focus this event through clicking it // and tabbing to it from another widget. I don't currently know @@ -1786,8 +1789,71 @@ void ChannelView::leaveEvent(QEvent * /*event*/) this->unpause(PauseReason::Mouse); } +bool ChannelView::event(QEvent *event) +{ + if (event->type() == QEvent::Gesture) + { + if (const auto *gestureEvent = dynamic_cast(event)) + { + return this->gestureEvent(gestureEvent); + } + } + + return BaseWidget::event(event); +} + +bool ChannelView::gestureEvent(const QGestureEvent *event) +{ + if (QGesture *pan = event->gesture(Qt::PanGesture)) + { + if (const auto *gesture = dynamic_cast(pan)) + { + switch (gesture->state()) + { + case Qt::GestureStarted: { + this->isPanning_ = true; + // Remove any selections and hide tooltip while panning + this->clearSelection(); + this->tooltipWidget_->hide(); + if (this->isScrolling_) + { + this->disableScrolling(); + } + } + break; + + case Qt::GestureUpdated: { + if (this->scrollBar_->isVisible()) + { + this->scrollBar_->offset(-gesture->delta().y() * 0.1); + } + } + break; + + case Qt::GestureFinished: + case Qt::GestureCanceled: + default: { + this->clearSelection(); + this->isPanning_ = false; + } + break; + } + + return true; + } + } + + return false; +} + void ChannelView::mouseMoveEvent(QMouseEvent *event) { + if (this->isPanning_) + { + // Don't do any text selection, hovering, etc while panning + return; + } + /// Pause on hover if (float pauseTime = getSettings()->pauseOnHoverDuration; pauseTime > 0.001F) diff --git a/src/widgets/helper/ChannelView.hpp b/src/widgets/helper/ChannelView.hpp index e6cb7597e..a670d6e30 100644 --- a/src/widgets/helper/ChannelView.hpp +++ b/src/widgets/helper/ChannelView.hpp @@ -10,6 +10,7 @@ #include "widgets/TooltipWidget.hpp" #include +#include #include #include #include @@ -216,6 +217,9 @@ protected: #endif void leaveEvent(QEvent * /*event*/) override; + bool event(QEvent *event) override; + bool gestureEvent(const QGestureEvent *event); + void mouseMoveEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; @@ -374,6 +378,7 @@ private: QTimer clickTimer_; bool isScrolling_ = false; + bool isPanning_ = false; QPointF lastMiddlePressPosition_; QPointF currentMousePosition_; QTimer scrollTimer_; From 5ee5abf5b20547bdcf991009a9d8583c5e319254 Mon Sep 17 00:00:00 2001 From: nerix Date: Sun, 28 Jul 2024 12:29:29 +0200 Subject: [PATCH 27/63] fix: sort elements after RTL reordering (#5525) --- CHANGELOG.md | 1 + .../layouts/MessageLayoutContainer.cpp | 14 +++++++++++ .../layouts/MessageLayoutContainer.hpp | 3 +++ tests/src/MessageLayoutContainer.cpp | 23 ++++++++----------- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index deec23cb2..fe4463eb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - Bugfix: Fixed `/clearmessages` not working with more than one window. (#5489) - Bugfix: Fixed splits staying paused after unfocusing Chatterino in certain configurations. (#5504) - Bugfix: Links with invalid characters in the domain are no longer detected. (#5509) +- Bugfix: Fixed janky selection for messages with RTL segments (selection is still wrong, but consistently wrong). (#5525) - Dev: Update Windows build from Qt 6.5.0 to Qt 6.7.1. (#5420) - Dev: Update vcpkg build Qt from 6.5.0 to 6.7.0, boost from 1.83.0 to 1.85.0, openssl from 3.1.3 to 3.3.0. (#5422) - Dev: Unsingletonize `ISoundController`. (#5462) diff --git a/src/messages/layouts/MessageLayoutContainer.cpp b/src/messages/layouts/MessageLayoutContainer.cpp index 3c2bd122d..0f8aa498f 100644 --- a/src/messages/layouts/MessageLayoutContainer.cpp +++ b/src/messages/layouts/MessageLayoutContainer.cpp @@ -56,6 +56,8 @@ void MessageLayoutContainer::beginLayout(int width, float scale, this->currentWordId_ = 0; this->canAddMessages_ = true; this->isCollapsed_ = false; + this->lineContainsRTL_ = false; + this->anyReorderingDone_ = false; } void MessageLayoutContainer::endLayout() @@ -105,6 +107,17 @@ void MessageLayoutContainer::endLayout() { this->elements_.back()->setTrailingSpace(false); } + + if (this->anyReorderingDone_) + { + std::ranges::sort(this->elements_, [](const auto &a, const auto &b) { + if (a->getLine() == b->getLine()) + { + return a->getRect().x() < b->getRect().x(); + } + return a->getLine() < b->getLine(); + }); + } } void MessageLayoutContainer::addElement(MessageLayoutElement *element) @@ -137,6 +150,7 @@ void MessageLayoutContainer::breakLine() } } this->lineContainsRTL_ = false; + this->anyReorderingDone_ = true; } int xOffset = 0; diff --git a/src/messages/layouts/MessageLayoutContainer.hpp b/src/messages/layouts/MessageLayoutContainer.hpp index 7cbcaf9fb..7c14faf40 100644 --- a/src/messages/layouts/MessageLayoutContainer.hpp +++ b/src/messages/layouts/MessageLayoutContainer.hpp @@ -357,6 +357,9 @@ private: /// linebreak after which it's reset to `false`. bool lineContainsRTL_ = false; + /// True if there was any RTL/LTR reordering done in this container + bool anyReorderingDone_ = false; + /// @brief The direction of the text in this container. /// /// This starts off as neutral until an element is encountered that is diff --git a/tests/src/MessageLayoutContainer.cpp b/tests/src/MessageLayoutContainer.cpp index b72934c76..b0aa4f30e 100644 --- a/tests/src/MessageLayoutContainer.cpp +++ b/tests/src/MessageLayoutContainer.cpp @@ -118,34 +118,31 @@ TEST_P(MessageLayoutContainerTest, RtlReordering) MessageElementFlag::TwitchEmote, }); } - container.breakLine(); + container.endLayout(); ASSERT_EQ(container.line_, 1) << "unexpected linebreak"; - // message layout elements ordered by x position - std::vector ordered; - ordered.reserve(container.elements_.size()); + int x = -1; for (const auto &el : container.elements_) { - ordered.push_back(el.get()); + ASSERT_LT(x, el->getRect().x()); + x = el->getRect().x(); } - std::ranges::sort(ordered, [](auto *a, auto *b) { - return a->getRect().x() < b->getRect().x(); - }); - QString got; - for (const auto &el : ordered) + for (const auto &el : container.elements_) { if (!got.isNull()) { got.append(' '); } - if (dynamic_cast(el)) + if (dynamic_cast(el.get())) { el->addCopyTextToString(got); - ASSERT_TRUE(got.endsWith(' ')); - got.chop(1); + if (el->hasTrailingSpace()) + { + got.chop(1); + } } else { From aed55ac1ba765aa21a74c79d7493fdd3fd79a657 Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 3 Aug 2024 12:00:58 +0200 Subject: [PATCH 28/63] fix: replace defines with constexpr/const and use more absolute paths for includes (#5527) bye bye nuuls --- CHANGELOG.md | 1 + src/common/ChannelChatters.cpp | 2 +- src/common/Common.hpp | 33 ++-- src/common/Credentials.cpp | 19 +- src/common/Modes.cpp | 2 +- src/common/Version.hpp | 19 +- src/controllers/accounts/Account.cpp | 2 +- src/controllers/accounts/AccountModel.cpp | 2 +- src/controllers/commands/Command.cpp | 2 +- src/controllers/highlights/HighlightBadge.cpp | 2 +- .../notifications/NotificationModel.cpp | 2 +- src/controllers/pings/MutedChannelModel.cpp | 2 +- src/debug/Benchmark.cpp | 2 +- src/messages/Emote.cpp | 2 +- src/messages/MessageBuilder.cpp | 2 +- src/messages/MessageColor.cpp | 2 +- src/messages/layouts/MessageLayout.cpp | 6 - .../layouts/MessageLayoutContainer.cpp | 21 ++- src/messages/search/RegexPredicate.cpp | 2 +- src/messages/search/RegexPredicate.hpp | 2 +- src/providers/IvrApi.cpp | 2 +- src/providers/IvrApi.hpp | 4 +- src/providers/irc/AbstractIrcServer.cpp | 2 +- src/providers/irc/Irc2.cpp | 2 +- src/providers/irc/IrcAccount.cpp | 2 +- src/providers/irc/IrcChannel2.cpp | 2 +- src/providers/irc/IrcCommands.cpp | 2 +- src/providers/irc/IrcConnection2.cpp | 4 +- src/providers/irc/IrcServer.cpp | 2 +- src/providers/twitch/ChannelPointReward.cpp | 21 ++- src/providers/twitch/ChannelPointReward.hpp | 6 +- src/providers/twitch/TwitchEmotes.cpp | 4 +- src/providers/twitch/TwitchEmotes.hpp | 9 +- src/providers/twitch/api/Helix.hpp | 4 +- src/singletons/ImageUploader.cpp | 6 +- src/singletons/Theme.cpp | 1 - src/singletons/Toasts.cpp | 12 +- src/singletons/Updates.cpp | 38 +++- src/util/DisplayBadge.cpp | 2 +- src/util/FunctionEventFilter.cpp | 2 +- src/util/FuzzyConvert.cpp | 2 +- src/util/Helpers.cpp | 2 +- src/util/RatelimitBucket.cpp | 2 +- src/util/SampleData.cpp | 2 +- src/widgets/AccountSwitchWidget.cpp | 2 +- src/widgets/TooltipWidget.cpp | 6 +- src/widgets/Window.cpp | 6 +- src/widgets/dialogs/BadgePickerDialog.cpp | 2 +- src/widgets/dialogs/EmotePopup.cpp | 2 +- src/widgets/dialogs/IrcConnectionEditor.cpp | 2 +- src/widgets/dialogs/QualityPopup.cpp | 2 +- src/widgets/dialogs/SelectChannelDialog.cpp | 8 +- .../dialogs/SelectChannelFiltersDialog.cpp | 2 +- src/widgets/dialogs/UserInfoPopup.cpp | 172 +++++++++--------- src/widgets/dialogs/WelcomeDialog.cpp | 2 +- src/widgets/helper/Button.cpp | 2 +- src/widgets/helper/ChannelView.cpp | 6 +- src/widgets/helper/ComboBoxItemDelegate.cpp | 2 +- src/widgets/helper/CommonTexts.hpp | 21 ++- src/widgets/helper/EditableModelView.cpp | 2 +- src/widgets/helper/NotebookButton.cpp | 2 - src/widgets/helper/NotebookTab.hpp | 2 +- src/widgets/helper/SearchPopup.cpp | 2 +- src/widgets/helper/TitlebarButton.cpp | 2 +- src/widgets/listview/GenericListItem.cpp | 2 +- src/widgets/listview/GenericListModel.cpp | 2 +- src/widgets/settingspages/AboutPage.cpp | 21 +-- src/widgets/settingspages/AccountsPage.cpp | 2 +- src/widgets/settingspages/CommandPage.cpp | 16 +- .../settingspages/ExternalToolsPage.cpp | 8 +- src/widgets/settingspages/FiltersPage.cpp | 12 +- src/widgets/settingspages/GeneralPage.cpp | 101 +++++----- .../settingspages/HighlightingPage.cpp | 10 +- src/widgets/settingspages/IgnoresPage.cpp | 10 +- src/widgets/settingspages/ModerationPage.cpp | 2 +- src/widgets/settingspages/NicknamesPage.cpp | 2 +- .../settingspages/NotificationPage.cpp | 2 +- src/widgets/settingspages/SettingsPage.cpp | 2 +- src/widgets/splits/ClosedSplits.cpp | 2 +- src/widgets/splits/Split.cpp | 47 ++--- src/widgets/splits/SplitContainer.cpp | 10 +- src/widgets/splits/SplitOverlay.cpp | 2 +- tests/src/Updates.cpp | 4 +- 83 files changed, 386 insertions(+), 380 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe4463eb3..d9abb6df1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ - Dev: The running Qt version is now shown in the about page if it differs from the compiled version. (#5501) - Dev: `FlagsEnum` is now `constexpr`. (#5510) - Dev: Documented and added tests to RTL handling. (#5473) +- Dev: Refactored a few `#define`s into `const(expr)` and cleaned includes. (#5527) ## 2.5.1 diff --git a/src/common/ChannelChatters.cpp b/src/common/ChannelChatters.cpp index 3bb785a0a..b66a3cc45 100644 --- a/src/common/ChannelChatters.cpp +++ b/src/common/ChannelChatters.cpp @@ -1,4 +1,4 @@ -#include "ChannelChatters.hpp" +#include "common/ChannelChatters.hpp" #include "common/Channel.hpp" #include "messages/Message.hpp" diff --git a/src/common/Common.hpp b/src/common/Common.hpp index 8d6097473..f1ce96754 100644 --- a/src/common/Common.hpp +++ b/src/common/Common.hpp @@ -5,17 +5,17 @@ #include #include -#include -#include - -#define LINK_CHATTERINO_WIKI "https://wiki.chatterino.com" -#define LINK_CHATTERINO_DISCORD "https://discord.gg/7Y5AYhAK4z" -#define LINK_CHATTERINO_SOURCE "https://github.com/Chatterino/chatterino2" namespace chatterino { -const inline auto TWITCH_PLAYER_URL = - QStringLiteral("https://player.twitch.tv/?channel=%1&parent=twitch.tv"); +constexpr QStringView LINK_CHATTERINO_WIKI = u"https://wiki.chatterino.com"; +constexpr QStringView LINK_CHATTERINO_DISCORD = + u"https://discord.gg/7Y5AYhAK4z"; +constexpr QStringView LINK_CHATTERINO_SOURCE = + u"https://github.com/Chatterino/chatterino2"; + +constexpr QStringView TWITCH_PLAYER_URL = + u"https://player.twitch.tv/?channel=%1&parent=twitch.tv"; enum class HighlightState { None, @@ -23,21 +23,14 @@ enum class HighlightState { NewMessage, }; -const Qt::KeyboardModifiers showSplitOverlayModifiers = +constexpr Qt::KeyboardModifiers SHOW_SPLIT_OVERLAY_MODIFIERS = Qt::ControlModifier | Qt::AltModifier; -const Qt::KeyboardModifiers showAddSplitRegions = +constexpr Qt::KeyboardModifiers SHOW_ADD_SPLIT_REGIONS = Qt::ControlModifier | Qt::AltModifier; -const Qt::KeyboardModifiers showResizeHandlesModifiers = Qt::ControlModifier; +constexpr Qt::KeyboardModifiers SHOW_RESIZE_HANDLES_MODIFIERS = + Qt::ControlModifier; -#ifndef ATTR_UNUSED -# ifdef Q_OS_WIN -# define ATTR_UNUSED -# else -# define ATTR_UNUSED __attribute__((unused)) -# endif -#endif - -static const char *ANONYMOUS_USERNAME_LABEL ATTR_UNUSED = " - anonymous - "; +constexpr const char *ANONYMOUS_USERNAME_LABEL = " - anonymous - "; template std::weak_ptr weakOf(T *element) diff --git a/src/common/Credentials.cpp b/src/common/Credentials.cpp index 68c9cdd59..3c1c0ce04 100644 --- a/src/common/Credentials.cpp +++ b/src/common/Credentials.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -26,16 +27,16 @@ # endif #endif -#define FORMAT_NAME \ - ([&] { \ - assert(!provider.contains(":")); \ - return QString("chatterino:%1:%2").arg(provider).arg(name_); \ - })() - namespace { using namespace chatterino; +QString formatName(const QString &provider, const QString &name) +{ + assert(!provider.contains(":")); + return u"chatterino:" % provider % u':' % name; +} + bool useKeyring() { #ifdef NO_QTKEYCHAIN @@ -184,7 +185,7 @@ void Credentials::get(const QString &provider, const QString &name_, { assertInGuiThread(); - auto name = FORMAT_NAME; + auto name = formatName(provider, name_); if (useKeyring()) { @@ -219,7 +220,7 @@ void Credentials::set(const QString &provider, const QString &name_, /// On linux, we try to use a keychain but show a message to disable it when it fails. /// XXX: add said message - auto name = FORMAT_NAME; + auto name = formatName(provider, name_); if (useKeyring()) { @@ -242,7 +243,7 @@ void Credentials::erase(const QString &provider, const QString &name_) { assertInGuiThread(); - auto name = FORMAT_NAME; + auto name = formatName(provider, name_); if (useKeyring()) { diff --git a/src/common/Modes.cpp b/src/common/Modes.cpp index ead79dea9..588a304f1 100644 --- a/src/common/Modes.cpp +++ b/src/common/Modes.cpp @@ -1,4 +1,4 @@ -#include "Modes.hpp" +#include "common/Modes.hpp" #include "util/CombinePath.hpp" diff --git a/src/common/Version.hpp b/src/common/Version.hpp index fbe536a69..8d9ef54a0 100644 --- a/src/common/Version.hpp +++ b/src/common/Version.hpp @@ -1,7 +1,8 @@ #pragma once #include -#include + +namespace chatterino { /** * Valid version formats, in order of latest to oldest @@ -24,21 +25,7 @@ * - 2.4.0-alpha.2 * - 2.4.0-alpha **/ -#define CHATTERINO_VERSION "2.5.1" - -#if defined(Q_OS_WIN) -# define CHATTERINO_OS "win" -#elif defined(Q_OS_MACOS) -# define CHATTERINO_OS "macos" -#elif defined(Q_OS_LINUX) -# define CHATTERINO_OS "linux" -#elif defined(Q_OS_FREEBSD) -# define CHATTERINO_OS "freebsd" -#else -# define CHATTERINO_OS "unknown" -#endif - -namespace chatterino { +inline const QString CHATTERINO_VERSION = QStringLiteral("2.5.1"); class Version { diff --git a/src/controllers/accounts/Account.cpp b/src/controllers/accounts/Account.cpp index 9cf9ceefa..1d9f0ab1c 100644 --- a/src/controllers/accounts/Account.cpp +++ b/src/controllers/accounts/Account.cpp @@ -1,4 +1,4 @@ -#include "Account.hpp" +#include "controllers/accounts/Account.hpp" #include diff --git a/src/controllers/accounts/AccountModel.cpp b/src/controllers/accounts/AccountModel.cpp index cf2b1c79f..f0598318c 100644 --- a/src/controllers/accounts/AccountModel.cpp +++ b/src/controllers/accounts/AccountModel.cpp @@ -1,4 +1,4 @@ -#include "AccountModel.hpp" +#include "controllers/accounts/AccountModel.hpp" #include "controllers/accounts/Account.hpp" #include "util/StandardItemHelper.hpp" diff --git a/src/controllers/commands/Command.cpp b/src/controllers/commands/Command.cpp index e7113db9c..5ac0feb5c 100644 --- a/src/controllers/commands/Command.cpp +++ b/src/controllers/commands/Command.cpp @@ -1,4 +1,4 @@ -#include "Command.hpp" +#include "controllers/commands/Command.hpp" namespace chatterino { diff --git a/src/controllers/highlights/HighlightBadge.cpp b/src/controllers/highlights/HighlightBadge.cpp index b4452a22b..7958c8faa 100644 --- a/src/controllers/highlights/HighlightBadge.cpp +++ b/src/controllers/highlights/HighlightBadge.cpp @@ -1,4 +1,4 @@ -#include "HighlightBadge.hpp" +#include "controllers/highlights/HighlightBadge.hpp" #include "messages/SharedMessageBuilder.hpp" #include "providers/twitch/TwitchBadge.hpp" diff --git a/src/controllers/notifications/NotificationModel.cpp b/src/controllers/notifications/NotificationModel.cpp index 5de8bc903..b68a50441 100644 --- a/src/controllers/notifications/NotificationModel.cpp +++ b/src/controllers/notifications/NotificationModel.cpp @@ -1,4 +1,4 @@ -#include "NotificationModel.hpp" +#include "controllers/notifications/NotificationModel.hpp" #include "Application.hpp" #include "singletons/Settings.hpp" diff --git a/src/controllers/pings/MutedChannelModel.cpp b/src/controllers/pings/MutedChannelModel.cpp index fc1473506..df32f53d5 100644 --- a/src/controllers/pings/MutedChannelModel.cpp +++ b/src/controllers/pings/MutedChannelModel.cpp @@ -1,4 +1,4 @@ -#include "MutedChannelModel.hpp" +#include "controllers/pings/MutedChannelModel.hpp" #include "Application.hpp" #include "singletons/Settings.hpp" diff --git a/src/debug/Benchmark.cpp b/src/debug/Benchmark.cpp index 5c93ac8e6..0aca0a61d 100644 --- a/src/debug/Benchmark.cpp +++ b/src/debug/Benchmark.cpp @@ -1,4 +1,4 @@ -#include "Benchmark.hpp" +#include "debug/Benchmark.hpp" #include "common/QLogging.hpp" diff --git a/src/messages/Emote.cpp b/src/messages/Emote.cpp index 6281277fc..f19fc3027 100644 --- a/src/messages/Emote.cpp +++ b/src/messages/Emote.cpp @@ -1,4 +1,4 @@ -#include "Emote.hpp" +#include "messages/Emote.hpp" #include diff --git a/src/messages/MessageBuilder.cpp b/src/messages/MessageBuilder.cpp index 3e91d04dd..ae78ab711 100644 --- a/src/messages/MessageBuilder.cpp +++ b/src/messages/MessageBuilder.cpp @@ -1,4 +1,4 @@ -#include "MessageBuilder.hpp" +#include "messages/MessageBuilder.hpp" #include "Application.hpp" #include "common/IrcColors.hpp" diff --git a/src/messages/MessageColor.cpp b/src/messages/MessageColor.cpp index bd784197a..6e2f01c67 100644 --- a/src/messages/MessageColor.cpp +++ b/src/messages/MessageColor.cpp @@ -1,4 +1,4 @@ -#include "MessageColor.hpp" +#include "messages/MessageColor.hpp" #include "singletons/Theme.hpp" diff --git a/src/messages/layouts/MessageLayout.cpp b/src/messages/layouts/MessageLayout.cpp index 10397d93c..e1a3d8a3c 100644 --- a/src/messages/layouts/MessageLayout.cpp +++ b/src/messages/layouts/MessageLayout.cpp @@ -19,12 +19,6 @@ #include #include -#define MARGIN_LEFT (int)(8 * this->scale) -#define MARGIN_RIGHT (int)(8 * this->scale) -#define MARGIN_TOP (int)(4 * this->scale) -#define MARGIN_BOTTOM (int)(4 * this->scale) -#define COMPACT_EMOTES_OFFSET 6 - namespace chatterino { namespace { diff --git a/src/messages/layouts/MessageLayoutContainer.cpp b/src/messages/layouts/MessageLayoutContainer.cpp index 0f8aa498f..0e84d3252 100644 --- a/src/messages/layouts/MessageLayoutContainer.cpp +++ b/src/messages/layouts/MessageLayoutContainer.cpp @@ -18,13 +18,17 @@ #include -#define COMPACT_EMOTES_OFFSET 4 -#define MAX_UNCOLLAPSED_LINES \ - (getSettings()->collpseMessagesMinLines.getValue()) - namespace { -constexpr const QMargins MARGIN{8, 4, 8, 4}; +using namespace chatterino; + +constexpr QMargins MARGIN{8, 4, 8, 4}; +constexpr int COMPACT_EMOTES_OFFSET = 4; + +int maxUncollapsedLines() +{ + return getSettings()->collpseMessagesMinLines.getValue(); +} } // namespace @@ -208,7 +212,7 @@ void MessageLayoutContainer::breakLine() this->lineStart_ = this->elements_.size(); // this->currentX = (int)(this->scale * 8); - if (this->canCollapse() && this->line_ + 1 >= MAX_UNCOLLAPSED_LINES) + if (this->canCollapse() && this->line_ + 1 >= maxUncollapsedLines()) { this->canAddMessages_ = false; return; @@ -568,8 +572,9 @@ int MessageLayoutContainer::remainingWidth() const { return (this->width_ - int(MARGIN.left() * this->scale_) - int(MARGIN.right() * this->scale_) - - (this->line_ + 1 == MAX_UNCOLLAPSED_LINES ? this->dotdotdotWidth_ - : 0)) - + (static_cast(this->line_ + 1) == maxUncollapsedLines() + ? this->dotdotdotWidth_ + : 0)) - this->currentX_; } diff --git a/src/messages/search/RegexPredicate.cpp b/src/messages/search/RegexPredicate.cpp index 02eeec6c8..733949afa 100644 --- a/src/messages/search/RegexPredicate.cpp +++ b/src/messages/search/RegexPredicate.cpp @@ -1,4 +1,4 @@ -#include "RegexPredicate.hpp" +#include "messages/search/RegexPredicate.hpp" #include "messages/Message.hpp" diff --git a/src/messages/search/RegexPredicate.hpp b/src/messages/search/RegexPredicate.hpp index 63e68cabd..e1cc6e15e 100644 --- a/src/messages/search/RegexPredicate.hpp +++ b/src/messages/search/RegexPredicate.hpp @@ -1,8 +1,8 @@ #pragma once #include "messages/search/MessagePredicate.hpp" -#include "QRegularExpression" +#include #include namespace chatterino { diff --git a/src/providers/IvrApi.cpp b/src/providers/IvrApi.cpp index 9991661b7..02d733b18 100644 --- a/src/providers/IvrApi.cpp +++ b/src/providers/IvrApi.cpp @@ -1,4 +1,4 @@ -#include "IvrApi.hpp" +#include "providers/IvrApi.hpp" #include "common/network/NetworkResult.hpp" #include "common/QLogging.hpp" diff --git a/src/providers/IvrApi.hpp b/src/providers/IvrApi.hpp index f8cc72b76..808471897 100644 --- a/src/providers/IvrApi.hpp +++ b/src/providers/IvrApi.hpp @@ -64,9 +64,7 @@ struct IvrEmote { : code(root.value("code").toString()) , id(root.value("id").toString()) , setId(root.value("setID").toString()) - , url(QString(TWITCH_EMOTE_TEMPLATE) - .replace("{id}", this->id) - .replace("{scale}", "3.0")) + , url(TWITCH_EMOTE_TEMPLATE.arg(this->id, u"3.0")) , emoteType(root.value("type").toString()) , imageType(root.value("assetType").toString()) { diff --git a/src/providers/irc/AbstractIrcServer.cpp b/src/providers/irc/AbstractIrcServer.cpp index 948a2962d..599a8e055 100644 --- a/src/providers/irc/AbstractIrcServer.cpp +++ b/src/providers/irc/AbstractIrcServer.cpp @@ -1,4 +1,4 @@ -#include "AbstractIrcServer.hpp" +#include "providers/irc/AbstractIrcServer.hpp" #include "common/Channel.hpp" #include "common/QLogging.hpp" diff --git a/src/providers/irc/Irc2.cpp b/src/providers/irc/Irc2.cpp index c51a5f323..48b3cd0a1 100644 --- a/src/providers/irc/Irc2.cpp +++ b/src/providers/irc/Irc2.cpp @@ -1,4 +1,4 @@ -#include "Irc2.hpp" +#include "providers/irc/Irc2.hpp" #include "Application.hpp" #include "common/Credentials.hpp" diff --git a/src/providers/irc/IrcAccount.cpp b/src/providers/irc/IrcAccount.cpp index 96486b7ea..530302521 100644 --- a/src/providers/irc/IrcAccount.cpp +++ b/src/providers/irc/IrcAccount.cpp @@ -1,4 +1,4 @@ -#include "IrcAccount.hpp" +#include "providers/irc/IrcAccount.hpp" // namespace chatterino { // diff --git a/src/providers/irc/IrcChannel2.cpp b/src/providers/irc/IrcChannel2.cpp index 2a2a3be93..76feb901b 100644 --- a/src/providers/irc/IrcChannel2.cpp +++ b/src/providers/irc/IrcChannel2.cpp @@ -1,4 +1,4 @@ -#include "IrcChannel2.hpp" +#include "providers/irc/IrcChannel2.hpp" #include "common/Channel.hpp" #include "debug/AssertInGuiThread.hpp" diff --git a/src/providers/irc/IrcCommands.cpp b/src/providers/irc/IrcCommands.cpp index cd5f7d5e6..b1b2e8fc3 100644 --- a/src/providers/irc/IrcCommands.cpp +++ b/src/providers/irc/IrcCommands.cpp @@ -1,4 +1,4 @@ -#include "IrcCommands.hpp" +#include "providers/irc/IrcCommands.hpp" #include "messages/MessageBuilder.hpp" #include "providers/irc/IrcChannel2.hpp" diff --git a/src/providers/irc/IrcConnection2.cpp b/src/providers/irc/IrcConnection2.cpp index 19f327c24..3f9d57c97 100644 --- a/src/providers/irc/IrcConnection2.cpp +++ b/src/providers/irc/IrcConnection2.cpp @@ -1,4 +1,4 @@ -#include "IrcConnection2.hpp" +#include "providers/irc/IrcConnection2.hpp" #include "common/QLogging.hpp" #include "common/Version.hpp" @@ -11,7 +11,7 @@ namespace chatterino { namespace { - const auto payload = QString("chatterino/" CHATTERINO_VERSION); + const auto payload = "chatterino/" + CHATTERINO_VERSION; } // namespace diff --git a/src/providers/irc/IrcServer.cpp b/src/providers/irc/IrcServer.cpp index a5148c9c7..c88109ad4 100644 --- a/src/providers/irc/IrcServer.cpp +++ b/src/providers/irc/IrcServer.cpp @@ -1,4 +1,4 @@ -#include "IrcServer.hpp" +#include "providers/irc/IrcServer.hpp" #include "Application.hpp" #include "common/QLogging.hpp" diff --git a/src/providers/twitch/ChannelPointReward.cpp b/src/providers/twitch/ChannelPointReward.cpp index 658d498ff..8849b8b62 100644 --- a/src/providers/twitch/ChannelPointReward.cpp +++ b/src/providers/twitch/ChannelPointReward.cpp @@ -1,8 +1,18 @@ -#include "ChannelPointReward.hpp" +#include "providers/twitch/ChannelPointReward.hpp" -#include "common/QLogging.hpp" #include "messages/Image.hpp" +#include + +namespace { + +QString twitchChannelPointRewardUrl(const QString &file) +{ + return u"https://static-cdn.jtvnw.net/custom-reward-images/default-" % file; +} + +} // namespace + namespace chatterino { ChannelPointReward::ChannelPointReward(const QJsonObject &redemption) @@ -94,11 +104,10 @@ ChannelPointReward::ChannelPointReward(const QJsonObject &redemption) else { static const ImageSet defaultImage{ - Image::fromUrl({TWITCH_CHANNEL_POINT_REWARD_URL("1.png")}, 1, - baseSize), - Image::fromUrl({TWITCH_CHANNEL_POINT_REWARD_URL("2.png")}, 0.5, + Image::fromUrl({twitchChannelPointRewardUrl("1.png")}, 1, baseSize), + Image::fromUrl({twitchChannelPointRewardUrl("2.png")}, 0.5, baseSize * 2), - Image::fromUrl({TWITCH_CHANNEL_POINT_REWARD_URL("4.png")}, 0.25, + Image::fromUrl({twitchChannelPointRewardUrl("4.png")}, 0.25, baseSize * 4)}; this->image = defaultImage; } diff --git a/src/providers/twitch/ChannelPointReward.hpp b/src/providers/twitch/ChannelPointReward.hpp index d4f428e92..6fdd985b6 100644 --- a/src/providers/twitch/ChannelPointReward.hpp +++ b/src/providers/twitch/ChannelPointReward.hpp @@ -1,15 +1,11 @@ #pragma once -#include "common/Aliases.hpp" #include "messages/ImageSet.hpp" #include -#define TWITCH_CHANNEL_POINT_REWARD_URL(x) \ - QString("https://static-cdn.jtvnw.net/custom-reward-images/default-%1") \ - .arg(x) - namespace chatterino { + struct ChannelPointReward { ChannelPointReward(const QJsonObject &redemption); ChannelPointReward() = delete; diff --git a/src/providers/twitch/TwitchEmotes.cpp b/src/providers/twitch/TwitchEmotes.cpp index 4baa13f20..b7ba9f54a 100644 --- a/src/providers/twitch/TwitchEmotes.cpp +++ b/src/providers/twitch/TwitchEmotes.cpp @@ -11,9 +11,7 @@ using namespace chatterino; Url getEmoteLink(const EmoteId &id, const QString &emoteScale) { - return {QString(TWITCH_EMOTE_TEMPLATE) - .replace("{id}", id.string) - .replace("{scale}", emoteScale)}; + return {TWITCH_EMOTE_TEMPLATE.arg(id.string, emoteScale)}; } QSize getEmoteExpectedBaseSize(const EmoteId &id) diff --git a/src/providers/twitch/TwitchEmotes.hpp b/src/providers/twitch/TwitchEmotes.hpp index 17e50b11f..f7691131c 100644 --- a/src/providers/twitch/TwitchEmotes.hpp +++ b/src/providers/twitch/TwitchEmotes.hpp @@ -10,12 +10,15 @@ #include #include +namespace chatterino { + // NB: "default" can be replaced with "static" to always get a non-animated // variant -#define TWITCH_EMOTE_TEMPLATE \ - "https://static-cdn.jtvnw.net/emoticons/v2/{id}/default/dark/{scale}" +/// %1 <-> {id} +/// %2 <-> {scale} (1.0, 2.0, 3.0) +constexpr QStringView TWITCH_EMOTE_TEMPLATE = + u"https://static-cdn.jtvnw.net/emoticons/v2/%1/default/dark/%2"; -namespace chatterino { struct Emote; using EmotePtr = std::shared_ptr; diff --git a/src/providers/twitch/api/Helix.hpp b/src/providers/twitch/api/Helix.hpp index 346c9f3c3..aa95f1e32 100644 --- a/src/providers/twitch/api/Helix.hpp +++ b/src/providers/twitch/api/Helix.hpp @@ -276,9 +276,7 @@ struct HelixChannelEmote { , name(jsonObject.value("name").toString()) , type(jsonObject.value("emote_type").toString()) , setId(jsonObject.value("emote_set_id").toString()) - , url(QString(TWITCH_EMOTE_TEMPLATE) - .replace("{id}", this->emoteId) - .replace("{scale}", "3.0")) + , url(TWITCH_EMOTE_TEMPLATE.arg(this->emoteId, u"3.0")) { } }; diff --git a/src/singletons/ImageUploader.cpp b/src/singletons/ImageUploader.cpp index b5fe9c43a..ebf39a958 100644 --- a/src/singletons/ImageUploader.cpp +++ b/src/singletons/ImageUploader.cpp @@ -24,11 +24,11 @@ #include -#define UPLOAD_DELAY 2000 -// Delay between uploads in milliseconds - namespace { +// Delay between uploads in milliseconds +constexpr int UPLOAD_DELAY = 2000; + std::optional convertToPng(const QImage &image) { QByteArray imageData; diff --git a/src/singletons/Theme.cpp b/src/singletons/Theme.cpp index bbd29abf9..8f1045e0c 100644 --- a/src/singletons/Theme.cpp +++ b/src/singletons/Theme.cpp @@ -1,4 +1,3 @@ - #include "singletons/Theme.hpp" #include "Application.hpp" diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index 26a82543a..7e21dc2c3 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -1,4 +1,4 @@ -#include "Toasts.hpp" +#include "singletons/Toasts.hpp" #include "Application.hpp" #include "common/Common.hpp" @@ -83,19 +83,17 @@ bool Toasts::isEnabled() QString Toasts::findStringFromReaction(const ToastReaction &reaction) { - // The constants are macros right now, but we want to avoid ASCII casts, - // so we're concatenating them with a QString literal - effectively making them part of it. switch (reaction) { case ToastReaction::OpenInBrowser: - return OPEN_IN_BROWSER u""_s; + return OPEN_IN_BROWSER; case ToastReaction::OpenInPlayer: - return OPEN_PLAYER_IN_BROWSER u""_s; + return OPEN_PLAYER_IN_BROWSER; case ToastReaction::OpenInStreamlink: - return OPEN_IN_STREAMLINK u""_s; + return OPEN_IN_STREAMLINK; case ToastReaction::DontOpen: default: - return DONT_OPEN u""_s; + return DONT_OPEN; } } diff --git a/src/singletons/Updates.cpp b/src/singletons/Updates.cpp index 0a7351491..35b625659 100644 --- a/src/singletons/Updates.cpp +++ b/src/singletons/Updates.cpp @@ -1,12 +1,13 @@ -#include "Updates.hpp" +#include "singletons/Updates.hpp" +#include "common/Literals.hpp" #include "common/Modes.hpp" #include "common/network/NetworkRequest.hpp" #include "common/network/NetworkResult.hpp" #include "common/QLogging.hpp" #include "common/Version.hpp" -#include "Settings.hpp" #include "singletons/Paths.hpp" +#include "singletons/Settings.hpp" #include "util/CombinePath.hpp" #include "util/PostToThread.hpp" @@ -15,16 +16,34 @@ #include #include #include +#include #include -namespace chatterino { namespace { - QString currentBranch() - { - return getSettings()->betaUpdates ? "beta" : "stable"; - } + +using namespace chatterino; +using namespace literals; + +QString currentBranch() +{ + return getSettings()->betaUpdates ? "beta" : "stable"; +} + +#if defined(Q_OS_WIN) +const QString CHATTERINO_OS = u"win"_s; +#elif defined(Q_OS_MACOS) +const QString CHATTERINO_OS = u"macos"_s; +#elif defined(Q_OS_LINUX) +const QString CHATTERINO_OS = u"linux"_s; +#elif defined(Q_OS_FREEBSD) +const QString CHATTERINO_OS = u"freebsd"_s; +#else +const QString CHATTERINO_OS = u"unknown"_s; +#endif +; } // namespace +namespace chatterino { Updates::Updates(const Paths &paths_) : paths(paths_) @@ -262,9 +281,8 @@ void Updates::checkForUpdates() return; } - QString url = - "https://notitia.chatterino.com/version/chatterino/" CHATTERINO_OS "/" + - currentBranch(); + QString url = "https://notitia.chatterino.com/version/chatterino/" % + CHATTERINO_OS % "/" % currentBranch(); NetworkRequest(url) .timeout(60000) diff --git a/src/util/DisplayBadge.cpp b/src/util/DisplayBadge.cpp index cf56634fa..733633339 100644 --- a/src/util/DisplayBadge.cpp +++ b/src/util/DisplayBadge.cpp @@ -1,4 +1,4 @@ -#include "DisplayBadge.hpp" +#include "util/DisplayBadge.hpp" namespace chatterino { DisplayBadge::DisplayBadge(QString displayName, QString badgeName) diff --git a/src/util/FunctionEventFilter.cpp b/src/util/FunctionEventFilter.cpp index 5071e6e9b..33a41a2c6 100644 --- a/src/util/FunctionEventFilter.cpp +++ b/src/util/FunctionEventFilter.cpp @@ -1,4 +1,4 @@ -#include "FunctionEventFilter.hpp" +#include "util/FunctionEventFilter.hpp" namespace chatterino { diff --git a/src/util/FuzzyConvert.cpp b/src/util/FuzzyConvert.cpp index 2d62e5648..0870b711a 100644 --- a/src/util/FuzzyConvert.cpp +++ b/src/util/FuzzyConvert.cpp @@ -1,4 +1,4 @@ -#include "FuzzyConvert.hpp" +#include "util/FuzzyConvert.hpp" #include diff --git a/src/util/Helpers.cpp b/src/util/Helpers.cpp index 836214d05..88ba17fe1 100644 --- a/src/util/Helpers.cpp +++ b/src/util/Helpers.cpp @@ -1,4 +1,4 @@ -#include "Helpers.hpp" +#include "util/Helpers.hpp" #include "providers/twitch/TwitchCommon.hpp" diff --git a/src/util/RatelimitBucket.cpp b/src/util/RatelimitBucket.cpp index c33f3a30a..75bf8e344 100644 --- a/src/util/RatelimitBucket.cpp +++ b/src/util/RatelimitBucket.cpp @@ -1,4 +1,4 @@ -#include "RatelimitBucket.hpp" +#include "util/RatelimitBucket.hpp" #include diff --git a/src/util/SampleData.cpp b/src/util/SampleData.cpp index 0b976f190..7b12cd31c 100644 --- a/src/util/SampleData.cpp +++ b/src/util/SampleData.cpp @@ -1,4 +1,4 @@ -#include "SampleData.hpp" +#include "util/SampleData.hpp" namespace chatterino { diff --git a/src/widgets/AccountSwitchWidget.cpp b/src/widgets/AccountSwitchWidget.cpp index 19dbc678b..01fc161bc 100644 --- a/src/widgets/AccountSwitchWidget.cpp +++ b/src/widgets/AccountSwitchWidget.cpp @@ -1,4 +1,4 @@ -#include "AccountSwitchWidget.hpp" +#include "widgets/AccountSwitchWidget.hpp" #include "Application.hpp" #include "common/Common.hpp" diff --git a/src/widgets/TooltipWidget.cpp b/src/widgets/TooltipWidget.cpp index 14328e91f..64b3bec82 100644 --- a/src/widgets/TooltipWidget.cpp +++ b/src/widgets/TooltipWidget.cpp @@ -7,11 +7,11 @@ #include -// number of columns in grid mode -#define GRID_NUM_COLS 3 - namespace { +// number of columns in grid mode +constexpr int GRID_NUM_COLS = 3; + #ifdef Q_OS_WIN template inline constexpr T *tooltipParentFor(T * /*desiredParent*/) diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index ee836d185..4374881fd 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -737,19 +737,19 @@ void Window::addMenuBar() // Help->Chatterino Wiki item QAction *helpWiki = helpMenu->addAction(QString("Chatterino Wiki")); connect(helpWiki, &QAction::triggered, this, []() { - QDesktopServices::openUrl(QUrl(LINK_CHATTERINO_WIKI)); + QDesktopServices::openUrl(QUrl(LINK_CHATTERINO_WIKI.toString())); }); // Help->Chatterino Github QAction *helpGithub = helpMenu->addAction(QString("Chatterino GitHub")); connect(helpGithub, &QAction::triggered, this, []() { - QDesktopServices::openUrl(QUrl(LINK_CHATTERINO_SOURCE)); + QDesktopServices::openUrl(QUrl(LINK_CHATTERINO_SOURCE.toString())); }); // Help->Chatterino Discord QAction *helpDiscord = helpMenu->addAction(QString("Chatterino Discord")); connect(helpDiscord, &QAction::triggered, this, []() { - QDesktopServices::openUrl(QUrl(LINK_CHATTERINO_DISCORD)); + QDesktopServices::openUrl(QUrl(LINK_CHATTERINO_DISCORD.toString())); }); } diff --git a/src/widgets/dialogs/BadgePickerDialog.cpp b/src/widgets/dialogs/BadgePickerDialog.cpp index f45dbbbf1..e90c66b51 100644 --- a/src/widgets/dialogs/BadgePickerDialog.cpp +++ b/src/widgets/dialogs/BadgePickerDialog.cpp @@ -1,4 +1,4 @@ -#include "BadgePickerDialog.hpp" +#include "widgets/dialogs/BadgePickerDialog.hpp" #include "Application.hpp" #include "providers/twitch/TwitchBadges.hpp" diff --git a/src/widgets/dialogs/EmotePopup.cpp b/src/widgets/dialogs/EmotePopup.cpp index eb789249a..8936549e6 100644 --- a/src/widgets/dialogs/EmotePopup.cpp +++ b/src/widgets/dialogs/EmotePopup.cpp @@ -1,4 +1,4 @@ -#include "EmotePopup.hpp" +#include "widgets/dialogs/EmotePopup.hpp" #include "Application.hpp" #include "common/QLogging.hpp" diff --git a/src/widgets/dialogs/IrcConnectionEditor.cpp b/src/widgets/dialogs/IrcConnectionEditor.cpp index 63e6bfa2d..8ebfd8f95 100644 --- a/src/widgets/dialogs/IrcConnectionEditor.cpp +++ b/src/widgets/dialogs/IrcConnectionEditor.cpp @@ -1,4 +1,4 @@ -#include "IrcConnectionEditor.hpp" +#include "widgets/dialogs/IrcConnectionEditor.hpp" #include "ui_IrcConnectionEditor.h" diff --git a/src/widgets/dialogs/QualityPopup.cpp b/src/widgets/dialogs/QualityPopup.cpp index e08d25208..9feec4f33 100644 --- a/src/widgets/dialogs/QualityPopup.cpp +++ b/src/widgets/dialogs/QualityPopup.cpp @@ -1,4 +1,4 @@ -#include "QualityPopup.hpp" +#include "widgets/dialogs/QualityPopup.hpp" #include "Application.hpp" #include "common/QLogging.hpp" diff --git a/src/widgets/dialogs/SelectChannelDialog.cpp b/src/widgets/dialogs/SelectChannelDialog.cpp index 1eb33c172..728caac8b 100644 --- a/src/widgets/dialogs/SelectChannelDialog.cpp +++ b/src/widgets/dialogs/SelectChannelDialog.cpp @@ -1,4 +1,4 @@ -#include "SelectChannelDialog.hpp" +#include "widgets/dialogs/SelectChannelDialog.hpp" #include "Application.hpp" #include "common/QLogging.hpp" @@ -25,11 +25,11 @@ #include #include -#define TAB_TWITCH 0 -#define TAB_IRC 1 - namespace chatterino { +constexpr int TAB_TWITCH = 0; +constexpr int TAB_IRC = 1; + SelectChannelDialog::SelectChannelDialog(QWidget *parent) : BaseWindow( { diff --git a/src/widgets/dialogs/SelectChannelFiltersDialog.cpp b/src/widgets/dialogs/SelectChannelFiltersDialog.cpp index 78c597c02..e0acb8523 100644 --- a/src/widgets/dialogs/SelectChannelFiltersDialog.cpp +++ b/src/widgets/dialogs/SelectChannelFiltersDialog.cpp @@ -1,4 +1,4 @@ -#include "SelectChannelFiltersDialog.hpp" +#include "widgets/dialogs/SelectChannelFiltersDialog.hpp" #include "controllers/filters/FilterRecord.hpp" #include "singletons/Settings.hpp" diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index 89d43da37..a25cf7633 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -38,101 +38,104 @@ #include #include #include +#include -const QString TEXT_FOLLOWERS("Followers: %1"); -const QString TEXT_CREATED("Created: %1"); -const QString TEXT_TITLE("%1's Usercard - #%2"); -#define TEXT_USER_ID "ID: " -#define TEXT_UNAVAILABLE "(not available)" - -namespace chatterino { namespace { - Label *addCopyableLabel(LayoutCreator box, const char *tooltip, - Button **copyButton = nullptr) + +constexpr QStringView TEXT_FOLLOWERS = u"Followers: %1"; +constexpr QStringView TEXT_CREATED = u"Created: %1"; +constexpr QStringView TEXT_TITLE = u"%1's Usercard - #%2"; +constexpr QStringView TEXT_USER_ID = u"ID: "; +constexpr QStringView TEXT_UNAVAILABLE = u"(not available)"; + +using namespace chatterino; + +Label *addCopyableLabel(LayoutCreator box, const char *tooltip, + Button **copyButton = nullptr) +{ + auto label = box.emplace