From 8ceb1001775cc57b695424cc74b51bf30e946438 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 18 Jul 2021 12:14:01 +0200 Subject: [PATCH 01/14] Add tests for `getEmoteSetBatches` (#3036) --- src/providers/twitch/TwitchAccount.cpp | 5 +- src/providers/twitch/TwitchAccount.hpp | 2 + tests/CMakeLists.txt | 1 + tests/src/TwitchAccount.cpp | 157 +++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 tests/src/TwitchAccount.cpp diff --git a/src/providers/twitch/TwitchAccount.cpp b/src/providers/twitch/TwitchAccount.cpp index af8627a6539..416d5ba619b 100644 --- a/src/providers/twitch/TwitchAccount.cpp +++ b/src/providers/twitch/TwitchAccount.cpp @@ -21,7 +21,7 @@ #include "util/QStringHash.hpp" #include "util/RapidjsonHelpers.hpp" -namespace { +namespace chatterino { std::vector getEmoteSetBatches(QStringList emoteSetKeys) { @@ -48,9 +48,6 @@ std::vector getEmoteSetBatches(QStringList emoteSetKeys) return batches; } -} // namespace - -namespace chatterino { TwitchAccount::TwitchAccount(const QString &username, const QString &oauthToken, const QString &oauthClient, const QString &userID) : Account(ProviderId::Twitch) diff --git a/src/providers/twitch/TwitchAccount.hpp b/src/providers/twitch/TwitchAccount.hpp index 4c203dad6f2..af56afaf1cb 100644 --- a/src/providers/twitch/TwitchAccount.hpp +++ b/src/providers/twitch/TwitchAccount.hpp @@ -51,6 +51,8 @@ struct TwitchEmoteSetResolverResponse { } }; +std::vector getEmoteSetBatches(QStringList emoteSetKeys); + class TwitchAccount : public Account { public: diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 52e8560f7b1..1736e89dc77 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ set(test_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/HighlightPhrase.cpp ${CMAKE_CURRENT_LIST_DIR}/src/Emojis.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ExponentialBackoff.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/TwitchAccount.cpp ) add_executable(${PROJECT_NAME} ${test_SOURCES}) diff --git a/tests/src/TwitchAccount.cpp b/tests/src/TwitchAccount.cpp new file mode 100644 index 00000000000..bb7e400fa89 --- /dev/null +++ b/tests/src/TwitchAccount.cpp @@ -0,0 +1,157 @@ +#include "providers/twitch/TwitchAccount.hpp" + +#include + +using namespace chatterino; + +TEST(TwitchAccount, BatchTwoParts) +{ + QStringList bigList{ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", + "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", + "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", + "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", + "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", + "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", + "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", + "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", + "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", + "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", + "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", + "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", + "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", + "141", "142", "143", "144", "145", "146", "147", "148", "149", "150", + }; + + std::vector expectation = { + { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", + "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", + "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", + "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", + "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", + "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", + "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", + "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", + "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", + }, + { + "101", "102", "103", "104", "105", "106", "107", "108", "109", + "110", "111", "112", "113", "114", "115", "116", "117", "118", + "119", "120", "121", "122", "123", "124", "125", "126", "127", + "128", "129", "130", "131", "132", "133", "134", "135", "136", + "137", "138", "139", "140", "141", "142", "143", "144", "145", + "146", "147", "148", "149", "150", + }, + }; + + auto result = getEmoteSetBatches(bigList); + + EXPECT_EQ(result, expectation); +} + +TEST(TwitchAccount, NotEnoughForMoreThanOneBatch) +{ + QStringList bigList{ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", + "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", + "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", + "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", + "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", + "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", + "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", + "85", "86", "87", "88", "89", "90", + }; + + std::vector expectation = { + { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", + "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", + "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", + "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", + "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", + "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", + "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", + "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", + }, + }; + + auto result = getEmoteSetBatches(bigList); + + EXPECT_EQ(result, expectation); +} + +TEST(TwitchAccount, BatchThreeParts) +{ + QStringList bigList{ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", + "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", + "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", + "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", + "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", + "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", + "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", + "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", + "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", + "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", + "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", + "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", + "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", + "141", "142", "143", "144", "145", "146", "147", "148", "149", "150", + "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", + "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", + "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", + "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", + "191", "192", "193", "194", "195", "196", "197", "198", "199", "200", + "201", "202", "203", "204", "205", "206", "207", "208", "209", "210", + "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", + "221", "222", "223", "224", "225", "226", "227", "228", "229", "230", + "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", + "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", + }; + + std::vector expectation = { + { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", + "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", + "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", + "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", + "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", + "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", + "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", + "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", + "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", + }, + { + "101", "102", "103", "104", "105", "106", "107", "108", "109", + "110", "111", "112", "113", "114", "115", "116", "117", "118", + "119", "120", "121", "122", "123", "124", "125", "126", "127", + "128", "129", "130", "131", "132", "133", "134", "135", "136", + "137", "138", "139", "140", "141", "142", "143", "144", "145", + "146", "147", "148", "149", "150", "151", "152", "153", "154", + "155", "156", "157", "158", "159", "160", "161", "162", "163", + "164", "165", "166", "167", "168", "169", "170", "171", "172", + "173", "174", "175", "176", "177", "178", "179", "180", "181", + "182", "183", "184", "185", "186", "187", "188", "189", "190", + "191", "192", "193", "194", "195", "196", "197", "198", "199", + "200", + }, + { + "201", "202", "203", "204", "205", "206", "207", "208", "209", + "210", "211", "212", "213", "214", "215", "216", "217", "218", + "219", "220", "221", "222", "223", "224", "225", "226", "227", + "228", "229", "230", "231", "232", "233", "234", "235", "236", + "237", "238", "239", "240", "241", "242", "243", "244", "245", + "246", "247", "248", "249", "250", + }, + }; + + auto result = getEmoteSetBatches(bigList); + + EXPECT_EQ(result, expectation); +} From 1f19d31a674ad29c0ac1aaa21ef78b9e209fc80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Sun, 18 Jul 2021 14:15:38 +0200 Subject: [PATCH 02/14] Added informative messages on issues related to recent-messages (#3029) --- CHANGELOG.md | 1 + src/providers/twitch/TwitchChannel.cpp | 40 ++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecd3acb1437..b9411ef4b4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Minor: Added autocompletion in /whispers for Twitch emotes, Global Bttv/Ffz emotes and emojis. (#2999, #3033) - Minor: Received Twitch messages now use the exact same timestamp (obtained from Twitch's server) for every Chatterino user instead of assuming message timestamp on client's side. (#3021) - Minor: Received IRC messages use `time` message tag for timestamp if it's available. (#3021) +- Minor: Added informative messages for recent-messages API's errors. (#3029) - Bugfix: Fixed "smiley" emotes being unable to be "Tabbed" with autocompletion, introduced in v2.3.3. (#3010) - Dev: Ubuntu packages are now available (#2936) diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 884d20140ff..326ae9b5341 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -761,13 +761,16 @@ void TwitchChannel::loadRecentMessages() .arg(baseURL) .arg(getSettings()->twitchMessageHistoryLimit); + auto weak = weakOf(this); + NetworkRequest(url) - .onSuccess([weak = weakOf(this)](auto result) -> Outcome { + .onSuccess([this, weak](NetworkResult result) -> Outcome { auto shared = weak.lock(); if (!shared) return Failure; - auto messages = parseRecentMessages(result.parseJson(), shared); + auto root = result.parseJson(); + auto messages = parseRecentMessages(root, shared); auto &handler = IrcMessageHandler::instance(); @@ -801,13 +804,38 @@ void TwitchChannel::loadRecentMessages() } } - postToThread( - [shared, messages = std::move(allBuiltMessages)]() mutable { - shared->addMessagesAtStart(messages); - }); + postToThread([this, shared, root, + messages = std::move(allBuiltMessages)]() mutable { + shared->addMessagesAtStart(messages); + + // Notify user about a possible gap in logs if it returned some messages + // but isn't currently joined to a channel + if (QString errorCode = root.value("error_code").toString(); + !errorCode.isEmpty()) + { + qCDebug(chatterinoTwitch) + << QString("rm error_code=%1, channel=%2") + .arg(errorCode, this->getName()); + if (errorCode == "channel_not_joined" && !messages.empty()) + { + shared->addMessage(makeSystemMessage( + "Message history service recovering, there may be " + "gaps in the message history.")); + } + } + }); return Success; }) + .onError([weak](NetworkResult result) { + auto shared = weak.lock(); + if (!shared) + return; + + shared->addMessage(makeSystemMessage( + QString("Message history service unavailable (Error %1)") + .arg(result.status()))); + }) .execute(); } From e5fe0999eea5743068d774a28a243a2b4f62d950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Sun, 18 Jul 2021 14:37:53 +0200 Subject: [PATCH 03/14] Replace std::string with QString in rapidjson and PubSub Client (#3018) --- src/providers/twitch/PubsubClient.cpp | 88 +++++++++++++-------------- src/providers/twitch/PubsubClient.hpp | 8 +-- src/util/RapidjsonHelpers.cpp | 4 +- src/util/RapidjsonHelpers.hpp | 2 +- 4 files changed, 49 insertions(+), 53 deletions(-) diff --git a/src/providers/twitch/PubsubClient.cpp b/src/providers/twitch/PubsubClient.cpp index 012c7ffadd9..1dfcd02e9c8 100644 --- a/src/providers/twitch/PubsubClient.cpp +++ b/src/providers/twitch/PubsubClient.cpp @@ -23,7 +23,7 @@ namespace chatterino { static const char *pingPayload = "{\"type\":\"PING\"}"; -static std::map sentMessages; +static std::map sentMessages; namespace detail { @@ -72,10 +72,10 @@ namespace detail { rj::set(message, "nonce", uuid); - std::string payload = rj::stringify(message); + QString payload = rj::stringify(message); sentMessages[uuid] = payload; - this->send(payload.c_str()); + this->send(payload.toUtf8()); return true; } @@ -109,10 +109,10 @@ namespace detail { rj::set(message, "nonce", generateUuid()); - std::string payload = rj::stringify(message); + QString payload = rj::stringify(message); sentMessages[uuid] = payload; - this->send(payload.c_str()); + this->send(payload.toUtf8()); } void PubSubClient::handlePong() @@ -829,20 +829,17 @@ PubSub::PubSub() // this->signals_.moderation.automodUserMessage.invoke(action); // }; - this->moderationActionHandlers["denied_automod_message"] = [](const auto - &data, - const auto - &roomID) { - // This message got denied by a moderator - // qCDebug(chatterinoPubsub) << QString::fromStdString(rj::stringify(data)); - }; + this->moderationActionHandlers["denied_automod_message"] = + [](const auto &data, const auto &roomID) { + // This message got denied by a moderator + // qCDebug(chatterinoPubsub) << rj::stringify(data); + }; - this->moderationActionHandlers - ["approved_automod_message"] = [](const auto &data, - const auto &roomID) { - // This message got approved by a moderator - // qCDebug(chatterinoPubsub) << QString::fromStdString(rj::stringify(data)); - }; + this->moderationActionHandlers["approved_automod_message"] = + [](const auto &data, const auto &roomID) { + // This message got approved by a moderator + // qCDebug(chatterinoPubsub) << rj::stringify(data); + }; this->websocketClient.set_access_channels(websocketpp::log::alevel::all); this->websocketClient.clear_access_channels( @@ -930,7 +927,7 @@ void PubSub::listenToChannelModerationActions( if (userID.isEmpty()) return; - auto topic = topicFormat.arg(userID).arg(channelID); + auto topic = topicFormat.arg(userID, channelID); if (this->isListeningToTopic(topic)) { @@ -952,7 +949,7 @@ void PubSub::listenToAutomod(const QString &channelID, if (userID.isEmpty()) return; - auto topic = topicFormat.arg(userID).arg(channelID); + auto topic = topicFormat.arg(userID, channelID); if (this->isListeningToTopic(topic)) { @@ -970,7 +967,6 @@ void PubSub::listenToChannelPointRewards(const QString &channelID, static const QString topicFormat("community-points-channel-v1.%1"); assert(!channelID.isEmpty()); assert(account != nullptr); - QString userID = account->getUserId(); auto topic = topicFormat.arg(channelID); @@ -1035,26 +1031,27 @@ bool PubSub::isListeningToTopic(const QString &topic) void PubSub::onMessage(websocketpp::connection_hdl hdl, WebsocketMessagePtr websocketMessage) { - const std::string &payload = websocketMessage->get_payload(); + const auto &payload = + QString::fromStdString(websocketMessage->get_payload()); rapidjson::Document msg; - rapidjson::ParseResult res = msg.Parse(payload.c_str()); + rapidjson::ParseResult res = msg.Parse(payload.toUtf8()); if (!res) { qCDebug(chatterinoPubsub) - << "Error parsing message '" << payload.c_str() - << "' from PubSub:" << rapidjson::GetParseError_En(res.Code()); + << QString("Error parsing message '%1' from PubSub: %2") + .arg(payload, rapidjson::GetParseError_En(res.Code())); return; } if (!msg.IsObject()) { qCDebug(chatterinoPubsub) - << "Error parsing message '" << payload.c_str() - << "' from PubSub. Root object is not an " - "object"; + << QString("Error parsing message '%1' from PubSub. Root object is " + "not an object") + .arg(payload); return; } @@ -1198,7 +1195,7 @@ void PubSub::handleListenResponse(const rapidjson::Document &msg) void PubSub::handleMessageResponse(const rapidjson::Value &outerData) { QString topic; - qCDebug(chatterinoPubsub) << rj::stringify(outerData).c_str(); + qCDebug(chatterinoPubsub) << rj::stringify(outerData); if (!rj::getSafe(outerData, "topic", topic)) { @@ -1207,7 +1204,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) return; } - std::string payload; + QString payload; if (!rj::getSafe(outerData, "message", payload)) { @@ -1217,19 +1214,19 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) rapidjson::Document msg; - rapidjson::ParseResult res = msg.Parse(payload.c_str()); + rapidjson::ParseResult res = msg.Parse(payload.toUtf8()); if (!res) { qCDebug(chatterinoPubsub) - << "Error parsing message '" << payload.c_str() - << "' from PubSub:" << rapidjson::GetParseError_En(res.Code()); + << QString("Error parsing message '%1' from PubSub: %2") + .arg(payload, rapidjson::GetParseError_En(res.Code())); return; } if (topic.startsWith("whispers.")) { - std::string whisperType; + QString whisperType; if (!rj::getSafe(msg, "type", whisperType)) { @@ -1251,8 +1248,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) } else { - qCDebug(chatterinoPubsub) - << "Invalid whisper type:" << whisperType.c_str(); + qCDebug(chatterinoPubsub) << "Invalid whisper type:" << whisperType; return; } } @@ -1262,7 +1258,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) assert(topicParts.length() == 3); const auto &data = msg["data"]; - std::string moderationEventType; + QString moderationEventType; if (!rj::getSafe(msg, "type", moderationEventType)) { @@ -1271,13 +1267,13 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) } if (moderationEventType == "moderation_action") { - std::string moderationAction; + QString moderationAction; if (!rj::getSafe(data, "moderation_action", moderationAction)) { qCDebug(chatterinoPubsub) << "Missing moderation action in data:" - << rj::stringify(data).c_str(); + << rj::stringify(data); return; } @@ -1288,7 +1284,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) { qCDebug(chatterinoPubsub) << "No handler found for moderation action" - << moderationAction.c_str(); + << moderationAction; return; } // Invoke handler function @@ -1296,13 +1292,13 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) } else if (moderationEventType == "channel_terms_action") { - std::string channelTermsAction; + QString channelTermsAction; if (!rj::getSafe(data, "type", channelTermsAction)) { qCDebug(chatterinoPubsub) << "Missing channel terms action in data:" - << rj::stringify(data).c_str(); + << rj::stringify(data); return; } @@ -1313,7 +1309,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) { qCDebug(chatterinoPubsub) << "No handler found for channel terms action" - << channelTermsAction.c_str(); + << channelTermsAction; return; } // Invoke handler function @@ -1322,7 +1318,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) } else if (topic.startsWith("community-points-channel-v1.")) { - std::string pointEventType; + QString pointEventType; if (!rj::getSafe(msg, "type", pointEventType)) { qCDebug(chatterinoPubsub) << "Bad channel point event data"; @@ -1348,7 +1344,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) else { qCDebug(chatterinoPubsub) - << "Invalid point event type:" << pointEventType.c_str(); + << "Invalid point event type:" << pointEventType; } } else if (topic.startsWith("automod-queue.")) @@ -1357,7 +1353,7 @@ void PubSub::handleMessageResponse(const rapidjson::Value &outerData) assert(topicParts.length() == 3); auto &data = msg["data"]; - std::string automodEventType; + QString automodEventType; if (!rj::getSafe(msg, "type", automodEventType)) { qCDebug(chatterinoPubsub) << "Bad automod event data"; diff --git a/src/providers/twitch/PubsubClient.hpp b/src/providers/twitch/PubsubClient.hpp index ab068b74380..1e5a01d1f29 100644 --- a/src/providers/twitch/PubsubClient.hpp +++ b/src/providers/twitch/PubsubClient.hpp @@ -179,12 +179,12 @@ class PubSub std::owner_less> clients; - std::unordered_map> + std::unordered_map< + QString, std::function> moderationActionHandlers; - std::unordered_map> + std::unordered_map< + QString, std::function> channelTermsActionHandlers; void onMessage(websocketpp::connection_hdl hdl, WebsocketMessagePtr msg); diff --git a/src/util/RapidjsonHelpers.cpp b/src/util/RapidjsonHelpers.cpp index b75f9ca4f9a..fb61219c9c3 100644 --- a/src/util/RapidjsonHelpers.cpp +++ b/src/util/RapidjsonHelpers.cpp @@ -19,13 +19,13 @@ namespace rj { obj.AddMember(rapidjson::Value(key, a).Move(), value.Move(), a); } - std::string stringify(const rapidjson::Value &value) + QString stringify(const rapidjson::Value &value) { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); value.Accept(writer); - return std::string(buffer.GetString()); + return buffer.GetString(); } bool getSafeObject(rapidjson::Value &obj, const char *key, diff --git a/src/util/RapidjsonHelpers.hpp b/src/util/RapidjsonHelpers.hpp index 6088b44caf7..403bbb5827e 100644 --- a/src/util/RapidjsonHelpers.hpp +++ b/src/util/RapidjsonHelpers.hpp @@ -95,7 +95,7 @@ namespace rj { bool getSafeObject(rapidjson::Value &obj, const char *key, rapidjson::Value &out); - std::string stringify(const rapidjson::Value &value); + QString stringify(const rapidjson::Value &value); } // namespace rj } // namespace chatterino From ae9f92ded95005d36cc80c9d37fdae40d077b611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Sun, 18 Jul 2021 15:21:09 +0200 Subject: [PATCH 04/14] Make use of QUrlQuery in NetworkRequests where it was hardcoded into url (#3039) Co-authored-by: Rasmus Karlsson --- src/providers/twitch/TwitchBadges.cpp | 8 ++++++-- src/providers/twitch/TwitchChannel.cpp | 13 ++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/providers/twitch/TwitchBadges.cpp b/src/providers/twitch/TwitchBadges.cpp index 65481ab5d0e..4394da9e6a3 100644 --- a/src/providers/twitch/TwitchBadges.cpp +++ b/src/providers/twitch/TwitchBadges.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "common/NetworkRequest.hpp" #include "common/Outcome.hpp" @@ -24,8 +25,11 @@ void TwitchBadges::loadTwitchBadges() { assert(this->loaded_ == false); - static QString url( - "https://badges.twitch.tv/v1/badges/global/display?language=en"); + QUrl url("https://badges.twitch.tv/v1/badges/global/display"); + + QUrlQuery urlQuery; + urlQuery.addQueryItem("language", "en"); + url.setQuery(urlQuery); NetworkRequest(url) .onSuccess([this](auto result) -> Outcome { diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 326ae9b5341..4571cca22b8 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -755,11 +755,14 @@ void TwitchChannel::loadRecentMessages() return; } - auto baseURL = Env::get().recentMessagesApiUrl.arg(this->getName()); - - auto url = QString("%1?limit=%2") - .arg(baseURL) - .arg(getSettings()->twitchMessageHistoryLimit); + QUrl url(Env::get().recentMessagesApiUrl.arg(this->getName())); + QUrlQuery urlQuery(url); + if (!urlQuery.hasQueryItem("limit")) + { + urlQuery.addQueryItem( + "limit", QString::number(getSettings()->twitchMessageHistoryLimit)); + } + url.setQuery(urlQuery); auto weak = weakOf(this); From 588ed557f05b1da4143355643a8811fcaf4c8194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Sat, 24 Jul 2021 12:01:50 +0200 Subject: [PATCH 05/14] Fixed comma appended to username completion when not at the beginning of the message (#3060) Co-authored-by: pajlada --- CHANGELOG.md | 1 + src/common/CompletionModel.cpp | 14 +++++++------ src/util/Helpers.cpp | 13 ++++++++++++ src/util/Helpers.hpp | 10 +++++++++ src/widgets/helper/ChannelView.cpp | 11 ++++++++-- src/widgets/helper/ResizingTextEdit.cpp | 27 ++++++++++++++----------- src/widgets/helper/ResizingTextEdit.hpp | 1 + src/widgets/splits/Split.cpp | 5 +++++ src/widgets/splits/Split.hpp | 1 + src/widgets/splits/SplitInput.cpp | 12 +++++++++-- src/widgets/splits/SplitInput.hpp | 1 + tests/CMakeLists.txt | 1 + tests/src/Helpers.cpp | 22 ++++++++++++++++++++ 13 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 tests/src/Helpers.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index b9411ef4b4a..3c23d71dd65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Minor: Received IRC messages use `time` message tag for timestamp if it's available. (#3021) - Minor: Added informative messages for recent-messages API's errors. (#3029) - Bugfix: Fixed "smiley" emotes being unable to be "Tabbed" with autocompletion, introduced in v2.3.3. (#3010) +- Bugfix: Fixed comma appended to username completion when not at the beginning of the message. (#3060) - Dev: Ubuntu packages are now available (#2936) ## 2.3.3 diff --git a/src/common/CompletionModel.cpp b/src/common/CompletionModel.cpp index 078ae86a8a3..ac96b85b4d0 100644 --- a/src/common/CompletionModel.cpp +++ b/src/common/CompletionModel.cpp @@ -10,6 +10,7 @@ #include "providers/twitch/TwitchIrcServer.hpp" #include "singletons/Emotes.hpp" #include "singletons/Settings.hpp" +#include "util/Helpers.hpp" #include "util/QStringHash.hpp" #include @@ -150,9 +151,6 @@ void CompletionModel::refresh(const QString &prefix, bool isFirstWord) } // Usernames - QString usernamePostfix = - isFirstWord && getSettings()->mentionUsersWithComma ? "," : QString(); - if (prefix.startsWith("@")) { QString usernamePrefix = prefix; @@ -162,8 +160,10 @@ void CompletionModel::refresh(const QString &prefix, bool isFirstWord) for (const auto &name : chatters) { - addString("@" + name + usernamePostfix, - TaggedString::Type::Username); + addString( + "@" + formatUserMention(name, isFirstWord, + getSettings()->mentionUsersWithComma), + TaggedString::Type::Username); } } else if (!getSettings()->userCompletionOnlyWithAt) @@ -172,7 +172,9 @@ void CompletionModel::refresh(const QString &prefix, bool isFirstWord) for (const auto &name : chatters) { - addString(name + usernamePostfix, TaggedString::Type::Username); + addString(formatUserMention(name, isFirstWord, + getSettings()->mentionUsersWithComma), + TaggedString::Type::Username); } } diff --git a/src/util/Helpers.cpp b/src/util/Helpers.cpp index 5528ac23a5f..2f4d98db998 100644 --- a/src/util/Helpers.cpp +++ b/src/util/Helpers.cpp @@ -68,4 +68,17 @@ QColor getRandomColor(const QString &userId) return TWITCH_USERNAME_COLORS[colorIndex]; } +QString formatUserMention(const QString &userName, bool isFirstWord, + bool mentionUsersWithComma) +{ + QString result = userName; + + if (isFirstWord && mentionUsersWithComma) + { + result += ","; + } + + return result; +} + } // namespace chatterino diff --git a/src/util/Helpers.hpp b/src/util/Helpers.hpp index b30a3f33135..13247f010bc 100644 --- a/src/util/Helpers.hpp +++ b/src/util/Helpers.hpp @@ -20,4 +20,14 @@ QString kFormatNumbers(const int &number); QColor getRandomColor(const QString &userId); +/** + * @brief Takes a user's name and some formatting parameter and spits out the standardized way to format it + * + * @param userName a user's name + * @param isFirstWord signifies whether this mention would be the first word in a message + * @param mentionUsersWithComma postfix mentions with a comma. generally powered by getSettings()->mentionUsersWithComma + **/ +QString formatUserMention(const QString &userName, bool isFirstWord, + bool mentionUsersWithComma); + } // namespace chatterino diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 37945a86e8d..8f04bab29ce 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -37,6 +37,7 @@ #include "singletons/WindowManager.hpp" #include "util/Clipboard.hpp" #include "util/DistanceBetweenPoints.hpp" +#include "util/Helpers.hpp" #include "util/IncognitoBrowser.hpp" #include "util/StreamerMode.hpp" #include "util/Twitch.hpp" @@ -48,6 +49,7 @@ #include "widgets/helper/EffectLabel.hpp" #include "widgets/helper/SearchPopup.hpp" #include "widgets/splits/Split.hpp" +#include "widgets/splits/SplitInput.hpp" #define DRAW_WIDTH (this->width()) #define SELECTION_RESUME_SCROLLING_MSG_THRESHOLD 3 @@ -1804,8 +1806,9 @@ void ChannelView::handleMouseClick(QMouseEvent *event, } break; case Qt::RightButton: { + auto split = dynamic_cast(this->parentWidget()); auto insertText = [=](QString text) { - if (auto split = dynamic_cast(this->parentWidget())) + if (split) { split->insertTextToInput(text); } @@ -1815,7 +1818,11 @@ void ChannelView::handleMouseClick(QMouseEvent *event, if (link.type == Link::UserInfo) { const bool commaMention = getSettings()->mentionUsersWithComma; - insertText("@" + link.value + (commaMention ? ", " : " ")); + const bool isFirstWord = + split && split->getInput().isEditFirstWord(); + auto userMention = + formatUserMention(link.value, isFirstWord, commaMention); + insertText("@" + userMention + " "); } else if (link.type == Link::UserWhisper) { diff --git a/src/widgets/helper/ResizingTextEdit.cpp b/src/widgets/helper/ResizingTextEdit.cpp index 56c60a72285..896efed6659 100644 --- a/src/widgets/helper/ResizingTextEdit.cpp +++ b/src/widgets/helper/ResizingTextEdit.cpp @@ -39,6 +39,19 @@ bool ResizingTextEdit::hasHeightForWidth() const return true; } +bool ResizingTextEdit::isFirstWord() const +{ + QString plainText = this->toPlainText(); + for (int i = this->textCursor().position(); i >= 0; i--) + { + if (plainText[i] == ' ') + { + return false; + } + } + return true; +}; + int ResizingTextEdit::heightForWidth(int) const { auto margins = this->contentsMargins(); @@ -108,17 +121,6 @@ void ResizingTextEdit::keyPressEvent(QKeyEvent *event) } QString currentCompletionPrefix = this->textUnderCursor(); - bool isFirstWord = [&] { - QString plainText = this->toPlainText(); - for (int i = this->textCursor().position(); i >= 0; i--) - { - if (plainText[i] == ' ') - { - return false; - } - } - return true; - }(); // check if there is something to complete if (currentCompletionPrefix.size() <= 1) @@ -134,7 +136,8 @@ void ResizingTextEdit::keyPressEvent(QKeyEvent *event) // First type pressing tab after modifying a message, we refresh our // completion model this->completer_->setModel(completionModel); - completionModel->refresh(currentCompletionPrefix, isFirstWord); + completionModel->refresh(currentCompletionPrefix, + this->isFirstWord()); this->completionInProgress_ = true; this->completer_->setCompletionPrefix(currentCompletionPrefix); this->completer_->complete(); diff --git a/src/widgets/helper/ResizingTextEdit.hpp b/src/widgets/helper/ResizingTextEdit.hpp index cd1db3114af..d3726e27afd 100644 --- a/src/widgets/helper/ResizingTextEdit.hpp +++ b/src/widgets/helper/ResizingTextEdit.hpp @@ -15,6 +15,7 @@ class ResizingTextEdit : public QTextEdit QSize sizeHint() const override; bool hasHeightForWidth() const override; + bool isFirstWord() const; pajlada::Signals::Signal keyPressed; pajlada::Signals::NoArgSignal focused; diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index 02af885735a..e601d35abee 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -306,6 +306,11 @@ ChannelView &Split::getChannelView() return *this->view_; } +SplitInput &Split::getInput() +{ + return *this->input_; +} + void Split::updateInputPlaceholder() { if (!this->getChannel()->isTwitchChannel()) diff --git a/src/widgets/splits/Split.hpp b/src/widgets/splits/Split.hpp index 193f2f79676..4ca2f44461e 100644 --- a/src/widgets/splits/Split.hpp +++ b/src/widgets/splits/Split.hpp @@ -47,6 +47,7 @@ class Split : public BaseWidget, pajlada::Signals::SignalHolder pajlada::Signals::NoArgSignal focusLost; ChannelView &getChannelView(); + SplitInput &getInput(); IndirectChannel getIndirectChannel(); ChannelPtr getChannel(); diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 96cbafd8f68..41aea01328d 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -8,6 +8,7 @@ #include "singletons/Settings.hpp" #include "singletons/Theme.hpp" #include "util/Clamp.hpp" +#include "util/Helpers.hpp" #include "util/LayoutCreator.hpp" #include "widgets/Notebook.hpp" #include "widgets/Scrollbar.hpp" @@ -568,8 +569,10 @@ void SplitInput::insertCompletionText(const QString &input_) } else if (text[i] == '@') { - input = "@" + input_ + - (getSettings()->mentionUsersWithComma ? ", " : " "); + const auto userMention = + formatUserMention(input_, edit.isFirstWord(), + getSettings()->mentionUsersWithComma); + input = "@" + userMention + " "; done = true; } @@ -595,6 +598,11 @@ void SplitInput::clearSelection() this->ui_.textEdit->setTextCursor(c); } +bool SplitInput::isEditFirstWord() const +{ + return this->ui_.textEdit->isFirstWord(); +} + QString SplitInput::getInputText() const { return this->ui_.textEdit->toPlainText(); diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index 52e9b015db1..5dc54bdc5a4 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -28,6 +28,7 @@ class SplitInput : public BaseWidget SplitInput(Split *_chatWidget); void clearSelection(); + bool isEditFirstWord() const; QString getInputText() const; void insertText(const QString &text); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1736e89dc77..e7e2c96b046 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,6 +10,7 @@ set(test_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/Emojis.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ExponentialBackoff.cpp ${CMAKE_CURRENT_LIST_DIR}/src/TwitchAccount.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/Helpers.cpp ) add_executable(${PROJECT_NAME} ${test_SOURCES}) diff --git a/tests/src/Helpers.cpp b/tests/src/Helpers.cpp new file mode 100644 index 00000000000..9ed012cc4a0 --- /dev/null +++ b/tests/src/Helpers.cpp @@ -0,0 +1,22 @@ +#include "util/Helpers.hpp" + +#include + +using namespace chatterino; + +TEST(Helpers, formatUserMention) +{ + const auto userName = "pajlada"; + + // A user mention that is the first word, that has 'mention with comma' enabled should have a comma appended at the end. + EXPECT_EQ(formatUserMention(userName, true, true), "pajlada,"); + + // A user mention that is not the first word, but has 'mention with comma' enabled should not have a comma appended at the end. + EXPECT_EQ(formatUserMention(userName, false, true), "pajlada"); + + // A user mention that is the first word, but has 'mention with comma' disabled should not have a comma appended at the end. + EXPECT_EQ(formatUserMention(userName, true, false), "pajlada"); + + // A user mention that is neither the first word, nor has 'mention with comma' enabled should not have a comma appended at the end. + EXPECT_EQ(formatUserMention(userName, false, false), "pajlada"); +} From 706605c99e30bc95f0fac1b668b36729795bd586 Mon Sep 17 00:00:00 2001 From: Mm2PL Date: Sat, 24 Jul 2021 12:52:00 +0200 Subject: [PATCH 06/14] Remove copyDarkTheme.png which was an unused SVG file. (#3056) Co-authored-by: pajlada --- resources/buttons/copyDarkTheme.png | 124 ------------------------- resources/resources_autogenerated.qrc | 1 - src/autogenerated/ResourcesAutogen.cpp | 1 - src/autogenerated/ResourcesAutogen.hpp | 1 - 4 files changed, 127 deletions(-) delete mode 100644 resources/buttons/copyDarkTheme.png diff --git a/resources/buttons/copyDarkTheme.png b/resources/buttons/copyDarkTheme.png deleted file mode 100644 index e225ee4ea1f..00000000000 --- a/resources/buttons/copyDarkTheme.png +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - Trashcan top - - - - - - - diff --git a/resources/resources_autogenerated.qrc b/resources/resources_autogenerated.qrc index e84cf632081..c40edc9732b 100644 --- a/resources/resources_autogenerated.qrc +++ b/resources/resources_autogenerated.qrc @@ -14,7 +14,6 @@ buttons/banRed.png buttons/copyDark.png buttons/copyDark.svg - buttons/copyDarkTheme.png buttons/copyLight.png buttons/copyLight.svg buttons/emote.svg diff --git a/src/autogenerated/ResourcesAutogen.cpp b/src/autogenerated/ResourcesAutogen.cpp index 7298a9f76ed..d4b48b970de 100644 --- a/src/autogenerated/ResourcesAutogen.cpp +++ b/src/autogenerated/ResourcesAutogen.cpp @@ -15,7 +15,6 @@ Resources2::Resources2() this->buttons.ban = QPixmap(":/buttons/ban.png"); this->buttons.banRed = QPixmap(":/buttons/banRed.png"); this->buttons.copyDark = QPixmap(":/buttons/copyDark.png"); - this->buttons.copyDarkTheme = QPixmap(":/buttons/copyDarkTheme.png"); this->buttons.copyLight = QPixmap(":/buttons/copyLight.png"); this->buttons.menuDark = QPixmap(":/buttons/menuDark.png"); this->buttons.menuLight = QPixmap(":/buttons/menuLight.png"); diff --git a/src/autogenerated/ResourcesAutogen.hpp b/src/autogenerated/ResourcesAutogen.hpp index f832981ead6..7277cc681e6 100644 --- a/src/autogenerated/ResourcesAutogen.hpp +++ b/src/autogenerated/ResourcesAutogen.hpp @@ -22,7 +22,6 @@ class Resources2 : public Singleton QPixmap ban; QPixmap banRed; QPixmap copyDark; - QPixmap copyDarkTheme; QPixmap copyLight; QPixmap menuDark; QPixmap menuLight; From b8bd0a587d034b97a61515c2a2e25ed7a1a014e3 Mon Sep 17 00:00:00 2001 From: ilyazzz Date: Sat, 24 Jul 2021 14:30:21 +0300 Subject: [PATCH 07/14] Disable update checker on Flatpak (#3051) Co-authored-by: Felanbird <41973452+Felanbird@users.noreply.github.com> Co-authored-by: pajlada --- CHANGELOG.md | 1 + src/singletons/Updates.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c23d71dd65..e57bba73aee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Bugfix: Fixed "smiley" emotes being unable to be "Tabbed" with autocompletion, introduced in v2.3.3. (#3010) - Bugfix: Fixed comma appended to username completion when not at the beginning of the message. (#3060) - Dev: Ubuntu packages are now available (#2936) +- Dev: Disabled update checker on Flatpak. (#3051) ## 2.3.3 diff --git a/src/singletons/Updates.cpp b/src/singletons/Updates.cpp index 75e9275e1ca..5751b59cc5e 100644 --- a/src/singletons/Updates.cpp +++ b/src/singletons/Updates.cpp @@ -240,6 +240,12 @@ void Updates::checkForUpdates() return; } + // Disable updates on Flatpak + if (QFileInfo::exists("/.flatpak-info")) + { + return; + } + // Disable updates if on nightly if (Modes::instance().isNightly) { From f949d6d1540bcc0a8707aea79020a59f71b9fe7c Mon Sep 17 00:00:00 2001 From: Mm2PL Date: Sun, 25 Jul 2021 00:52:34 +0200 Subject: [PATCH 08/14] Add HTTP logging (#2991) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Co-authored-by: pajlada --- CHANGELOG.md | 1 + src/common/NetworkCommon.hpp | 7 +++++ src/common/NetworkPrivate.cpp | 50 +++++++++++++++++++++++++++++++++++ src/common/QLogging.cpp | 1 + src/common/QLogging.hpp | 1 + 5 files changed, 60 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e57bba73aee..8f29536b83a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Bugfix: Fixed comma appended to username completion when not at the beginning of the message. (#3060) - Dev: Ubuntu packages are now available (#2936) - Dev: Disabled update checker on Flatpak. (#3051) +- Dev: Add logging for HTTP requests (#2991) ## 2.3.3 diff --git a/src/common/NetworkCommon.hpp b/src/common/NetworkCommon.hpp index 5f90a95a0bc..cb37cf43d40 100644 --- a/src/common/NetworkCommon.hpp +++ b/src/common/NetworkCommon.hpp @@ -24,6 +24,13 @@ enum class NetworkRequestType { Delete, Patch, }; +const static std::vector networkRequestTypes{ + "GET", // + "POST", // + "PUT", // + "DELETE", // + "PATCH", // +}; // parseHeaderList takes a list of headers in string form, // where each header pair is separated by semicolons (;) and the header name and value is divided by a colon (:) diff --git a/src/common/NetworkPrivate.cpp b/src/common/NetworkPrivate.cpp index b141cd853e1..c49fcff9755 100644 --- a/src/common/NetworkPrivate.cpp +++ b/src/common/NetworkPrivate.cpp @@ -145,6 +145,11 @@ void loadUncached(const std::shared_ptr &data) data->timer_, &QTimer::timeout, worker, [reply, data]() { qCDebug(chatterinoCommon) << "Aborted!"; reply->abort(); + qCDebug(chatterinoHTTP) + << QString("%1 [timed out] %2") + .arg(networkRequestTypes.at( + int(data->requestType_)), + data->request_.url().toString()); if (data->onError_) { @@ -181,6 +186,11 @@ void loadUncached(const std::shared_ptr &data) QNetworkReply::NetworkError::OperationCanceledError) { // Operation cancelled, most likely timed out + qCDebug(chatterinoHTTP) + << QString("%1 [cancelled] %2") + .arg(networkRequestTypes.at( + int(data->requestType_)), + data->request_.url().toString()); return; } @@ -188,6 +198,25 @@ void loadUncached(const std::shared_ptr &data) { auto status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute); + if (data->requestType_ == NetworkRequestType::Get) + { + qCDebug(chatterinoHTTP) + << QString("%1 %2 %3") + .arg(networkRequestTypes.at( + int(data->requestType_)), + QString::number(status.toInt()), + data->request_.url().toString()); + } + else + { + qCDebug(chatterinoHTTP) + << QString("%1 %2 %3 %4") + .arg(networkRequestTypes.at( + int(data->requestType_)), + QString::number(status.toInt()), + data->request_.url().toString(), + QString(data->payload_)); + } // TODO: Should this always be run on the GUI thread? postToThread([data, code = status.toInt()] { data->onError_(NetworkResult({}, code)); @@ -227,6 +256,23 @@ void loadUncached(const std::shared_ptr &data) reply->deleteLater(); + if (data->requestType_ == NetworkRequestType::Get) + { + qCDebug(chatterinoHTTP) + << QString("%1 %2 %3") + .arg(networkRequestTypes.at(int(data->requestType_)), + QString::number(status.toInt()), + data->request_.url().toString()); + } + else + { + qCDebug(chatterinoHTTP) + << QString("%1 %3 %2 %4") + .arg(networkRequestTypes.at(int(data->requestType_)), + data->request_.url().toString(), + QString::number(status.toInt()), + QString(data->payload_)); + } if (data->finally_) { if (data->executeConcurrently_) @@ -286,6 +332,10 @@ void loadCached(const std::shared_ptr &data) QByteArray bytes = cachedFile.readAll(); NetworkResult result(bytes, 200); + qCDebug(chatterinoHTTP) + << QString("%1 [CACHED] 200 %2") + .arg(networkRequestTypes.at(int(data->requestType_)), + data->request_.url().toString()); if (data->onSuccess_) { if (data->executeConcurrently_ || isGuiThread()) diff --git a/src/common/QLogging.cpp b/src/common/QLogging.cpp index 742cbe243ef..a54b3296c68 100644 --- a/src/common/QLogging.cpp +++ b/src/common/QLogging.cpp @@ -15,6 +15,7 @@ Q_LOGGING_CATEGORY(chatterinoCommon, "chatterino.common", logThreshold); Q_LOGGING_CATEGORY(chatterinoEmoji, "chatterino.emoji", logThreshold); Q_LOGGING_CATEGORY(chatterinoFfzemotes, "chatterino.ffzemotes", logThreshold); Q_LOGGING_CATEGORY(chatterinoHelper, "chatterino.helper", logThreshold); +Q_LOGGING_CATEGORY(chatterinoHTTP, "chatterino.http", logThreshold); Q_LOGGING_CATEGORY(chatterinoImage, "chatterino.image", logThreshold); Q_LOGGING_CATEGORY(chatterinoIrc, "chatterino.irc", logThreshold); Q_LOGGING_CATEGORY(chatterinoIvr, "chatterino.ivr", logThreshold); diff --git a/src/common/QLogging.hpp b/src/common/QLogging.hpp index b157d79a6b0..e588ad48ac2 100644 --- a/src/common/QLogging.hpp +++ b/src/common/QLogging.hpp @@ -11,6 +11,7 @@ Q_DECLARE_LOGGING_CATEGORY(chatterinoCommon); Q_DECLARE_LOGGING_CATEGORY(chatterinoEmoji); Q_DECLARE_LOGGING_CATEGORY(chatterinoFfzemotes); Q_DECLARE_LOGGING_CATEGORY(chatterinoHelper); +Q_DECLARE_LOGGING_CATEGORY(chatterinoHTTP); Q_DECLARE_LOGGING_CATEGORY(chatterinoImage); Q_DECLARE_LOGGING_CATEGORY(chatterinoIrc); Q_DECLARE_LOGGING_CATEGORY(chatterinoIvr); From b352dea2dcc80dfee0647ea56aa45f57ef68293d Mon Sep 17 00:00:00 2001 From: Mm2PL Date: Sun, 25 Jul 2021 13:15:38 +0200 Subject: [PATCH 09/14] Make the copy button switch light/dark theme (#3057) Co-authored-by: Rasmus Karlsson --- CHANGELOG.md | 1 + resources/buttons/copyDark.png | Bin 1157 -> 1004 bytes resources/buttons/copyDark.svg | 2 +- resources/buttons/copyLight.png | Bin 1004 -> 1157 bytes resources/buttons/copyLight.svg | 2 +- src/singletons/Theme.cpp | 15 ++++++++++++++- src/singletons/Theme.hpp | 4 ++++ src/widgets/dialogs/UserInfoPopup.cpp | 3 ++- 8 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f29536b83a..0a18cc9d938 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Minor: Received IRC messages use `time` message tag for timestamp if it's available. (#3021) - Minor: Added informative messages for recent-messages API's errors. (#3029) - Bugfix: Fixed "smiley" emotes being unable to be "Tabbed" with autocompletion, introduced in v2.3.3. (#3010) +- Bugfix: Copy buttons in usercard now show properly in light mode (#3057) - Bugfix: Fixed comma appended to username completion when not at the beginning of the message. (#3060) - Dev: Ubuntu packages are now available (#2936) - Dev: Disabled update checker on Flatpak. (#3051) diff --git a/resources/buttons/copyDark.png b/resources/buttons/copyDark.png index 2a663bfd6d9d5dcdb81ded3e4f469c6c5eb90d18..a0b633eec4f5420f4d98abba1a4f73ae312b87a2 100644 GIT binary patch delta 962 zcmV;z13mnO3G4@uIDZ44NklYl2vyLx6}c6206*1>%W*aD0fLq|(3yGCbUYq}XYp9Qu9FMoiqKvc2<(R={@wuB2s zw$o^z0IQ3BtIdLd*>}U&ta`w(o?JI$6iL|B)98RfAp~#-^i$U2W)FdVZQeA5fHvds z&AkMM+rV+aK0|!|!TOj8;Mw95#&{mM2#mQL>gZx3K+EGO9PR+iHOCNpN(3;kJ-{3= z!A=vB8Uf6CBY*H1*vd{_iHQK;8Q{us6_gKv11@8T&KxRxF=z_lsrwuFQ?!@R&H^#Y zVgz*^*Z`acLI{NWe<1-ofqO;2+}wp?wycb--$6Vi;V|$$G&YvNNnubc&tBnvy_ybU z;C+Cl5hNsFQW()s0(#oQR_xnw&BKw0WM$C~!G01@Ie%!uaRRnEV3*+2Wg-Dmk~Tqg zSE%d8LZ|M1_@cx!?TB!Xd6S*sywbXm$g$iSy?oZdYzr~R72q7eYp=va!1^LeK6$2r zFGasja{_~J0(`tXWei$rl_i^V!Wv4xi%bA7feyeQKYZI`Ntm+e3BRsv2!Nq{8% zB!FA>Du1va_zZjk_~WNliHQIvx&wF%yao*Uc3Zw?-=%}POL!i1x->;6rV=pm@fCN{ zbQ)@x`sRu05cI{^sy-6{dQA{w)yydWJ`+ZE<@CgwLM9h>#LUAf50K^A1or%O#)? zl)O2YfU<7QV)ko}@TX23q= zTzRg6@|epoC^{Z;+yUc4LM)4Gz;nRVopCSssW0oweV30*r;TIj-r~Tz!o!U>OAX$W zJ%kXg1VZNOx3BmKY}H^g0buG|RkkAY6FZ;nRb%B2XyhQNdcy|&W}2F7878^``~p%q k2!9|>zMyGuv2fAlAL^z0ZKJ;az5oCK07*qoM6N<$g1Jq|_y7O^ delta 1116 zcmV-i1f%=x2ZafcIDZ5;NklY`l}hSc%95Nnv3pq82uO1O%}Z zMABG@h+t)F)WS*;Vp0lejFl+CRANAks1g4J8^xGJ?nuNh^y2UB?H-f6o%d$4d&f*} z2PQM~zUIB(%$xnlUVooOsaC6d3WdVR+S=Mds11aw{Vi=@KYxm1Ht5&u^)_0I+*GMl zx((Y$p!)&5ABv5Rbql7JYqeTAm&?t=!6oI9#6KF3(>T$GpVdFGt3+=)z`vyB13Oy$J0*%{ak@mB!hl%1NLv<(1umeY~m z1~X3q!WC5Y41Y<-I;^+^K>NYb2$OughdKrjjL)ows{Gd_03>fOL0}pnY?lOW_&xzZ zah*h+0|*tHAURpz0H9d*p}qkKhq%B@c`gBJhv;p}>nbE8psG=w-V z0EAz*-cbr%W0X2_?PccMDC-;)p92I+4XZ)`3^E$s1Ykp3Sn>TZ`gAzbA!%HsL$I3w z7(2}fR=}gnBt1|W6#{?@QUxgK3K=;Bp``QBjnWK2xM(t=8ep6}2Tq)P8npQojO1Zs z0wCN$rGLJ*I0FD2-5YvISDx#r-@|c|<|>pQ!!}*sV+-8}aI4JmVhtuB4&$Xu1(&jq zurUg!$I#N<9;HN-78~h9y>ACoq#ikpw7Wg(=z~oa9hqOsB=6;%-?Rd1BA8f`5hqb5CK2;*%TnR z$|^6q8*@J@3lF6gRspau>yKy#0M?3IWsc|1GBciLJAeU)SUs@=xF9*6fSn)gECqyh z>VJtHzy-|RNMMcqnC0I2-0IwKy?U+a9N0J%I@d2^8c zqch|%y@qcC-s$`^{y+jhXj)!fT|JLyqJLX3M!)8u5FNenN^#3IVVT1N0r8Z)F|;&{gjX z6BQ{15*hEXGW!Xv>D(CrKZGMfIWl ihLhu{(p{_(KK}uU6#m1T5kS}g0000 - + diff --git a/resources/buttons/copyLight.png b/resources/buttons/copyLight.png index a0b633eec4f5420f4d98abba1a4f73ae312b87a2..2a663bfd6d9d5dcdb81ded3e4f469c6c5eb90d18 100644 GIT binary patch delta 1116 zcmV-i1f%=x2ZafcIDZ5;NklY`l}hSc%95Nnv3pq82uO1O%}Z zMABG@h+t)F)WS*;Vp0lejFl+CRANAks1g4J8^xGJ?nuNh^y2UB?H-f6o%d$4d&f*} z2PQM~zUIB(%$xnlUVooOsaC6d3WdVR+S=Mds11aw{Vi=@KYxm1Ht5&u^)_0I+*GMl zx((Y$p!)&5ABv5Rbql7JYqeTAm&?t=!6oI9#6KF3(>T$GpVdFGt3+=)z`vyB13Oy$J0*%{ak@mB!hl%1NLv<(1umeY~m z1~X3q!WC5Y41Y<-I;^+^K>NYb2$OughdKrjjL)ows{Gd_03>fOL0}pnY?lOW_&xzZ zah*h+0|*tHAURpz0H9d*p}qkKhq%B@c`gBJhv;p}>nbE8psG=w-V z0EAz*-cbr%W0X2_?PccMDC-;)p92I+4XZ)`3^E$s1Ykp3Sn>TZ`gAzbA!%HsL$I3w z7(2}fR=}gnBt1|W6#{?@QUxgK3K=;Bp``QBjnWK2xM(t=8ep6}2Tq)P8npQojO1Zs z0wCN$rGLJ*I0FD2-5YvISDx#r-@|c|<|>pQ!!}*sV+-8}aI4JmVhtuB4&$Xu1(&jq zurUg!$I#N<9;HN-78~h9y>ACoq#ikpw7Wg(=z~oa9hqOsB=6;%-?Rd1BA8f`5hqb5CK2;*%TnR z$|^6q8*@J@3lF6gRspau>yKy#0M?3IWsc|1GBciLJAeU)SUs@=xF9*6fSn)gECqyh z>VJtHzy-|RNMMcqnC0I2-0IwKy?U+a9N0J%I@d2^8c zqch|%y@qcC-s$`^{y+jhXj)!fT|JLyqJLX3M!)8u5FNenN^#3IVVT1N0r8Z)F|;&{gjX z6BQ{15*hEXGW!Xv>D(CrKZGMfIWl ihLhu{(p{_(KK}uU6#m1T5kS}g0000Yl2vyLx6}c6206*1>%W*aD0fLq|(3yGCbUYq}XYp9Qu9FMoiqKvc2<(R={@wuB2s zw$o^z0IQ3BtIdLd*>}U&ta`w(o?JI$6iL|B)98RfAp~#-^i$U2W)FdVZQeA5fHvds z&AkMM+rV+aK0|!|!TOj8;Mw95#&{mM2#mQL>gZx3K+EGO9PR+iHOCNpN(3;kJ-{3= z!A=vB8Uf6CBY*H1*vd{_iHQK;8Q{us6_gKv11@8T&KxRxF=z_lsrwuFQ?!@R&H^#Y zVgz*^*Z`acLI{NWe<1-ofqO;2+}wp?wycb--$6Vi;V|$$G&YvNNnubc&tBnvy_ybU z;C+Cl5hNsFQW()s0(#oQR_xnw&BKw0WM$C~!G01@Ie%!uaRRnEV3*+2Wg-Dmk~Tqg zSE%d8LZ|M1_@cx!?TB!Xd6S*sywbXm$g$iSy?oZdYzr~R72q7eYp=va!1^LeK6$2r zFGasja{_~J0(`tXWei$rl_i^V!Wv4xi%bA7feyeQKYZI`Ntm+e3BRsv2!Nq{8% zB!FA>Du1va_zZjk_~WNliHQIvx&wF%yao*Uc3Zw?-=%}POL!i1x->;6rV=pm@fCN{ zbQ)@x`sRu05cI{^sy-6{dQA{w)yydWJ`+ZE<@CgwLM9h>#LUAf50K^A1or%O#)? zl)O2YfU<7QV)ko}@TX23q= zTzRg6@|epoC^{Z;+yUc4LM)4Gz;nRVopCSssW0oweV30*r;TIj-r~Tz!o!U>OAX$W zJ%kXg1VZNOx3BmKY}H^g0buG|RkkAY6FZ;nRb%B2XyhQNdcy|&W}2F7878^``~p%q k2!9|>zMyGuv2fAlAL^z0ZKJ;az5oCK07*qoM6N<$g1Jq|_y7O^ diff --git a/resources/buttons/copyLight.svg b/resources/buttons/copyLight.svg index 5fddace4e98..ed30f70a720 100644 --- a/resources/buttons/copyLight.svg +++ b/resources/buttons/copyLight.svg @@ -9,5 +9,5 @@ height="368.64pt" viewBox="0 0 368.64 368.64"> - + diff --git a/src/singletons/Theme.cpp b/src/singletons/Theme.cpp index 13e01bf87ca..2e73d170313 100644 --- a/src/singletons/Theme.cpp +++ b/src/singletons/Theme.cpp @@ -1,12 +1,15 @@ -#define LOOKUP_COLOR_COUNT 360 #include "singletons/Theme.hpp" + #include "Application.hpp" +#include "singletons/Resources.hpp" #include #include +#define LOOKUP_COLOR_COUNT 360 + namespace chatterino { Theme::Theme() @@ -80,6 +83,16 @@ void Theme::actuallyUpdate(double hue, double multiplier) this->splits.background = getColor(0, sat, 1); this->splits.dropPreview = QColor(0, 148, 255, 0x30); this->splits.dropPreviewBorder = QColor(0, 148, 255, 0xff); + + // Copy button + if (this->isLightTheme()) + { + this->buttons.copy = getResources().buttons.copyDark; + } + else + { + this->buttons.copy = getResources().buttons.copyLight; + } } void Theme::normalizeColor(QColor &color) diff --git a/src/singletons/Theme.hpp b/src/singletons/Theme.hpp index 99905fa8329..8b55dbab2ca 100644 --- a/src/singletons/Theme.hpp +++ b/src/singletons/Theme.hpp @@ -48,6 +48,10 @@ class Theme final : public Singleton, public BaseTheme } input; } splits; + struct { + QPixmap copy; + } buttons; + void normalizeColor(QColor &color); private: diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index 3c82d43f4f5..1f5c62afec1 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -13,6 +13,7 @@ #include "providers/twitch/api/Kraken.hpp" #include "singletons/Resources.hpp" #include "singletons/Settings.hpp" +#include "singletons/Theme.hpp" #include "util/Clipboard.hpp" #include "util/Helpers.hpp" #include "util/LayoutCreator.hpp" @@ -42,7 +43,7 @@ namespace { { auto label = box.emplace