From a6e5505fb79b27a1a3bf4a7eba01eac0279ddd99 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sat, 10 Feb 2024 21:39:16 +0100 Subject: [PATCH 1/8] chore: Add a full-build shell script for use in CI/docker (#5167) --- .CI/full-ubuntu-build.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 .CI/full-ubuntu-build.sh diff --git a/.CI/full-ubuntu-build.sh b/.CI/full-ubuntu-build.sh new file mode 100755 index 00000000000..f93d8ef2a8e --- /dev/null +++ b/.CI/full-ubuntu-build.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +set -e + +mkdir build +cmake -B build +CXXFLAGS=-fno-sized-deallocation cmake \ + -B build \ + -DCMAKE_INSTALL_PREFIX=appdir/usr/ \ + -DCMAKE_BUILD_TYPE=Release \ + -DUSE_PRECOMPILED_HEADERS=OFF \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=On \ + -DCHATTERINO_PLUGINS="$C2_PLUGINS" \ + -DCMAKE_PREFIX_PATH="$Qt6_DIR/lib/cmake" \ + -DBUILD_WITH_QT6="$C2_BUILD_WITH_QT6" \ + .. +cmake --build build + +# TODO: Test appimage/deb creation +# sh ./../.CI/CreateAppImage.sh +# sh ./../.CI/CreateUbuntuDeb.sh From e3c9c1359860711a4bd6941e94116a3bb2860f4c Mon Sep 17 00:00:00 2001 From: pajlada Date: Sat, 10 Feb 2024 22:13:53 +0100 Subject: [PATCH 2/8] chore: update the ci full build script (#5168) --- .CI/full-ubuntu-build.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.CI/full-ubuntu-build.sh b/.CI/full-ubuntu-build.sh index f93d8ef2a8e..c863a4c160e 100755 --- a/.CI/full-ubuntu-build.sh +++ b/.CI/full-ubuntu-build.sh @@ -1,10 +1,15 @@ #!/bin/sh +# TODO: Investigate if the -fno-sized-deallocation flag is still necessary +# TODO: Test appimage/deb creation + set -e +env + +rm -rf build mkdir build -cmake -B build -CXXFLAGS=-fno-sized-deallocation cmake \ +cmake \ -B build \ -DCMAKE_INSTALL_PREFIX=appdir/usr/ \ -DCMAKE_BUILD_TYPE=Release \ @@ -13,9 +18,9 @@ CXXFLAGS=-fno-sized-deallocation cmake \ -DCHATTERINO_PLUGINS="$C2_PLUGINS" \ -DCMAKE_PREFIX_PATH="$Qt6_DIR/lib/cmake" \ -DBUILD_WITH_QT6="$C2_BUILD_WITH_QT6" \ - .. + -DCMAKE_CXX_FLAGS="-fno-sized-deallocation" \ + . cmake --build build -# TODO: Test appimage/deb creation # sh ./../.CI/CreateAppImage.sh # sh ./../.CI/CreateUbuntuDeb.sh From fe1e498a5f1c213dc6a9c5571e5e077ef0c14911 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 11 Feb 2024 19:11:30 +0100 Subject: [PATCH 3/8] chore: Run Ubuntu tests in Docker (#5170) Co-authored-by: Wissididom <30803034+Wissididom@users.noreply.github.com> --- .CI/full-ubuntu-build.sh | 4 + .github/workflows/test.yml | 102 +++++++++-------------- benchmarks/CMakeLists.txt | 7 ++ mocks/include/mocks/EmptyApplication.hpp | 9 ++ src/CMakeLists.txt | 7 +- tests/CMakeLists.txt | 7 ++ 6 files changed, 73 insertions(+), 63 deletions(-) diff --git a/.CI/full-ubuntu-build.sh b/.CI/full-ubuntu-build.sh index c863a4c160e..a9f4dfcae36 100755 --- a/.CI/full-ubuntu-build.sh +++ b/.CI/full-ubuntu-build.sh @@ -13,11 +13,15 @@ cmake \ -B build \ -DCMAKE_INSTALL_PREFIX=appdir/usr/ \ -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_APP=On \ + -DBUILD_TESTS=On \ + -DBUILD_BENCHMARKS=On \ -DUSE_PRECOMPILED_HEADERS=OFF \ -DCMAKE_EXPORT_COMPILE_COMMANDS=On \ -DCHATTERINO_PLUGINS="$C2_PLUGINS" \ -DCMAKE_PREFIX_PATH="$Qt6_DIR/lib/cmake" \ -DBUILD_WITH_QT6="$C2_BUILD_WITH_QT6" \ + -DCHATTERINO_STATIC_QT_BUILD=On \ -DCMAKE_CXX_FLAGS="-fno-sized-deallocation" \ . cmake --build build diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index acfe026022d..45c1a291bc9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,5 @@ --- -name: Test +name: Test Ubuntu on: pull_request: @@ -7,7 +7,7 @@ on: merge_group: env: - TWITCH_PUBSUB_SERVER_IMAGE: ghcr.io/chatterino/twitch-pubsub-server-test:v1.0.6 + TWITCH_PUBSUB_SERVER_TAG: v1.0.7 QT_QPA_PLATFORM: minimal concurrency: @@ -16,91 +16,71 @@ concurrency: jobs: test: - runs-on: ${{ matrix.os }} + name: "${{ matrix.os }}" + runs-on: ubuntu-latest + container: ${{ matrix.container }} strategy: matrix: include: - os: "ubuntu-22.04" - qt-version: "5.15.2" - - os: "ubuntu-22.04" - qt-version: "5.12.12" - - os: "ubuntu-22.04" - qt-version: "6.2.4" + container: ghcr.io/chatterino/chatterino2-build-ubuntu-22.04:latest + qt-version: 6.6.1 + plugins: true fail-fast: false env: - C2_BUILD_WITH_QT6: ${{ startsWith(matrix.qt-version, '6.') && 'ON' || 'OFF' }} - QT_MODULES: ${{ startsWith(matrix.qt-version, '6.') && 'qt5compat qtimageformats' || '' }} + C2_PLUGINS: ${{ matrix.plugins }} + C2_BUILD_WITH_QT6: ${{ startsWith(matrix.qt-version, '6.') }} steps: - uses: actions/checkout@v4 with: submodules: recursive - - name: Install Qt - uses: jurplel/install-qt-action@v3.3.0 - with: - cache: true - cache-key-prefix: ${{ runner.os }}-QtCache-${{ matrix.qt-version }}-v2 - modules: ${{ env.QT_MODULES }} - version: ${{ matrix.qt-version }} - - - name: Apply Qt patches (Ubuntu) - if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.qt-version, '5.') - run: | - patch "$Qt5_DIR/include/QtConcurrent/qtconcurrentthreadengine.h" .patches/qt5-on-newer-gcc.patch - shell: bash - - # LINUX - - name: Install dependencies (Ubuntu) - if: startsWith(matrix.os, 'ubuntu') - run: | - sudo apt-get update - sudo apt-get -y install \ - libbenchmark-dev \ - cmake \ - rapidjson-dev \ - libssl-dev \ - libboost-dev \ - libboost-system-dev \ - libboost-filesystem-dev \ - libpulse-dev \ - libxkbcommon-x11-0 \ - libgstreamer-plugins-base1.0-0 \ - build-essential \ - libgl1-mesa-dev \ - libxcb-icccm4 \ - libxcb-image0 \ - libxcb-keysyms1 \ - libxcb-render-util0 \ - libxcb-xinerama0 - - name: Create build directory (Ubuntu) - if: startsWith(matrix.os, 'ubuntu') + run: mkdir build-test + + - name: Install googlebench run: | - mkdir build-test - shell: bash + sudo apt update + sudo apt -y install \ + libbenchmark-dev - name: Build (Ubuntu) - if: startsWith(matrix.os, 'ubuntu') run: | cmake \ -DBUILD_TESTS=On \ -DBUILD_BENCHMARKS=On \ -DBUILD_APP=OFF \ + -DCHATTERINO_PLUGINS="$C2_PLUGINS" \ + -DCMAKE_PREFIX_PATH="$Qt6_DIR/lib/cmake" \ -DBUILD_WITH_QT6="$C2_BUILD_WITH_QT6" \ + -DCHATTERINO_STATIC_QT_BUILD=On \ .. cmake --build . working-directory: build-test - shell: bash - - name: Test (Ubuntu) - if: startsWith(matrix.os, 'ubuntu') + - name: Download and extract Twitch PubSub Server Test + run: | + mkdir pubsub-server-test + curl -L -o pubsub-server.tar.gz "https://github.com/Chatterino/twitch-pubsub-server-test/releases/download/${{ env.TWITCH_PUBSUB_SERVER_TAG }}/server-${{ env.TWITCH_PUBSUB_SERVER_TAG }}-linux-amd64.tar.gz" + tar -xzf pubsub-server.tar.gz -C pubsub-server-test + rm pubsub-server.tar.gz + cd pubsub-server-test + curl -L -o server.crt "https://github.com/Chatterino/twitch-pubsub-server-test/raw/${{ env.TWITCH_PUBSUB_SERVER_TAG }}/cmd/server/server.crt" + curl -L -o server.key "https://github.com/Chatterino/twitch-pubsub-server-test/raw/${{ env.TWITCH_PUBSUB_SERVER_TAG }}/cmd/server/server.key" + cd .. + + - uses: dtolnay/rust-toolchain@stable + - name: Cargo Install httpbox + run: | + cargo install --git https://github.com/kevinastone/httpbox --rev 89b971f + + - name: Test timeout-minutes: 30 run: | - docker pull kennethreitz/httpbin - docker pull ${{ env.TWITCH_PUBSUB_SERVER_IMAGE }} - docker run --network=host --detach ${{ env.TWITCH_PUBSUB_SERVER_IMAGE }} - docker run -p 9051:80 --detach kennethreitz/httpbin - ctest --repeat until-pass:4 --output-on-failure + httpbox --port 9051 & + cd ../pubsub-server-test + ./server 127.0.0.1:9050 & + cd ../build-test + ctest --repeat until-pass:4 --output-on-failure --exclude-regex ClassicEmoteNameFiltering working-directory: build-test - shell: bash diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 209c0115b74..a0e73332e70 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -32,3 +32,10 @@ set_target_properties(${PROJECT_NAME} RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/bin" AUTORCC ON ) + +if (CHATTERINO_STATIC_QT_BUILD) + qt_import_plugins(${PROJECT_NAME} INCLUDE_BY_TYPE + platforms Qt::QXcbIntegrationPlugin + Qt::QMinimalIntegrationPlugin + ) +endif () diff --git a/mocks/include/mocks/EmptyApplication.hpp b/mocks/include/mocks/EmptyApplication.hpp index a6a1745d280..483cad11a74 100644 --- a/mocks/include/mocks/EmptyApplication.hpp +++ b/mocks/include/mocks/EmptyApplication.hpp @@ -186,6 +186,15 @@ class EmptyApplication : public IApplication return nullptr; } +#ifdef CHATTERINO_HAVE_PLUGINS + PluginController *getPlugins() override + { + assert(false && "EmptyApplication::getPlugins was called without " + "being initialized"); + return nullptr; + } +#endif + Updates &getUpdates() override { return this->updates_; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8878def7aa2..faef0c8f22b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -728,7 +728,7 @@ add_library(${LIBRARY_PROJECT} OBJECT ${SOURCE_FILES}) if(CHATTERINO_PLUGINS) target_compile_definitions(${LIBRARY_PROJECT} - PRIVATE + PUBLIC CHATTERINO_HAVE_PLUGINS ) message(STATUS "Building Chatterino with lua plugin support enabled.") @@ -814,7 +814,10 @@ if (BUILD_APP) endif() if (CHATTERINO_STATIC_QT_BUILD) - qt_import_plugins(${EXECUTABLE_PROJECT} INCLUDE_BY_TYPE platforms Qt::QXcbIntegrationPlugin) + qt_import_plugins(${EXECUTABLE_PROJECT} INCLUDE_BY_TYPE + platforms Qt::QXcbIntegrationPlugin + Qt::QMinimalIntegrationPlugin + ) endif () target_include_directories(${EXECUTABLE_PROJECT} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/autogen/) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3fc7f13085c..3aadc2543af 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -73,4 +73,11 @@ set_target_properties(${PROJECT_NAME} AUTORCC ON ) +if (CHATTERINO_STATIC_QT_BUILD) + qt_import_plugins(${PROJECT_NAME} INCLUDE_BY_TYPE + platforms Qt::QXcbIntegrationPlugin + Qt::QMinimalIntegrationPlugin + ) +endif () + gtest_discover_tests(${PROJECT_NAME}) From 4a5d4ef3fab3c07a5c88a0e4ba58a1a0c88916f8 Mon Sep 17 00:00:00 2001 From: nerix Date: Wed, 14 Feb 2024 14:49:31 +0100 Subject: [PATCH 4/8] fix: minimize button remaining hovered on Windows (#5175) --- CHANGELOG.md | 2 +- src/widgets/BaseWindow.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 394596b6273..90380a7aeb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,7 +65,7 @@ - Bugfix: Fixed rare crash with Image Uploader when closing a split right after starting an upload. (#4971) - Bugfix: Fixed an issue on macOS where the image uploader would keep prompting the user even after they clicked "Yes, don't ask again". (#5011) - Bugfix: Hide the Usercard button in the User Info Popup when in special channels. (#4972) -- Bugfix: Fixed support for Windows 11 Snap layouts. (#4994) +- Bugfix: Fixed support for Windows 11 Snap layouts. (#4994, #5175) - Bugfix: Fixed some windows appearing between screens. (#4797) - Bugfix: Fixed a crash that could occur when using certain features in a Usercard after closing the split from which it was created. (#5034, #5051) - Bugfix: Fixed a crash that could occur when using certain features in a Reply popup after closing the split from which it was created. (#5036, #5051) diff --git a/src/widgets/BaseWindow.cpp b/src/widgets/BaseWindow.cpp index c77ab62107c..ca7d02d4401 100644 --- a/src/widgets/BaseWindow.cpp +++ b/src/widgets/BaseWindow.cpp @@ -962,6 +962,13 @@ bool BaseWindow::handleSIZE(MSG *msg) QPoint(rect.right - 1, rect.bottom - 1)); } this->useNextBounds_.stop(); + + if (msg->wParam == SIZE_MINIMIZED && this->ui_.titlebarButtons) + { + // Windows doesn't send a WM_NCMOUSELEAVE event when clicking + // the minimize button, so we have to emulate it. + this->ui_.titlebarButtons->leave(); + } } } return false; From 3cdb7bf4f654a7e89f124f22dddac2be7f14352f Mon Sep 17 00:00:00 2001 From: KleberPF <43550602+KleberPF@users.noreply.github.com> Date: Sat, 17 Feb 2024 08:22:49 -0300 Subject: [PATCH 5/8] fix: resolve /live channel liveness using their channel ID (#5172) --- CHANGELOG.md | 1 + src/controllers/notifications/NotificationController.cpp | 3 ++- src/providers/twitch/TwitchChannel.cpp | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90380a7aeb0..3249aaaa1a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ - Bugfix: Fixed double-click text selection moving its position with each new message. (#4898) - Bugfix: Fixed an issue where notifications on Windows would contain no or an old avatar. (#4899) - Bugfix: Fixed headers of tables in the settings switching to bold text when selected. (#4913) +- Bugfix: Fixed an issue in the `/live` split that caused some channels to not get grayed-out when they went offline. (#5172) - Bugfix: Fixed tooltips appearing too large and/or away from the cursor. (#4920) - Bugfix: Fixed a crash when clicking `More messages below` button in a usercard and closing it quickly. (#4933) - Bugfix: Fixed thread popup window missing messages for nested threads. (#4923) diff --git a/src/controllers/notifications/NotificationController.cpp b/src/controllers/notifications/NotificationController.cpp index af15ea765c1..5e3aa1fdd82 100644 --- a/src/controllers/notifications/NotificationController.cpp +++ b/src/controllers/notifications/NotificationController.cpp @@ -227,7 +227,8 @@ void NotificationController::removeFakeChannel(const QString channelName) { const auto &s = snapshot[i]; - if (s->messageText == liveMessageSearchText) + if (QString::compare(s->messageText, liveMessageSearchText, + Qt::CaseInsensitive) == 0) { s->flags.set(MessageFlag::Disabled); break; diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index e99bdd2285f..f92e9981e05 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -164,12 +164,14 @@ TwitchChannel::TwitchChannel(const QString &name) MessageBuilder builder; TwitchMessageBuilder::liveSystemMessage(this->getDisplayName(), &builder); + builder.message().id = this->roomId(); this->addMessage(builder.release()); // Message in /live channel MessageBuilder builder2; TwitchMessageBuilder::liveMessage(this->getDisplayName(), &builder2); + builder2.message().id = this->roomId(); getApp()->twitch->liveChannel->addMessage(builder2.release()); // Notify on all channels with a ping sound @@ -197,14 +199,12 @@ TwitchChannel::TwitchChannel(const QString &name) // MSVC hates this code if the parens are not there int end = (std::max)(0, snapshotLength - 200); - auto liveMessageSearchText = - QString("%1 is live!").arg(this->getDisplayName()); for (int i = snapshotLength - 1; i >= end; --i) { const auto &s = snapshot[i]; - if (s->messageText == liveMessageSearchText) + if (s->id == this->roomId()) { s->flags.set(MessageFlag::Disabled); break; From 4b48774cbb5a633b402c982e6582124004e59a40 Mon Sep 17 00:00:00 2001 From: KleberPF <43550602+KleberPF@users.noreply.github.com> Date: Sat, 17 Feb 2024 08:49:06 -0300 Subject: [PATCH 6/8] fix: searching redemptions that require user input (#5177) Co-authored-by: Felanbird <41973452+Felanbird@users.noreply.github.com> --- CHANGELOG.md | 1 + src/providers/twitch/TwitchMessageBuilder.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3249aaaa1a7..e904f9aa7f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ - Bugfix: Fixed too much text being copied when copying chat messages. (#4812, #4830, #4839) - Bugfix: Fixed an issue where the setting `Only search for emote autocompletion at the start of emote names` wouldn't disable if it was enabled when the client started. (#4855) - Bugfix: Fixed empty page being added when showing out of bounds dialog. (#4849) +- Bugfix: Fixed an issue preventing searching a redemption by it's title when the redemption contained text input. (#5117) - Bugfix: Fixed issue on Windows preventing the title bar from being dragged in the top left corner. (#4873) - Bugfix: Fixed an issue where reply context didn't render correctly if an emoji was touching text. (#4875, #4977) - Bugfix: Fixed the input completion popup from disappearing when clicking on it on Windows and macOS. (#4876) diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 5037da5615c..e333d155ab8 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -564,9 +564,10 @@ MessagePtr TwitchMessageBuilder::build() this->stylizeUsername(this->userName, this->message()); this->message().messageText = this->originalMessage_; - this->message().searchText = stylizedUsername + " " + - this->message().localizedName + " " + - this->userName + ": " + this->originalMessage_; + this->message().searchText = + stylizedUsername + " " + this->message().localizedName + " " + + this->userName + ": " + this->originalMessage_ + " " + + this->message().searchText; // highlights this->parseHighlights(); From 32d269dffce303322b983592ded74dcd65c3b258 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sat, 17 Feb 2024 13:26:54 +0100 Subject: [PATCH 7/8] feat: add the ability to unit test some aspects of SplitInput (#5179) --- CHANGELOG.md | 1 + mocks/include/mocks/TwitchIrcServer.hpp | 6 ++ src/providers/twitch/TwitchIrcServer.cpp | 5 ++ src/providers/twitch/TwitchIrcServer.hpp | 4 + src/widgets/splits/SplitInput.cpp | 13 ++- src/widgets/splits/SplitInput.hpp | 7 ++ tests/CMakeLists.txt | 1 + tests/src/SplitInput.cpp | 109 +++++++++++++++++++++++ 8 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 tests/src/SplitInput.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index e904f9aa7f9..182d678392d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,7 @@ - Dev: Replace `boost::optional` with `std::optional`. (#4877) - Dev: Improve performance of selecting text. (#4889, #4911) - Dev: Removed direct dependency on Qt 5 compatibility module. (#4906) +- Dev: Added unit test capabilities to SplitInput. (#5179) - Dev: Refactor `Emoji`'s EmojiMap into a vector. (#4980) - Dev: Refactor `DebugCount` and add copy button to debug popup. (#4921) - Dev: Refactor `common/Credentials`. (#4979) diff --git a/mocks/include/mocks/TwitchIrcServer.hpp b/mocks/include/mocks/TwitchIrcServer.hpp index 2ef163db611..976d6f2addd 100644 --- a/mocks/include/mocks/TwitchIrcServer.hpp +++ b/mocks/include/mocks/TwitchIrcServer.hpp @@ -24,8 +24,14 @@ class MockTwitchIrcServer : public ITwitchIrcServer return this->watchingChannel; } + QString getLastUserThatWhisperedMe() const override + { + return this->lastUserThatWhisperedMe; + } + ChannelPtr watchingChannelInner; IndirectChannel watchingChannel; + QString lastUserThatWhisperedMe{"forsen"}; }; } // namespace chatterino::mock diff --git a/src/providers/twitch/TwitchIrcServer.cpp b/src/providers/twitch/TwitchIrcServer.cpp index acad48f8664..d7fbdc4d00c 100644 --- a/src/providers/twitch/TwitchIrcServer.cpp +++ b/src/providers/twitch/TwitchIrcServer.cpp @@ -525,6 +525,11 @@ const IndirectChannel &TwitchIrcServer::getWatchingChannel() const return this->watchingChannel; } +QString TwitchIrcServer::getLastUserThatWhisperedMe() const +{ + return this->lastUserThatWhisperedMe.get(); +} + void TwitchIrcServer::reloadBTTVGlobalEmotes() { getIApp()->getBttvEmotes()->loadEmotes(); diff --git a/src/providers/twitch/TwitchIrcServer.hpp b/src/providers/twitch/TwitchIrcServer.hpp index 6fe36c0a2fd..53db359641e 100644 --- a/src/providers/twitch/TwitchIrcServer.hpp +++ b/src/providers/twitch/TwitchIrcServer.hpp @@ -29,6 +29,8 @@ class ITwitchIrcServer virtual const IndirectChannel &getWatchingChannel() const = 0; + virtual QString getLastUserThatWhisperedMe() const = 0; + // Update this interface with TwitchIrcServer methods as needed }; @@ -81,6 +83,8 @@ class TwitchIrcServer final : public AbstractIrcServer, const IndirectChannel &getWatchingChannel() const override; + QString getLastUserThatWhisperedMe() const override; + protected: void initializeConnection(IrcConnection *connection, ConnectionType type) override; diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index e39b9d08280..81707a066a2 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -78,7 +78,7 @@ SplitInput::SplitInput(QWidget *parent, Split *_chatWidget, void SplitInput::initLayout() { - auto *app = getApp(); + auto *app = getIApp(); LayoutCreator layoutCreator(this); auto layout = @@ -202,7 +202,7 @@ void SplitInput::initLayout() void SplitInput::scaleChangedEvent(float scale) { - auto *app = getApp(); + auto *app = getIApp(); // update the icon size of the buttons this->updateEmoteButton(); this->updateCancelReplyButton(); @@ -919,9 +919,14 @@ bool SplitInput::isHidden() const return this->hidden; } +void SplitInput::setInputText(const QString &newInputText) +{ + this->ui_.textEdit->setPlainText(newInputText); +} + void SplitInput::editTextChanged() { - auto *app = getApp(); + auto *app = getIApp(); // set textLengthLabel value QString text = this->ui_.textEdit->toPlainText(); @@ -936,7 +941,7 @@ void SplitInput::editTextChanged() if (text.startsWith("/r ", Qt::CaseInsensitive) && this->split_->getChannel()->isTwitchChannel()) { - QString lastUser = app->twitch->lastUserThatWhisperedMe.get(); + auto lastUser = app->getTwitch()->getLastUserThatWhisperedMe(); if (!lastUser.isEmpty()) { this->ui_.textEdit->setPlainText("/w " + lastUser + text.mid(2)); diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index d1eb64007a7..f66d5d27f4e 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -66,6 +66,13 @@ class SplitInput : public BaseWidget **/ bool isHidden() const; + /** + * @brief Sets the text of this input + * + * This method should only be used in tests + */ + void setInputText(const QString &newInputText); + pajlada::Signals::Signal textChanged; pajlada::Signals::NoArgSignal selectionChanged; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3aadc2543af..564d6ad4798 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,6 +37,7 @@ set(test_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/XDGHelper.cpp ${CMAKE_CURRENT_LIST_DIR}/src/Selection.cpp ${CMAKE_CURRENT_LIST_DIR}/src/NotebookTab.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/SplitInput.cpp # Add your new file above this line! ) diff --git a/tests/src/SplitInput.cpp b/tests/src/SplitInput.cpp new file mode 100644 index 00000000000..8f5667bded0 --- /dev/null +++ b/tests/src/SplitInput.cpp @@ -0,0 +1,109 @@ +#include "widgets/splits/SplitInput.hpp" + +#include "common/Literals.hpp" +#include "controllers/accounts/AccountController.hpp" +#include "controllers/commands/Command.hpp" +#include "controllers/commands/CommandController.hpp" +#include "controllers/hotkeys/HotkeyController.hpp" +#include "mocks/EmptyApplication.hpp" +#include "singletons/Emotes.hpp" +#include "singletons/Fonts.hpp" +#include "singletons/Paths.hpp" +#include "singletons/Theme.hpp" +#include "singletons/WindowManager.hpp" +#include "widgets/Notebook.hpp" +#include "widgets/splits/Split.hpp" + +#include +#include +#include +#include + +using namespace chatterino; +using ::testing::Exactly; + +namespace { + +class MockApplication : mock::EmptyApplication +{ +public: + MockApplication() + : windowManager(this->paths) + { + } + Theme *getThemes() override + { + return &this->theme; + } + + HotkeyController *getHotkeys() override + { + return &this->hotkeys; + } + + Fonts *getFonts() override + { + return &this->fonts; + } + + WindowManager *getWindows() override + { + return &this->windowManager; + } + + AccountController *getAccounts() override + { + return &this->accounts; + } + + CommandController *getCommands() override + { + return &this->commands; + } + + IEmotes *getEmotes() override + { + return &this->emotes; + } + + Theme theme; + HotkeyController hotkeys; + Fonts fonts; + Paths paths; + WindowManager windowManager; + AccountController accounts; + CommandController commands; + Emotes emotes; +}; + +class SplitInputFixture : public ::testing::Test +{ +protected: + SplitInputFixture() + : split(new Split(nullptr)) + , input(this->split) + { + } + + MockApplication mockApplication; + Split *split; + SplitInput input; +}; + +} // namespace + +TEST_F(SplitInputFixture, Reply) +{ + ASSERT_EQ("", this->input.getInputText()); + this->input.setInputText("forsen"); + ASSERT_EQ("forsen", this->input.getInputText()); + auto *message = new Message(); + message->displayName = "xd"; + auto reply = MessagePtr(message); + this->input.setReply(reply); + QString expected("@xd forsen "); + QString actual = this->input.getInputText(); + ASSERT_EQ(expected, actual) + << "Input text after setReply should be '" << qUtf8Printable(expected) + << "', but got '" << qUtf8Printable(actual) << "'"; +} From 42e4559910dff8ea2c3b8f89fceef46db0190849 Mon Sep 17 00:00:00 2001 From: KleberPF <43550602+KleberPF@users.noreply.github.com> Date: Sat, 17 Feb 2024 10:25:14 -0300 Subject: [PATCH 8/8] fix: "reply to message" now takes usernames with @'s & commas into consideration (#5173) Co-authored-by: Rasmus Karlsson Co-authored-by: Felanbird <41973452+Felanbird@users.noreply.github.com> --- CHANGELOG.md | 1 + src/widgets/splits/SplitInput.cpp | 28 ++++++++--- tests/src/SplitInput.cpp | 78 +++++++++++++++++++++++++++---- 3 files changed, 93 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 182d678392d..a8553d9b939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ - Bugfix: Fixed avatar in usercard and moderation button triggering when releasing the mouse outside their area. (#5052) - Bugfix: Fixed moderator-only topics being subscribed to for non-moderators. (#5056) - Bugfix: Fixed a bug where buttons would remain in a hovered state after leaving them. (#5077) +- Bugfix: Fixed an issue where you had to click the `reply` button twice if you already had that users @ in your input box. (#5173) - Bugfix: Fixed popup windows not persisting between restarts. (#5081) - Bugfix: Fixed splits not retaining their focus after minimizing. (#5080) - Bugfix: Fixed _Copy message_ copying the channel name in global search. (#5106) diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 81707a066a2..d53b4bad991 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -1113,16 +1113,32 @@ void SplitInput::setReply(MessagePtr reply, bool showReplyingLabel) // Only enable reply label if inline replying auto replyPrefix = "@" + this->replyThread_->displayName; auto plainText = this->ui_.textEdit->toPlainText().trimmed(); - if (!plainText.startsWith(replyPrefix)) + + // This makes it so if plainText contains "@StreamerFan" and + // we are replying to "@Streamer" we don't just leave "Fan" + // in the text box + if (plainText.startsWith(replyPrefix)) { - if (!plainText.isEmpty()) + if (plainText.length() > replyPrefix.length()) { - replyPrefix.append(' '); + if (plainText.at(replyPrefix.length()) == ',' || + plainText.at(replyPrefix.length()) == ' ') + { + plainText.remove(0, replyPrefix.length() + 1); + } } - this->ui_.textEdit->setPlainText(replyPrefix + plainText + " "); - this->ui_.textEdit->moveCursor(QTextCursor::EndOfBlock); - this->ui_.textEdit->resetCompletion(); + else + { + plainText.remove(0, replyPrefix.length()); + } + } + if (!plainText.isEmpty() && !plainText.startsWith(' ')) + { + replyPrefix.append(' '); } + this->ui_.textEdit->setPlainText(replyPrefix + plainText + " "); + this->ui_.textEdit->moveCursor(QTextCursor::EndOfBlock); + this->ui_.textEdit->resetCompletion(); this->ui_.replyLabel->setText("Replying to @" + this->replyThread_->displayName); } diff --git a/tests/src/SplitInput.cpp b/tests/src/SplitInput.cpp index 8f5667bded0..5d542f735dc 100644 --- a/tests/src/SplitInput.cpp +++ b/tests/src/SplitInput.cpp @@ -76,10 +76,11 @@ class MockApplication : mock::EmptyApplication Emotes emotes; }; -class SplitInputFixture : public ::testing::Test +class SplitInputTest + : public ::testing::TestWithParam> { -protected: - SplitInputFixture() +public: + SplitInputTest() : split(new Split(nullptr)) , input(this->split) { @@ -92,18 +93,79 @@ class SplitInputFixture : public ::testing::Test } // namespace -TEST_F(SplitInputFixture, Reply) +TEST_P(SplitInputTest, Reply) { + std::tuple params = this->GetParam(); + auto [inputText, expected] = params; ASSERT_EQ("", this->input.getInputText()); - this->input.setInputText("forsen"); - ASSERT_EQ("forsen", this->input.getInputText()); + this->input.setInputText(inputText); + ASSERT_EQ(inputText, this->input.getInputText()); + auto *message = new Message(); - message->displayName = "xd"; + message->displayName = "forsen"; auto reply = MessagePtr(message); this->input.setReply(reply); - QString expected("@xd forsen "); QString actual = this->input.getInputText(); ASSERT_EQ(expected, actual) << "Input text after setReply should be '" << qUtf8Printable(expected) << "', but got '" << qUtf8Printable(actual) << "'"; } + +INSTANTIATE_TEST_SUITE_P( + SplitInput, SplitInputTest, + testing::Values( + // Ensure message is retained + std::make_tuple( + // Pre-existing text in the input + "Test message", + // Expected text after replying to forsen + "@forsen Test message "), + + // Ensure mention is stripped, no message + std::make_tuple( + // Pre-existing text in the input + "@forsen", + // Expected text after replying to forsen + "@forsen "), + + // Ensure mention with space is stripped, no message + std::make_tuple( + // Pre-existing text in the input + "@forsen ", + // Expected text after replying to forsen + "@forsen "), + + // Ensure mention is stripped, retain message + std::make_tuple( + // Pre-existing text in the input + "@forsen Test message", + // Expected text after replying to forsen + "@forsen Test message "), + + // Ensure mention with comma is stripped, no message + std::make_tuple( + // Pre-existing text in the input + "@forsen,", + // Expected text after replying to forsen + "@forsen "), + + // Ensure mention with comma is stripped, retain message + std::make_tuple( + // Pre-existing text in the input + "@forsen Test message", + // Expected text after replying to forsen + "@forsen Test message "), + + // Ensure mention with comma and space is stripped, no message + std::make_tuple( + // Pre-existing text in the input + "@forsen, ", + // Expected text after replying to forsen + "@forsen "), + + // Ensure it works with no message + std::make_tuple( + // Pre-existing text in the input + "", + // Expected text after replying to forsen + "@forsen ")));