mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Merge branch 'master' of github.com:Chatterino/chatterino2
This commit is contained in:
commit
0dd6934f02
42 changed files with 394 additions and 100 deletions
44
.github/workflows/build.yml
vendored
44
.github/workflows/build.yml
vendored
|
@ -63,29 +63,32 @@ jobs:
|
||||||
version: ${{ matrix.qt-version }}
|
version: ${{ matrix.qt-version }}
|
||||||
|
|
||||||
# WINDOWS
|
# WINDOWS
|
||||||
|
|
||||||
- name: Cache conan packages
|
- name: Cache conan packages
|
||||||
if: startsWith(matrix.os, 'windows')
|
if: startsWith(matrix.os, 'windows')
|
||||||
uses: actions/cache@v2.1.4
|
uses: actions/cache@v2.1.4
|
||||||
with:
|
with:
|
||||||
key: ${{ runner.os }}-conan-${{ hashFiles('**/conanfile.txt') }}-20210307
|
key: ${{ runner.os }}-conan-${{ hashFiles('**/conanfile.txt') }}-20210412
|
||||||
path: C:/.conan/
|
path: C:/.conan/
|
||||||
|
|
||||||
|
- name: Add Conan to path
|
||||||
|
if: startsWith(matrix.os, 'windows')
|
||||||
|
run: echo "C:\Program Files\Conan\conan\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
|
||||||
- name: Install dependencies (Windows)
|
- name: Install dependencies (Windows)
|
||||||
if: startsWith(matrix.os, 'windows')
|
if: startsWith(matrix.os, 'windows')
|
||||||
run: |
|
run: |
|
||||||
choco install conan -y
|
choco install conan -y
|
||||||
|
|
||||||
refreshenv
|
- name: Enable Developer Command Prompt
|
||||||
shell: cmd
|
if: startsWith(matrix.os, 'windows')
|
||||||
|
uses: ilammy/msvc-dev-cmd@v1.7.0
|
||||||
|
|
||||||
- name: Build (Windows)
|
- name: Build (Windows)
|
||||||
if: startsWith(matrix.os, 'windows') && matrix.build-system == 'qmake'
|
if: startsWith(matrix.os, 'windows') && matrix.build-system == 'qmake'
|
||||||
run: |
|
run: |
|
||||||
call "%programfiles(x86)%\Microsoft Visual Studio\%vs_version%\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
"C:\Program Files\Conan\conan\conan.exe" install ..
|
conan install ..
|
||||||
qmake ..
|
qmake ..
|
||||||
set cl=/MP
|
set cl=/MP
|
||||||
nmake /S /NOLOGO
|
nmake /S /NOLOGO
|
||||||
|
@ -93,15 +96,13 @@ jobs:
|
||||||
cp release/chatterino.exe Chatterino2/
|
cp release/chatterino.exe Chatterino2/
|
||||||
echo nightly > Chatterino2/modes
|
echo nightly > Chatterino2/modes
|
||||||
7z a chatterino-windows-x86-64.zip Chatterino2/
|
7z a chatterino-windows-x86-64.zip Chatterino2/
|
||||||
shell: cmd
|
|
||||||
|
|
||||||
- name: Build with CMake (Windows)
|
- name: Build with CMake (Windows)
|
||||||
if: startsWith(matrix.os, 'windows') && matrix.build-system == 'cmake'
|
if: startsWith(matrix.os, 'windows') && matrix.build-system == 'cmake'
|
||||||
run: |
|
run: |
|
||||||
call "%programfiles(x86)%\Microsoft Visual Studio\%vs_version%\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
"C:\Program Files\Conan\conan\conan.exe" install ..
|
conan install ..
|
||||||
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DUSE_CONAN=ON ..
|
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DUSE_CONAN=ON ..
|
||||||
set cl=/MP
|
set cl=/MP
|
||||||
nmake /S /NOLOGO
|
nmake /S /NOLOGO
|
||||||
|
@ -109,17 +110,10 @@ jobs:
|
||||||
cp bin/chatterino.exe Chatterino2/
|
cp bin/chatterino.exe Chatterino2/
|
||||||
echo nightly > Chatterino2/modes
|
echo nightly > Chatterino2/modes
|
||||||
7z a chatterino-windows-x86-64.zip Chatterino2/
|
7z a chatterino-windows-x86-64.zip Chatterino2/
|
||||||
shell: cmd
|
|
||||||
|
|
||||||
- name: Ensure build succeeded (Windows)
|
|
||||||
if: startsWith(matrix.os, 'windows')
|
|
||||||
run: |
|
|
||||||
cd build
|
|
||||||
ls Chatterino2/chatterino.exe
|
|
||||||
|
|
||||||
- name: Upload artifact (Windows)
|
- name: Upload artifact (Windows)
|
||||||
if: startsWith(matrix.os, 'windows')
|
if: startsWith(matrix.os, 'windows')
|
||||||
uses: actions/upload-artifact@v2.2.2
|
uses: actions/upload-artifact@v2.2.3
|
||||||
with:
|
with:
|
||||||
name: chatterino-windows-x86-64-${{ matrix.qt-version }}-${{ matrix.build-system }}.zip
|
name: chatterino-windows-x86-64-${{ matrix.qt-version }}-${{ matrix.build-system }}.zip
|
||||||
path: build/chatterino-windows-x86-64.zip
|
path: build/chatterino-windows-x86-64.zip
|
||||||
|
@ -176,7 +170,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload artifact (Ubuntu)
|
- name: Upload artifact (Ubuntu)
|
||||||
if: startsWith(matrix.os, 'ubuntu')
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
uses: actions/upload-artifact@v2.2.2
|
uses: actions/upload-artifact@v2.2.3
|
||||||
with:
|
with:
|
||||||
name: Chatterino-x86_64-${{ matrix.qt-version }}-${{ matrix.build-system }}.AppImage
|
name: Chatterino-x86_64-${{ matrix.qt-version }}-${{ matrix.build-system }}.AppImage
|
||||||
path: build/Chatterino-x86_64.AppImage
|
path: build/Chatterino-x86_64.AppImage
|
||||||
|
@ -221,7 +215,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload artifact (MacOS)
|
- name: Upload artifact (MacOS)
|
||||||
if: startsWith(matrix.os, 'macos')
|
if: startsWith(matrix.os, 'macos')
|
||||||
uses: actions/upload-artifact@v2.2.2
|
uses: actions/upload-artifact@v2.2.3
|
||||||
with:
|
with:
|
||||||
name: chatterino-osx-${{ matrix.qt-version }}-${{ matrix.build-system }}.dmg
|
name: chatterino-osx-${{ matrix.qt-version }}-${{ matrix.build-system }}.dmg
|
||||||
path: build/chatterino-osx.dmg
|
path: build/chatterino-osx.dmg
|
||||||
|
@ -245,32 +239,32 @@ jobs:
|
||||||
Nightly Build
|
Nightly Build
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|
||||||
- uses: actions/download-artifact@v2.0.8
|
- uses: actions/download-artifact@v2.0.9
|
||||||
with:
|
with:
|
||||||
name: chatterino-windows-x86-64-5.15.2-qmake.zip
|
name: chatterino-windows-x86-64-5.15.2-qmake.zip
|
||||||
path: windows/
|
path: windows/
|
||||||
|
|
||||||
- uses: actions/download-artifact@v2.0.8
|
- uses: actions/download-artifact@v2.0.9
|
||||||
with:
|
with:
|
||||||
name: chatterino-windows-x86-64-5.15.2-cmake.zip
|
name: chatterino-windows-x86-64-5.15.2-cmake.zip
|
||||||
path: windows-cmake/
|
path: windows-cmake/
|
||||||
|
|
||||||
- uses: actions/download-artifact@v2.0.8
|
- uses: actions/download-artifact@v2.0.9
|
||||||
with:
|
with:
|
||||||
name: Chatterino-x86_64-5.15.2-qmake.AppImage
|
name: Chatterino-x86_64-5.15.2-qmake.AppImage
|
||||||
path: linux/
|
path: linux/
|
||||||
|
|
||||||
- uses: actions/download-artifact@v2.0.8
|
- uses: actions/download-artifact@v2.0.9
|
||||||
with:
|
with:
|
||||||
name: Chatterino-x86_64-5.15.2-cmake.AppImage
|
name: Chatterino-x86_64-5.15.2-cmake.AppImage
|
||||||
path: linux-cmake/
|
path: linux-cmake/
|
||||||
|
|
||||||
- uses: actions/download-artifact@v2.0.8
|
- uses: actions/download-artifact@v2.0.9
|
||||||
with:
|
with:
|
||||||
name: chatterino-osx-5.15.2-qmake.dmg
|
name: chatterino-osx-5.15.2-qmake.dmg
|
||||||
path: macos/
|
path: macos/
|
||||||
|
|
||||||
- uses: actions/download-artifact@v2.0.8
|
- uses: actions/download-artifact@v2.0.9
|
||||||
with:
|
with:
|
||||||
name: chatterino-osx-5.15.2-cmake.dmg
|
name: chatterino-osx-5.15.2-cmake.dmg
|
||||||
path: macos-cmake/
|
path: macos-cmake/
|
||||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -25,3 +25,6 @@
|
||||||
[submodule "lib/websocketpp"]
|
[submodule "lib/websocketpp"]
|
||||||
path = lib/websocketpp
|
path = lib/websocketpp
|
||||||
url = https://github.com/ziocleto/websocketpp
|
url = https://github.com/ziocleto/websocketpp
|
||||||
|
[submodule "cmake/sanitizers-cmake"]
|
||||||
|
path = cmake/sanitizers-cmake
|
||||||
|
url = https://github.com/arsenm/sanitizers-cmake
|
||||||
|
|
|
@ -6,8 +6,25 @@ Note on Qt version compatibility: If you are installing Qt from a package manage
|
||||||
|
|
||||||
_most likely works the same for other Debian-like distros_
|
_most likely works the same for other Debian-like distros_
|
||||||
|
|
||||||
1. Install dependencies (and the C++ IDE Qt Creator) `sudo apt install qtcreator qtmultimedia5-dev libqt5svg5-dev libboost-dev libssl-dev libboost-system-dev libboost-filesystem-dev cmake`
|
1. Install dependencies `sudo apt install qttools5-dev qtmultimedia5-dev libqt5svg5-dev libboost-dev libssl-dev libboost-system-dev libboost-filesystem-dev cmake g++`
|
||||||
1. Open `chatterino.pro` with QT Creator and build
|
|
||||||
|
### Through Qt Creator
|
||||||
|
|
||||||
|
1. Install C++ IDE Qt Creator `sudo apt install qtcreator`
|
||||||
|
1. Open `chatterino.pro` with Qt Creator and select build
|
||||||
|
|
||||||
|
### Manually
|
||||||
|
|
||||||
|
1. go into project directory
|
||||||
|
1. create build folder `mkdir build && cd build`
|
||||||
|
|
||||||
|
#### Using QMake
|
||||||
|
|
||||||
|
1. `qmake .. && make`
|
||||||
|
|
||||||
|
#### Using CMake
|
||||||
|
|
||||||
|
1. `cmake .. && make`
|
||||||
|
|
||||||
## Arch Linux
|
## Arch Linux
|
||||||
|
|
||||||
|
@ -17,15 +34,15 @@ _most likely works the same for other Debian-like distros_
|
||||||
|
|
||||||
### Manually
|
### Manually
|
||||||
|
|
||||||
1. `sudo pacman -S qt5-base qt5-multimedia qt5-svg gst-plugins-ugly gst-plugins-good boost rapidjson pkgconf openssl cmake`
|
1. `sudo pacman -S qt5-base qt5-multimedia qt5-svg qt5-tools gst-plugins-ugly gst-plugins-good boost rapidjson pkgconf openssl cmake`
|
||||||
1. go into project directory
|
1. go into project directory
|
||||||
1. create build folder `mkdir build && cd build`
|
1. create build folder `mkdir build && cd build`
|
||||||
|
|
||||||
### Using QMake
|
#### Using QMake
|
||||||
|
|
||||||
1. `qmake .. && make`
|
1. `qmake .. && make`
|
||||||
|
|
||||||
### Using CMake
|
#### Using CMake
|
||||||
|
|
||||||
1. `cmake .. && make`
|
1. `cmake .. && make`
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ Note: This installation will take about 1.5 GB of disk space.
|
||||||
|
|
||||||
### For our websocket library, we need OpenSSL 1.1
|
### For our websocket library, we need OpenSSL 1.1
|
||||||
|
|
||||||
1. Download OpenSSL for windows, version `1.1.1i`: **[Download](https://slproweb.com/download/Win64OpenSSL-1_1_1i.exe)**
|
1. Download OpenSSL for windows, version `1.1.1j`: **[Download](https://slproweb.com/download/Win64OpenSSL-1_1_1j.exe)**
|
||||||
2. When prompted, install OpenSSL to `C:\local\openssl`
|
2. When prompted, install OpenSSL to `C:\local\openssl`
|
||||||
3. When prompted, copy the OpenSSL DLLs to "The OpenSSL binaries (/bin) directory".
|
3. When prompted, copy the OpenSSL DLLs to "The OpenSSL binaries (/bin) directory".
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
- Major: Added clip creation support. You can create clips with `/clip` command, `Alt+X` keybind or `Create a clip` option in split header's context menu. This requires a new authentication scope so re-authentication will be required to use it. (#2271, #2377, #2528)
|
- Major: Added clip creation support. You can create clips with `/clip` command, `Alt+X` keybind or `Create a clip` option in split header's context menu. This requires a new authentication scope so re-authentication will be required to use it. (#2271, #2377, #2528)
|
||||||
- Major: Added "Channel Filters". See https://wiki.chatterino.com/Filters/ for how they work or how to configure them. (#1748, #2083, #2090, #2200, #2225)
|
- Major: Added "Channel Filters". See https://wiki.chatterino.com/Filters/ for how they work or how to configure them. (#1748, #2083, #2090, #2200, #2225)
|
||||||
- Major: Added Streamer Mode configuration (under `Settings -> General`), where you can select which features of Chatterino should behave differently when you are in Streamer Mode. (#2001, #2316, #2342, #2376)
|
- Major: Added Streamer Mode configuration (under `Settings -> General`), where you can select which features of Chatterino should behave differently when you are in Streamer Mode. (#2001, #2316, #2342, #2376)
|
||||||
- Major: Color mentions to match the mentioned users. You can disable this by unchecking "Color @usernames" under `Settings -> General -> Advanced (misc.)`. (#1963, #2284)
|
- Major: Add `/settitle` and `/setgame` commands, originally made for Mm2PL/Dankerino. (#2534, #2609)
|
||||||
|
- Major: Color mentions to match the mentioned users. You can disable this by unchecking "Color @usernames" under `Settings -> General -> Advanced (misc.)`. (#1963, #2284, #2597)
|
||||||
- Major: Commands `/ignore` and `/unignore` have been renamed to `/block` and `/unblock` in order to keep consistency with Twitch's terms. (#2370)
|
- Major: Commands `/ignore` and `/unignore` have been renamed to `/block` and `/unblock` in order to keep consistency with Twitch's terms. (#2370)
|
||||||
- Major: Added support for bit emotes - the ones you unlock after cheering to streamer. (#2550)
|
- Major: Added support for bit emotes - the ones you unlock after cheering to streamer. (#2550)
|
||||||
- Minor: Added `/clearmessages` command - does what "Burger menu -> More -> Clear messages" does. (#2485)
|
- Minor: Added `/clearmessages` command - does what "Burger menu -> More -> Clear messages" does. (#2485)
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
- Minor: Show channels live now enabled by default
|
- Minor: Show channels live now enabled by default
|
||||||
- Minor: Bold usernames enabled by default
|
- Minor: Bold usernames enabled by default
|
||||||
- Minor: Improve UX of the "Login expired!" message (#2029)
|
- Minor: Improve UX of the "Login expired!" message (#2029)
|
||||||
- Minor: PageUp and PageDown now scroll in the selected split (#2070, #2081)
|
- Minor: PageUp and PageDown now scroll in the selected split and in the emote popup (#2070, #2081, #2410, #2607)
|
||||||
- Minor: Allow highlights to be excluded from `/mentions`. Excluded highlights will not trigger tab highlights either. (#1793, #2036)
|
- Minor: Allow highlights to be excluded from `/mentions`. Excluded highlights will not trigger tab highlights either. (#1793, #2036)
|
||||||
- Minor: Flag all popup dialogs as actual dialogs so they get the relevant window manager hints (#1843, #2182, #2185, #2232, #2234)
|
- Minor: Flag all popup dialogs as actual dialogs so they get the relevant window manager hints (#1843, #2182, #2185, #2232, #2234)
|
||||||
- Minor: Don't show update button for nightly builds on macOS and Linux, this was already the case for Windows (#2163, #2164)
|
- Minor: Don't show update button for nightly builds on macOS and Linux, this was already the case for Windows (#2163, #2164)
|
||||||
|
@ -59,6 +60,7 @@
|
||||||
- Minor: Added `/streamlink` command. Usage: `/streamlink <channel>`. You can also use the command without arguments in any twitch channel to open it in streamlink. (#2443, #2495)
|
- Minor: Added `/streamlink` command. Usage: `/streamlink <channel>`. You can also use the command without arguments in any twitch channel to open it in streamlink. (#2443, #2495)
|
||||||
- Minor: Humanized all numbers visible to end-users. (#2488)
|
- Minor: Humanized all numbers visible to end-users. (#2488)
|
||||||
- Minor: Added a context menu to avatar in usercard. It opens on right-clicking the avatar in usercard. (#2517)
|
- Minor: Added a context menu to avatar in usercard. It opens on right-clicking the avatar in usercard. (#2517)
|
||||||
|
- Minor: Handle messages that users can share after unlocking a new bits badge. (#2611)
|
||||||
- Bugfix: Fix crash occurring when pressing Escape in the Color Picker Dialog (#1843)
|
- Bugfix: Fix crash occurring when pressing Escape in the Color Picker Dialog (#1843)
|
||||||
- Bugfix: Fix bug where the "check user follow state" event could trigger a network request requesting the user to follow or unfollow a user. By itself its quite harmless as it just repeats to Twitch the same follow state we had, so no follows should have been lost by this but it meant there was a rogue network request that was fired that could cause a crash (#1906)
|
- Bugfix: Fix bug where the "check user follow state" event could trigger a network request requesting the user to follow or unfollow a user. By itself its quite harmless as it just repeats to Twitch the same follow state we had, so no follows should have been lost by this but it meant there was a rogue network request that was fired that could cause a crash (#1906)
|
||||||
- Bugfix: /usercard command will now respect the "Automatically close user popup" setting (#1918)
|
- Bugfix: /usercard command will now respect the "Automatically close user popup" setting (#1918)
|
||||||
|
@ -81,11 +83,14 @@
|
||||||
- Bugfix: Fix anonymous users being pinged by "username" justinfan64537 (#2156, #2352)
|
- Bugfix: Fix anonymous users being pinged by "username" justinfan64537 (#2156, #2352)
|
||||||
- Bugfix: Fixed hidden tooltips when always on top is active (#2384)
|
- Bugfix: Fixed hidden tooltips when always on top is active (#2384)
|
||||||
- Bugfix: Fix CLI arguments (`--help`, `--version`, `--channels`) not being respected (#2368, #2190)
|
- Bugfix: Fix CLI arguments (`--help`, `--version`, `--channels`) not being respected (#2368, #2190)
|
||||||
|
- Bugfix: Fixed search field not being focused on popup open (#2540)
|
||||||
- Bugfix: Fix Twitch cheer emotes not displaying tooltips when hovered (#2434, #2503)
|
- Bugfix: Fix Twitch cheer emotes not displaying tooltips when hovered (#2434, #2503)
|
||||||
- Bugfix: Fix BTTV/FFZ channel emotes saying unknown error when no emotes found (#2542)
|
- Bugfix: Fix BTTV/FFZ channel emotes saying unknown error when no emotes found (#2542)
|
||||||
- Bugfix: Fix directory not opening when clicking "Open AppData Directory" setting button on macOS (#2531, #2537)
|
- Bugfix: Fix directory not opening when clicking "Open AppData Directory" setting button on macOS (#2531, #2537)
|
||||||
- Bugfix: Fix quickswitcher not respecting order of tabs when filtering (#2519, #2561)
|
- Bugfix: Fix quickswitcher not respecting order of tabs when filtering (#2519, #2561)
|
||||||
- Bugfix: Fix GNOME not associating Chatterino's window with its desktop entry (#1863, #2587)
|
- Bugfix: Fix GNOME not associating Chatterino's window with its desktop entry (#1863, #2587)
|
||||||
|
- Bugfix: Fix buffer overflow in emoji parsing. (#2602)
|
||||||
|
- Bugfix: Fix windows being brought back to life after the settings dialog was closed. (#1892, #2613)
|
||||||
- Dev: Updated minimum required Qt framework version to 5.12. (#2210)
|
- Dev: Updated minimum required Qt framework version to 5.12. (#2210)
|
||||||
- Dev: Migrated `Kraken::getUser` to Helix (#2260)
|
- Dev: Migrated `Kraken::getUser` to Helix (#2260)
|
||||||
- Dev: Migrated `TwitchAccount::(un)followUser` from Kraken to Helix and moved it to `Helix::(un)followUser`. (#2306)
|
- Dev: Migrated `TwitchAccount::(un)followUser` from Kraken to Helix and moved it to `Helix::(un)followUser`. (#2306)
|
||||||
|
|
|
@ -4,6 +4,7 @@ include(FeatureSummary)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH
|
list(APPEND CMAKE_MODULE_PATH
|
||||||
"${CMAKE_SOURCE_DIR}/cmake"
|
"${CMAKE_SOURCE_DIR}/cmake"
|
||||||
|
"${CMAKE_SOURCE_DIR}/cmake/sanitizers-cmake/cmake"
|
||||||
)
|
)
|
||||||
|
|
||||||
project(chatterino VERSION 2.2.3)
|
project(chatterino VERSION 2.2.3)
|
||||||
|
@ -44,6 +45,8 @@ if (WIN32)
|
||||||
find_package(WinToast REQUIRED)
|
find_package(WinToast REQUIRED)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
find_package(Sanitizers)
|
||||||
|
|
||||||
# Find boost on the system
|
# Find boost on the system
|
||||||
find_package(Boost REQUIRED)
|
find_package(Boost REQUIRED)
|
||||||
|
|
||||||
|
|
1
cmake/sanitizers-cmake
Submodule
1
cmake/sanitizers-cmake
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 99e159ec9bc8dd362b08d18436bd40ff0648417b
|
|
@ -13,8 +13,7 @@
|
||||||
</summary>
|
</summary>
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
Chatterino 2 is the second installment of the Twitch chat client series
|
Chatterino is a chat client for Twitch chat. It aims to be an improved/extended version of the Twitch web chat.
|
||||||
"Chatterino".
|
|
||||||
</p>
|
</p>
|
||||||
</description>
|
</description>
|
||||||
<screenshots>
|
<screenshots>
|
||||||
|
|
|
@ -13,7 +13,7 @@ AB_SETTINGS_CLASS *AB_SETTINGS_CLASS::instance = nullptr;
|
||||||
void _actuallyRegisterSetting(
|
void _actuallyRegisterSetting(
|
||||||
std::weak_ptr<pajlada::Settings::SettingData> setting)
|
std::weak_ptr<pajlada::Settings::SettingData> setting)
|
||||||
{
|
{
|
||||||
_settings.push_back(setting);
|
_settings.push_back(std::move(setting));
|
||||||
}
|
}
|
||||||
|
|
||||||
AB_SETTINGS_CLASS::AB_SETTINGS_CLASS(const QString &settingsDirectory)
|
AB_SETTINGS_CLASS::AB_SETTINGS_CLASS(const QString &settingsDirectory)
|
||||||
|
|
|
@ -460,6 +460,7 @@ endif ()
|
||||||
source_group(TREE ${CMAKE_SOURCE_DIR} FILES ${SOURCE_FILES})
|
source_group(TREE ${CMAKE_SOURCE_DIR} FILES ${SOURCE_FILES})
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
|
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
|
||||||
|
add_sanitizers(${PROJECT_NAME})
|
||||||
|
|
||||||
target_precompile_headers(${PROJECT_NAME} PRIVATE PrecompiledHeader.hpp)
|
target_precompile_headers(${PROJECT_NAME} PRIVATE PrecompiledHeader.hpp)
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ void Args::applyCustomChannelLayout(const QString &argValue)
|
||||||
return QRect(-1, -1, -1, -1);
|
return QRect(-1, -1, -1, -1);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
window.geometry_ = std::move(configMainLayout);
|
window.geometry_ = configMainLayout;
|
||||||
|
|
||||||
QStringList channelArgList = argValue.split(";");
|
QStringList channelArgList = argValue.split(";");
|
||||||
for (const QString &channelArg : channelArgList)
|
for (const QString &channelArg : channelArgList)
|
||||||
|
|
|
@ -320,13 +320,13 @@ void Channel::onConnected()
|
||||||
// Indirect channel
|
// Indirect channel
|
||||||
//
|
//
|
||||||
IndirectChannel::Data::Data(ChannelPtr _channel, Channel::Type _type)
|
IndirectChannel::Data::Data(ChannelPtr _channel, Channel::Type _type)
|
||||||
: channel(_channel)
|
: channel(std::move(_channel))
|
||||||
, type(_type)
|
, type(_type)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IndirectChannel::IndirectChannel(ChannelPtr channel, Channel::Type type)
|
IndirectChannel::IndirectChannel(ChannelPtr channel, Channel::Type type)
|
||||||
: data_(std::make_unique<Data>(channel, type))
|
: data_(std::make_unique<Data>(std::move(channel), type))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +339,7 @@ void IndirectChannel::reset(ChannelPtr channel)
|
||||||
{
|
{
|
||||||
assert(this->data_->type != Channel::Type::Direct);
|
assert(this->data_->type != Channel::Type::Direct);
|
||||||
|
|
||||||
this->data_->channel = channel;
|
this->data_->channel = std::move(channel);
|
||||||
this->data_->changed.invoke();
|
this->data_->changed.invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace chatterino {
|
||||||
|
|
||||||
void _registerSetting(std::weak_ptr<pajlada::Settings::SettingData> setting)
|
void _registerSetting(std::weak_ptr<pajlada::Settings::SettingData> setting)
|
||||||
{
|
{
|
||||||
_actuallyRegisterSetting(setting);
|
_actuallyRegisterSetting(std::move(setting));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -19,6 +19,7 @@ enum class NetworkRequestType {
|
||||||
Post,
|
Post,
|
||||||
Put,
|
Put,
|
||||||
Delete,
|
Delete,
|
||||||
|
Patch,
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -116,6 +116,19 @@ void loadUncached(const std::shared_ptr<NetworkData> &data)
|
||||||
return NetworkManager::accessManager.post(
|
return NetworkManager::accessManager.post(
|
||||||
data->request_, data->payload_);
|
data->request_, data->payload_);
|
||||||
}
|
}
|
||||||
|
case NetworkRequestType::Patch:
|
||||||
|
if (data->multiPartPayload_)
|
||||||
|
{
|
||||||
|
assert(data->payload_.isNull());
|
||||||
|
|
||||||
|
return NetworkManager::accessManager.sendCustomRequest(
|
||||||
|
data->request_, "PATCH", data->multiPartPayload_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NetworkManager::accessManager.sendCustomRequest(
|
||||||
|
data->request_, "PATCH", data->payload_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -643,7 +643,85 @@ void CommandController::initialize(Settings &, Paths &paths)
|
||||||
getApp()->windows->getMainWindow().getNotebook().getSelectedPage());
|
getApp()->windows->getMainWindow().getNotebook().getSelectedPage());
|
||||||
|
|
||||||
currentPage->getSelectedSplit()->getChannelView().clearMessages();
|
currentPage->getSelectedSplit()->getChannelView().clearMessages();
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
this->registerCommand("/settitle", [](const QStringList &words,
|
||||||
|
ChannelPtr channel) {
|
||||||
|
if (words.size() < 2)
|
||||||
|
{
|
||||||
|
channel->addMessage(
|
||||||
|
makeSystemMessage("Usage: /settitle <stream title>."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get()))
|
||||||
|
{
|
||||||
|
auto status = twitchChannel->accessStreamStatus();
|
||||||
|
auto title = words.mid(1).join(" ");
|
||||||
|
getHelix()->updateChannel(
|
||||||
|
twitchChannel->roomId(), "", "", title,
|
||||||
|
[channel, title](NetworkResult) {
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
QString("Updated title to %1").arg(title)));
|
||||||
|
},
|
||||||
|
[channel] {
|
||||||
|
channel->addMessage(
|
||||||
|
makeSystemMessage("Title update failed! Are you "
|
||||||
|
"missing the required scope?"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
"Unable to set title of non-Twitch channel."));
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
this->registerCommand("/setgame", [](const QStringList &words,
|
||||||
|
ChannelPtr channel) {
|
||||||
|
if (words.size() < 2)
|
||||||
|
{
|
||||||
|
channel->addMessage(
|
||||||
|
makeSystemMessage("Usage: /setgame <stream game>."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get()))
|
||||||
|
{
|
||||||
|
getHelix()->searchGames(
|
||||||
|
words.mid(1).join(" "),
|
||||||
|
[channel, twitchChannel](std::vector<HelixGame> games) {
|
||||||
|
if (games.empty())
|
||||||
|
{
|
||||||
|
channel->addMessage(
|
||||||
|
makeSystemMessage("Game not found."));
|
||||||
|
}
|
||||||
|
else // 1 or more games
|
||||||
|
{
|
||||||
|
auto status = twitchChannel->accessStreamStatus();
|
||||||
|
getHelix()->updateChannel(
|
||||||
|
twitchChannel->roomId(), games.at(0).id, "", "",
|
||||||
|
[channel, games](NetworkResult) {
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
QString("Updated game to %1")
|
||||||
|
.arg(games.at(0).name)));
|
||||||
|
},
|
||||||
|
[channel] {
|
||||||
|
channel->addMessage(makeSystemMessage(
|
||||||
|
"Game update failed! Are you "
|
||||||
|
"missing the required scope?"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[channel] {
|
||||||
|
channel->addMessage(
|
||||||
|
makeSystemMessage("Failed to look up game."));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
channel->addMessage(
|
||||||
|
makeSystemMessage("Unable to set game of non-Twitch channel."));
|
||||||
|
}
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ HighlightPhrase::HighlightPhrase(const QString &pattern, bool showInMentions,
|
||||||
, isRegex_(isRegex)
|
, isRegex_(isRegex)
|
||||||
, isCaseSensitive_(isCaseSensitive)
|
, isCaseSensitive_(isCaseSensitive)
|
||||||
, soundUrl_(soundUrl)
|
, soundUrl_(soundUrl)
|
||||||
, color_(color)
|
, color_(std::move(color))
|
||||||
, regex_(isRegex_
|
, regex_(isRegex_
|
||||||
? pattern
|
? pattern
|
||||||
: REGEX_START_BOUNDARY + QRegularExpression::escape(pattern) +
|
: REGEX_START_BOUNDARY + QRegularExpression::escape(pattern) +
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MessageLayout::MessageLayout(MessagePtr message)
|
MessageLayout::MessageLayout(MessagePtr message)
|
||||||
: message_(message)
|
: message_(std::move(message))
|
||||||
, container_(std::make_shared<MessageLayoutContainer>())
|
, container_(std::make_shared<MessageLayoutContainer>())
|
||||||
{
|
{
|
||||||
DebugCount::increase("message layout");
|
DebugCount::increase("message layout");
|
||||||
|
|
|
@ -88,7 +88,7 @@ FlagsEnum<MessageElementFlag> MessageLayoutElement::getFlags() const
|
||||||
ImageLayoutElement::ImageLayoutElement(MessageElement &creator, ImagePtr image,
|
ImageLayoutElement::ImageLayoutElement(MessageElement &creator, ImagePtr image,
|
||||||
const QSize &size)
|
const QSize &size)
|
||||||
: MessageLayoutElement(creator, size)
|
: MessageLayoutElement(creator, size)
|
||||||
, image_(image)
|
, image_(std::move(image))
|
||||||
{
|
{
|
||||||
this->trailingSpace = creator.hasTrailingSpace();
|
this->trailingSpace = creator.hasTrailingSpace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ const std::shared_ptr<QColor> ColorProvider::color(ColorType type) const
|
||||||
void ColorProvider::updateColor(ColorType type, QColor color)
|
void ColorProvider::updateColor(ColorType type, QColor color)
|
||||||
{
|
{
|
||||||
auto colorPtr = this->typeColorMap_.at(type);
|
auto colorPtr = this->typeColorMap_.at(type);
|
||||||
*colorPtr = color;
|
*colorPtr = std::move(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<QColor> ColorProvider::recentColors() const
|
QSet<QColor> ColorProvider::recentColors() const
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace {
|
||||||
const rapidjson::Value &unparsedEmoji,
|
const rapidjson::Value &unparsedEmoji,
|
||||||
QString shortCode = QString())
|
QString shortCode = QString())
|
||||||
{
|
{
|
||||||
static uint unicodeBytes[4];
|
std::array<uint32_t, 7> unicodeBytes;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool apple;
|
bool apple;
|
||||||
|
@ -91,11 +91,12 @@ namespace {
|
||||||
|
|
||||||
for (const QString &unicodeCharacter : unicodeCharacters)
|
for (const QString &unicodeCharacter : unicodeCharacters)
|
||||||
{
|
{
|
||||||
unicodeBytes[numUnicodeBytes++] =
|
unicodeBytes.at(numUnicodeBytes++) =
|
||||||
QString(unicodeCharacter).toUInt(nullptr, 16);
|
QString(unicodeCharacter).toUInt(nullptr, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
emojiData->value = QString::fromUcs4(unicodeBytes, numUnicodeBytes);
|
emojiData->value =
|
||||||
|
QString::fromUcs4(unicodeBytes.data(), numUnicodeBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// getToneNames takes a tones and returns their names in the same order
|
// getToneNames takes a tones and returns their names in the same order
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "singletons/Settings.hpp"
|
#include "singletons/Settings.hpp"
|
||||||
#include "singletons/WindowManager.hpp"
|
#include "singletons/WindowManager.hpp"
|
||||||
#include "util/FormatTime.hpp"
|
#include "util/FormatTime.hpp"
|
||||||
|
#include "util/Helpers.hpp"
|
||||||
#include "util/IrcHelpers.hpp"
|
#include "util/IrcHelpers.hpp"
|
||||||
|
|
||||||
#include <IrcMessage>
|
#include <IrcMessage>
|
||||||
|
@ -579,10 +580,11 @@ std::vector<MessagePtr> IrcMessageHandler::parseUserNoticeMessage(
|
||||||
content = parameters[1];
|
content = parameters[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgType == "sub" || msgType == "resub" || msgType == "subgift")
|
if (msgType == "sub" || msgType == "resub" || msgType == "subgift" ||
|
||||||
|
msgType == "bitsbadgetier")
|
||||||
{
|
{
|
||||||
// Sub-specific message. I think it's only allowed for "resub" messages
|
// Sub-specific and bits badge upgrade specific message.
|
||||||
// atm
|
// It's only allowed for "resub" messages.
|
||||||
if (!content.isEmpty())
|
if (!content.isEmpty())
|
||||||
{
|
{
|
||||||
MessageParseArgs args;
|
MessageParseArgs args;
|
||||||
|
@ -600,8 +602,17 @@ std::vector<MessagePtr> IrcMessageHandler::parseUserNoticeMessage(
|
||||||
|
|
||||||
if (it != tags.end())
|
if (it != tags.end())
|
||||||
{
|
{
|
||||||
auto b =
|
QString messageText = it.value().toString();
|
||||||
MessageBuilder(systemMessage, parseTagString(it.value().toString()),
|
|
||||||
|
if (msgType == "bitsbadgetier")
|
||||||
|
{
|
||||||
|
messageText = QString("%1 just earned a new %2 Bits badge!")
|
||||||
|
.arg(tags.value("display-name").toString())
|
||||||
|
.arg(kFormatNumbers(
|
||||||
|
tags.value("msg-param-threshold").toInt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto b = MessageBuilder(systemMessage, parseTagString(messageText),
|
||||||
calculateMessageTimestamp(message));
|
calculateMessageTimestamp(message));
|
||||||
|
|
||||||
b->flags.set(MessageFlag::Subscription);
|
b->flags.set(MessageFlag::Subscription);
|
||||||
|
@ -628,10 +639,11 @@ void IrcMessageHandler::handleUserNoticeMessage(Communi::IrcMessage *message,
|
||||||
content = parameters[1];
|
content = parameters[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgType == "sub" || msgType == "resub" || msgType == "subgift")
|
if (msgType == "sub" || msgType == "resub" || msgType == "subgift" ||
|
||||||
|
msgType == "bitsbadgetier")
|
||||||
{
|
{
|
||||||
// Sub-specific message. I think it's only allowed for "resub" messages
|
// Sub-specific and bits badge upgrade specific message.
|
||||||
// atm
|
// It's only allowed for "resub" messages.
|
||||||
if (!content.isEmpty())
|
if (!content.isEmpty())
|
||||||
{
|
{
|
||||||
this->addMessage(message, target, content, server, true, false);
|
this->addMessage(message, target, content, server, true, false);
|
||||||
|
@ -642,8 +654,17 @@ void IrcMessageHandler::handleUserNoticeMessage(Communi::IrcMessage *message,
|
||||||
|
|
||||||
if (it != tags.end())
|
if (it != tags.end())
|
||||||
{
|
{
|
||||||
auto b =
|
QString messageText = it.value().toString();
|
||||||
MessageBuilder(systemMessage, parseTagString(it.value().toString()),
|
|
||||||
|
if (msgType == "bitsbadgetier")
|
||||||
|
{
|
||||||
|
messageText = QString("%1 just earned a new %2 Bits badge!")
|
||||||
|
.arg(tags.value("display-name").toString())
|
||||||
|
.arg(kFormatNumbers(
|
||||||
|
tags.value("msg-param-threshold").toInt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto b = MessageBuilder(systemMessage, parseTagString(messageText),
|
||||||
calculateMessageTimestamp(message));
|
calculateMessageTimestamp(message));
|
||||||
|
|
||||||
b->flags.set(MessageFlag::Subscription);
|
b->flags.set(MessageFlag::Subscription);
|
||||||
|
|
|
@ -64,7 +64,7 @@ QColor TwitchAccount::color()
|
||||||
|
|
||||||
void TwitchAccount::setColor(QColor color)
|
void TwitchAccount::setColor(QColor color)
|
||||||
{
|
{
|
||||||
this->color_.set(color);
|
this->color_.set(std::move(color));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TwitchAccount::setOAuthClient(const QString &newClientID)
|
bool TwitchAccount::setOAuthClient(const QString &newClientID)
|
||||||
|
@ -131,7 +131,7 @@ void TwitchAccount::blockUser(QString userId, std::function<void()> onSuccess,
|
||||||
}
|
}
|
||||||
onSuccess();
|
onSuccess();
|
||||||
},
|
},
|
||||||
onFailure);
|
std::move(onFailure));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchAccount::unblockUser(QString userId, std::function<void()> onSuccess,
|
void TwitchAccount::unblockUser(QString userId, std::function<void()> onSuccess,
|
||||||
|
@ -149,7 +149,7 @@ void TwitchAccount::unblockUser(QString userId, std::function<void()> onSuccess,
|
||||||
}
|
}
|
||||||
onSuccess();
|
onSuccess();
|
||||||
},
|
},
|
||||||
onFailure);
|
std::move(onFailure));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchAccount::checkFollow(const QString targetUserID,
|
void TwitchAccount::checkFollow(const QString targetUserID,
|
||||||
|
|
|
@ -484,6 +484,7 @@ void TwitchMessageBuilder::addTextOrEmoji(const QString &string_)
|
||||||
if (match.hasMatch())
|
if (match.hasMatch())
|
||||||
{
|
{
|
||||||
QString username = match.captured(1);
|
QString username = match.captured(1);
|
||||||
|
auto originalTextColor = textColor;
|
||||||
|
|
||||||
if (this->twitchChannel != nullptr && getSettings()->colorUsernames)
|
if (this->twitchChannel != nullptr && getSettings()->colorUsernames)
|
||||||
{
|
{
|
||||||
|
@ -495,13 +496,23 @@ void TwitchMessageBuilder::addTextOrEmoji(const QString &string_)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->emplace<TextElement>(string, MessageElementFlag::BoldUsername,
|
auto prefixedUsername = '@' + username;
|
||||||
|
this->emplace<TextElement>(prefixedUsername,
|
||||||
|
MessageElementFlag::BoldUsername,
|
||||||
textColor, FontStyle::ChatMediumBold)
|
textColor, FontStyle::ChatMediumBold)
|
||||||
->setLink({Link::UserInfo, username});
|
->setLink({Link::UserInfo, username})
|
||||||
|
->setTrailingSpace(false);
|
||||||
|
|
||||||
|
this->emplace<TextElement>(prefixedUsername,
|
||||||
|
MessageElementFlag::NonBoldUsername,
|
||||||
|
textColor)
|
||||||
|
->setLink({Link::UserInfo, username})
|
||||||
|
->setTrailingSpace(false);
|
||||||
|
|
||||||
|
this->emplace<TextElement>(string.remove(prefixedUsername),
|
||||||
|
MessageElementFlag::Text,
|
||||||
|
originalTextColor);
|
||||||
|
|
||||||
this->emplace<TextElement>(
|
|
||||||
string, MessageElementFlag::NonBoldUsername, textColor)
|
|
||||||
->setLink({Link::UserInfo, username});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,6 +525,8 @@ void TwitchMessageBuilder::addTextOrEmoji(const QString &string_)
|
||||||
|
|
||||||
if (match.hasMatch() && chatters->contains(username))
|
if (match.hasMatch() && chatters->contains(username))
|
||||||
{
|
{
|
||||||
|
auto originalTextColor = textColor;
|
||||||
|
|
||||||
if (getSettings()->colorUsernames)
|
if (getSettings()->colorUsernames)
|
||||||
{
|
{
|
||||||
if (auto userColor =
|
if (auto userColor =
|
||||||
|
@ -524,13 +537,21 @@ void TwitchMessageBuilder::addTextOrEmoji(const QString &string_)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->emplace<TextElement>(string, MessageElementFlag::BoldUsername,
|
this->emplace<TextElement>(username,
|
||||||
|
MessageElementFlag::BoldUsername,
|
||||||
textColor, FontStyle::ChatMediumBold)
|
textColor, FontStyle::ChatMediumBold)
|
||||||
->setLink({Link::UserInfo, username});
|
->setLink({Link::UserInfo, username})
|
||||||
|
->setTrailingSpace(false);
|
||||||
|
|
||||||
this->emplace<TextElement>(
|
this->emplace<TextElement>(
|
||||||
string, MessageElementFlag::NonBoldUsername, textColor)
|
username, MessageElementFlag::NonBoldUsername, textColor)
|
||||||
->setLink({Link::UserInfo, username});
|
->setLink({Link::UserInfo, username})
|
||||||
|
->setTrailingSpace(false);
|
||||||
|
|
||||||
|
this->emplace<TextElement>(string.remove(username),
|
||||||
|
MessageElementFlag::Text,
|
||||||
|
originalTextColor);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ void Helix::getUserByName(QString userName,
|
||||||
HelixFailureCallback failureCallback)
|
HelixFailureCallback failureCallback)
|
||||||
{
|
{
|
||||||
QStringList userIds;
|
QStringList userIds;
|
||||||
QStringList userLogins{userName};
|
QStringList userLogins{std::move(userName)};
|
||||||
|
|
||||||
this->fetchUsers(
|
this->fetchUsers(
|
||||||
userIds, userLogins,
|
userIds, userLogins,
|
||||||
|
@ -78,7 +78,7 @@ void Helix::getUserById(QString userId,
|
||||||
ResultCallback<HelixUser> successCallback,
|
ResultCallback<HelixUser> successCallback,
|
||||||
HelixFailureCallback failureCallback)
|
HelixFailureCallback failureCallback)
|
||||||
{
|
{
|
||||||
QStringList userIds{userId};
|
QStringList userIds{std::move(userId)};
|
||||||
QStringList userLogins;
|
QStringList userLogins;
|
||||||
|
|
||||||
this->fetchUsers(
|
this->fetchUsers(
|
||||||
|
@ -136,7 +136,8 @@ void Helix::getUserFollowers(
|
||||||
QString userId, ResultCallback<HelixUsersFollowsResponse> successCallback,
|
QString userId, ResultCallback<HelixUsersFollowsResponse> successCallback,
|
||||||
HelixFailureCallback failureCallback)
|
HelixFailureCallback failureCallback)
|
||||||
{
|
{
|
||||||
this->fetchUsersFollows("", userId, successCallback, failureCallback);
|
this->fetchUsersFollows("", std::move(userId), std::move(successCallback),
|
||||||
|
std::move(failureCallback));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Helix::getUserFollow(
|
void Helix::getUserFollow(
|
||||||
|
@ -145,7 +146,7 @@ void Helix::getUserFollow(
|
||||||
HelixFailureCallback failureCallback)
|
HelixFailureCallback failureCallback)
|
||||||
{
|
{
|
||||||
this->fetchUsersFollows(
|
this->fetchUsersFollows(
|
||||||
userId, targetId,
|
std::move(userId), std::move(targetId),
|
||||||
[successCallback](const auto &response) {
|
[successCallback](const auto &response) {
|
||||||
if (response.data.empty())
|
if (response.data.empty())
|
||||||
{
|
{
|
||||||
|
@ -155,7 +156,7 @@ void Helix::getUserFollow(
|
||||||
|
|
||||||
successCallback(true, response.data[0]);
|
successCallback(true, response.data[0]);
|
||||||
},
|
},
|
||||||
failureCallback);
|
std::move(failureCallback));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Helix::fetchStreams(
|
void Helix::fetchStreams(
|
||||||
|
@ -209,7 +210,7 @@ void Helix::getStreamById(QString userId,
|
||||||
ResultCallback<bool, HelixStream> successCallback,
|
ResultCallback<bool, HelixStream> successCallback,
|
||||||
HelixFailureCallback failureCallback)
|
HelixFailureCallback failureCallback)
|
||||||
{
|
{
|
||||||
QStringList userIds{userId};
|
QStringList userIds{std::move(userId)};
|
||||||
QStringList userLogins;
|
QStringList userLogins;
|
||||||
|
|
||||||
this->fetchStreams(
|
this->fetchStreams(
|
||||||
|
@ -230,7 +231,7 @@ void Helix::getStreamByName(QString userName,
|
||||||
HelixFailureCallback failureCallback)
|
HelixFailureCallback failureCallback)
|
||||||
{
|
{
|
||||||
QStringList userIds;
|
QStringList userIds;
|
||||||
QStringList userLogins{userName};
|
QStringList userLogins{std::move(userName)};
|
||||||
|
|
||||||
this->fetchStreams(
|
this->fetchStreams(
|
||||||
userIds, userLogins,
|
userIds, userLogins,
|
||||||
|
@ -295,11 +296,47 @@ void Helix::fetchGames(QStringList gameIds, QStringList gameNames,
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Helix::searchGames(QString gameName,
|
||||||
|
ResultCallback<std::vector<HelixGame>> successCallback,
|
||||||
|
HelixFailureCallback failureCallback)
|
||||||
|
{
|
||||||
|
QUrlQuery urlQuery;
|
||||||
|
urlQuery.addQueryItem("query", gameName);
|
||||||
|
|
||||||
|
this->makeRequest("search/categories", urlQuery)
|
||||||
|
.onSuccess([successCallback, failureCallback](auto result) -> Outcome {
|
||||||
|
auto root = result.parseJson();
|
||||||
|
auto data = root.value("data");
|
||||||
|
|
||||||
|
if (!data.isArray())
|
||||||
|
{
|
||||||
|
failureCallback();
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HelixGame> games;
|
||||||
|
|
||||||
|
for (const auto &jsonStream : data.toArray())
|
||||||
|
{
|
||||||
|
games.emplace_back(jsonStream.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
successCallback(games);
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
})
|
||||||
|
.onError([failureCallback](auto /*result*/) {
|
||||||
|
// TODO: make better xd
|
||||||
|
failureCallback();
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
void Helix::getGameById(QString gameId,
|
void Helix::getGameById(QString gameId,
|
||||||
ResultCallback<HelixGame> successCallback,
|
ResultCallback<HelixGame> successCallback,
|
||||||
HelixFailureCallback failureCallback)
|
HelixFailureCallback failureCallback)
|
||||||
{
|
{
|
||||||
QStringList gameIds{gameId};
|
QStringList gameIds{std::move(gameId)};
|
||||||
QStringList gameNames;
|
QStringList gameNames;
|
||||||
|
|
||||||
this->fetchGames(
|
this->fetchGames(
|
||||||
|
@ -409,7 +446,7 @@ void Helix::createClip(QString channelId,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(finallyCallback)
|
.finally(std::move(finallyCallback))
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,6 +615,48 @@ void Helix::unblockUser(QString targetUserId,
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Helix::updateChannel(QString broadcasterId, QString gameId,
|
||||||
|
QString language, QString title,
|
||||||
|
std::function<void(NetworkResult)> successCallback,
|
||||||
|
HelixFailureCallback failureCallback)
|
||||||
|
{
|
||||||
|
QUrlQuery urlQuery;
|
||||||
|
auto data = QJsonDocument();
|
||||||
|
auto obj = QJsonObject();
|
||||||
|
if (!gameId.isEmpty())
|
||||||
|
{
|
||||||
|
obj.insert("game_id", gameId);
|
||||||
|
}
|
||||||
|
if (!language.isEmpty())
|
||||||
|
{
|
||||||
|
obj.insert("broadcaster_language", language);
|
||||||
|
}
|
||||||
|
if (!title.isEmpty())
|
||||||
|
{
|
||||||
|
obj.insert("title", title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (title.isEmpty() && gameId.isEmpty() && language.isEmpty())
|
||||||
|
{
|
||||||
|
qCDebug(chatterinoCommon) << "Tried to update channel with no changes!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.setObject(obj);
|
||||||
|
urlQuery.addQueryItem("broadcaster_id", broadcasterId);
|
||||||
|
this->makeRequest("channels", urlQuery)
|
||||||
|
.type(NetworkRequestType::Patch)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.payload(data.toJson())
|
||||||
|
.onSuccess([successCallback, failureCallback](auto result) -> Outcome {
|
||||||
|
successCallback(result);
|
||||||
|
return Success;
|
||||||
|
})
|
||||||
|
.onError([failureCallback](NetworkResult result) {
|
||||||
|
failureCallback();
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
NetworkRequest Helix::makeRequest(QString url, QUrlQuery urlQuery)
|
NetworkRequest Helix::makeRequest(QString url, QUrlQuery urlQuery)
|
||||||
{
|
{
|
||||||
assert(!url.startsWith("/"));
|
assert(!url.startsWith("/"));
|
||||||
|
@ -611,8 +690,8 @@ NetworkRequest Helix::makeRequest(QString url, QUrlQuery urlQuery)
|
||||||
|
|
||||||
void Helix::update(QString clientId, QString oauthToken)
|
void Helix::update(QString clientId, QString oauthToken)
|
||||||
{
|
{
|
||||||
this->clientId = clientId;
|
this->clientId = std::move(clientId);
|
||||||
this->oauthToken = oauthToken;
|
this->oauthToken = std::move(oauthToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Helix::initialize()
|
void Helix::initialize()
|
||||||
|
|
|
@ -252,6 +252,11 @@ public:
|
||||||
ResultCallback<std::vector<HelixGame>> successCallback,
|
ResultCallback<std::vector<HelixGame>> successCallback,
|
||||||
HelixFailureCallback failureCallback);
|
HelixFailureCallback failureCallback);
|
||||||
|
|
||||||
|
// https://dev.twitch.tv/docs/api/reference#search-categories
|
||||||
|
void searchGames(QString gameName,
|
||||||
|
ResultCallback<std::vector<HelixGame>> successCallback,
|
||||||
|
HelixFailureCallback failureCallback);
|
||||||
|
|
||||||
void getGameById(QString gameId, ResultCallback<HelixGame> successCallback,
|
void getGameById(QString gameId, ResultCallback<HelixGame> successCallback,
|
||||||
HelixFailureCallback failureCallback);
|
HelixFailureCallback failureCallback);
|
||||||
|
|
||||||
|
@ -296,6 +301,12 @@ public:
|
||||||
std::function<void()> successCallback,
|
std::function<void()> successCallback,
|
||||||
HelixFailureCallback failureCallback);
|
HelixFailureCallback failureCallback);
|
||||||
|
|
||||||
|
// https://dev.twitch.tv/docs/api/reference#modify-channel-information
|
||||||
|
void updateChannel(QString broadcasterId, QString gameId, QString language,
|
||||||
|
QString title,
|
||||||
|
std::function<void(NetworkResult)> successCallback,
|
||||||
|
HelixFailureCallback failureCallback);
|
||||||
|
|
||||||
void update(QString clientId, QString oauthToken);
|
void update(QString clientId, QString oauthToken);
|
||||||
|
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
|
@ -63,8 +63,8 @@ NetworkRequest Kraken::makeRequest(QString url, QUrlQuery urlQuery)
|
||||||
|
|
||||||
void Kraken::update(QString clientId, QString oauthToken)
|
void Kraken::update(QString clientId, QString oauthToken)
|
||||||
{
|
{
|
||||||
this->clientId = clientId;
|
this->clientId = std::move(clientId);
|
||||||
this->oauthToken = oauthToken;
|
this->oauthToken = std::move(oauthToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kraken::initialize()
|
void Kraken::initialize()
|
||||||
|
|
|
@ -104,6 +104,16 @@ URL: https://dev.twitch.tv/docs/api/reference#get-channel-information
|
||||||
Used in:
|
Used in:
|
||||||
- `TwitchChannel` to refresh stream title
|
- `TwitchChannel` to refresh stream title
|
||||||
|
|
||||||
|
### Update Channel
|
||||||
|
|
||||||
|
URL: https://dev.twitch.tv/docs/api/reference#modify-channel-information
|
||||||
|
Requires `channel:manage:broadcast` scope
|
||||||
|
|
||||||
|
- We implement this in `providers/twitch/api/Helix.cpp updateChannel`
|
||||||
|
Used in:
|
||||||
|
- `/setgame` to update the game in the current channel
|
||||||
|
- `/settitle` to update the title in the current channel
|
||||||
|
|
||||||
### Create Stream Marker
|
### Create Stream Marker
|
||||||
|
|
||||||
URL: https://dev.twitch.tv/docs/api/reference/#create-stream-marker
|
URL: https://dev.twitch.tv/docs/api/reference/#create-stream-marker
|
||||||
|
@ -142,6 +152,14 @@ Requires `user:manage:blocked_users` scope
|
||||||
- `widgets/dialogs/UserInfoPopup.cpp` to unblock a user via checkbox in the usercard
|
- `widgets/dialogs/UserInfoPopup.cpp` to unblock a user via checkbox in the usercard
|
||||||
- `controllers/commands/CommandController.cpp` to unblock a user via "/unblock" command
|
- `controllers/commands/CommandController.cpp` to unblock a user via "/unblock" command
|
||||||
|
|
||||||
|
### Search Categories
|
||||||
|
|
||||||
|
URL: https://dev.twitch.tv/docs/api/reference#search-categories
|
||||||
|
|
||||||
|
- We implement this in `providers/twitch/api/Helix.cpp searchGames`
|
||||||
|
Used in:
|
||||||
|
- `controllers/commands/CommandController.cpp` in `/setgame` command to fuzzy search for game titles
|
||||||
|
|
||||||
## TMI
|
## TMI
|
||||||
|
|
||||||
The TMI api is undocumented.
|
The TMI api is undocumented.
|
||||||
|
|
|
@ -33,7 +33,7 @@ TooltipPreviewImage::TooltipPreviewImage()
|
||||||
|
|
||||||
void TooltipPreviewImage::setImage(ImagePtr image)
|
void TooltipPreviewImage::setImage(ImagePtr image)
|
||||||
{
|
{
|
||||||
this->image_ = image;
|
this->image_ = std::move(image);
|
||||||
|
|
||||||
this->refreshTooltipWidgetPixmap();
|
this->refreshTooltipWidgetPixmap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,4 +42,9 @@ QString localizeNumbers(const int &number)
|
||||||
return locale.toString(number);
|
return locale.toString(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString kFormatNumbers(const int &number)
|
||||||
|
{
|
||||||
|
return QString("%1K").arg(number / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -15,4 +15,6 @@ QString shortenString(const QString &str, unsigned maxWidth = 50);
|
||||||
|
|
||||||
QString localizeNumbers(const int &number);
|
QString localizeNumbers(const int &number);
|
||||||
|
|
||||||
|
QString kFormatNumbers(const int &number);
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -17,7 +17,7 @@ class LambdaRunnable : public QRunnable
|
||||||
public:
|
public:
|
||||||
LambdaRunnable(std::function<void()> action)
|
LambdaRunnable(std::function<void()> action)
|
||||||
{
|
{
|
||||||
this->action_ = action;
|
this->action_ = std::move(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
|
|
|
@ -143,7 +143,7 @@ void AttachedWindow::detach(const QString &winId)
|
||||||
|
|
||||||
void AttachedWindow::setChannel(ChannelPtr channel)
|
void AttachedWindow::setChannel(ChannelPtr channel)
|
||||||
{
|
{
|
||||||
this->ui_.split->setChannel(channel);
|
this->ui_.split->setChannel(std::move(channel));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachedWindow::showEvent(QShowEvent *)
|
void AttachedWindow::showEvent(QShowEvent *)
|
||||||
|
|
|
@ -244,7 +244,10 @@ void BaseWindow::init()
|
||||||
getSettings()->windowTopMost.connect(
|
getSettings()->windowTopMost.connect(
|
||||||
[this](bool topMost, auto) {
|
[this](bool topMost, auto) {
|
||||||
this->setWindowFlag(Qt::WindowStaysOnTopHint, topMost);
|
this->setWindowFlag(Qt::WindowStaysOnTopHint, topMost);
|
||||||
|
if (this->isVisible())
|
||||||
|
{
|
||||||
this->show();
|
this->show();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
this->managedConnections_);
|
this->managedConnections_);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
Label::Label(QString text, FontStyle style)
|
Label::Label(QString text, FontStyle style)
|
||||||
: Label(nullptr, text, style)
|
: Label(nullptr, std::move(text), style)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Label::Label(BaseWidget *parent, QString text, FontStyle style)
|
Label::Label(BaseWidget *parent, QString text, FontStyle style)
|
||||||
: BaseWidget(parent)
|
: BaseWidget(parent)
|
||||||
, text_(text)
|
, text_(std::move(text))
|
||||||
, fontStyle_(style)
|
, fontStyle_(style)
|
||||||
{
|
{
|
||||||
this->connections_.managedConnect(getFonts()->fontChanged, [this] {
|
this->connections_.managedConnect(getFonts()->fontChanged, [this] {
|
||||||
|
|
|
@ -26,7 +26,7 @@ StreamView::StreamView(ChannelPtr channel, const QUrl &url)
|
||||||
|
|
||||||
auto chat = layoutCreator.emplace<ChannelView>();
|
auto chat = layoutCreator.emplace<ChannelView>();
|
||||||
chat->setFixedWidth(300);
|
chat->setFixedWidth(300);
|
||||||
chat->setChannel(channel);
|
chat->setChannel(std::move(channel));
|
||||||
|
|
||||||
this->layout()->setSpacing(0);
|
this->layout()->setSpacing(0);
|
||||||
this->layout()->setMargin(0);
|
this->layout()->setMargin(0);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "singletons/WindowManager.hpp"
|
#include "singletons/WindowManager.hpp"
|
||||||
#include "util/Shortcut.hpp"
|
#include "util/Shortcut.hpp"
|
||||||
#include "widgets/Notebook.hpp"
|
#include "widgets/Notebook.hpp"
|
||||||
|
#include "widgets/Scrollbar.hpp"
|
||||||
#include "widgets/helper/ChannelView.hpp"
|
#include "widgets/helper/ChannelView.hpp"
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
@ -178,6 +179,20 @@ EmotePopup::EmotePopup(QWidget *parent)
|
||||||
createWindowShortcut(this, "CTRL+Shift+Tab", [=] {
|
createWindowShortcut(this, "CTRL+Shift+Tab", [=] {
|
||||||
notebook->selectPreviousTab();
|
notebook->selectPreviousTab();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Scroll with Page Up / Page Down
|
||||||
|
createWindowShortcut(this, "PgUp", [=] {
|
||||||
|
auto &scrollbar =
|
||||||
|
dynamic_cast<ChannelView *>(notebook->getSelectedPage())
|
||||||
|
->getScrollBar();
|
||||||
|
scrollbar.offset(-scrollbar.getLargeChange());
|
||||||
|
});
|
||||||
|
createWindowShortcut(this, "PgDown", [=] {
|
||||||
|
auto &scrollbar =
|
||||||
|
dynamic_cast<ChannelView *>(notebook->getSelectedPage())
|
||||||
|
->getScrollBar();
|
||||||
|
scrollbar.offset(scrollbar.getLargeChange());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmotePopup::loadChannel(ChannelPtr _channel)
|
void EmotePopup::loadChannel(ChannelPtr _channel)
|
||||||
|
|
|
@ -45,7 +45,7 @@ void NotificationPopup::updatePosition()
|
||||||
|
|
||||||
void NotificationPopup::addMessage(MessagePtr msg)
|
void NotificationPopup::addMessage(MessagePtr msg)
|
||||||
{
|
{
|
||||||
this->channel_->addMessage(msg);
|
this->channel_->addMessage(std::move(msg));
|
||||||
|
|
||||||
// QTimer::singleShot(5000, this, [this, msg] { this->channel->remove });
|
// QTimer::singleShot(5000, this, [this, msg] { this->channel->remove });
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ Button::Button(BaseWidget *parent)
|
||||||
|
|
||||||
void Button::setMouseEffectColor(boost::optional<QColor> color)
|
void Button::setMouseEffectColor(boost::optional<QColor> color)
|
||||||
{
|
{
|
||||||
this->mouseEffectColor_ = color;
|
this->mouseEffectColor_ = std::move(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Button::setPixmap(const QPixmap &_pixmap)
|
void Button::setPixmap(const QPixmap &_pixmap)
|
||||||
|
|
|
@ -550,7 +550,7 @@ bool ChannelView::getEnableScrollingToBottom() const
|
||||||
|
|
||||||
void ChannelView::setOverrideFlags(boost::optional<MessageElementFlags> value)
|
void ChannelView::setOverrideFlags(boost::optional<MessageElementFlags> value)
|
||||||
{
|
{
|
||||||
this->overrideFlags_ = value;
|
this->overrideFlags_ = std::move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const boost::optional<MessageElementFlags> &ChannelView::getOverrideFlags()
|
const boost::optional<MessageElementFlags> &ChannelView::getOverrideFlags()
|
||||||
|
@ -647,7 +647,7 @@ void ChannelView::setChannel(ChannelPtr underlyingChannel)
|
||||||
this->channelConnections_.push_back(this->channel_->messageAppended.connect(
|
this->channelConnections_.push_back(this->channel_->messageAppended.connect(
|
||||||
[this](MessagePtr &message,
|
[this](MessagePtr &message,
|
||||||
boost::optional<MessageFlags> overridingFlags) {
|
boost::optional<MessageFlags> overridingFlags) {
|
||||||
this->messageAppended(message, overridingFlags);
|
this->messageAppended(message, std::move(overridingFlags));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this->channelConnections_.push_back(
|
this->channelConnections_.push_back(
|
||||||
|
@ -753,7 +753,7 @@ ChannelPtr ChannelView::sourceChannel() const
|
||||||
|
|
||||||
void ChannelView::setSourceChannel(ChannelPtr sourceChannel)
|
void ChannelView::setSourceChannel(ChannelPtr sourceChannel)
|
||||||
{
|
{
|
||||||
this->sourceChannel_ = sourceChannel;
|
this->sourceChannel_ = std::move(sourceChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChannelView::hasSourceChannel() const
|
bool ChannelView::hasSourceChannel() const
|
||||||
|
|
|
@ -66,7 +66,7 @@ SearchPopup::SearchPopup(QWidget *parent)
|
||||||
|
|
||||||
void SearchPopup::setChannelFilters(FilterSetPtr filters)
|
void SearchPopup::setChannelFilters(FilterSetPtr filters)
|
||||||
{
|
{
|
||||||
this->channelFilters_ = filters;
|
this->channelFilters_ = std::move(filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchPopup::setChannel(const ChannelPtr &channel)
|
void SearchPopup::setChannel(const ChannelPtr &channel)
|
||||||
|
@ -155,6 +155,8 @@ void SearchPopup::initLayout()
|
||||||
|
|
||||||
this->setLayout(layout1);
|
this->setLayout(layout1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->searchInput_->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<MessagePredicate>> SearchPopup::parsePredicates(
|
std::vector<std::unique_ptr<MessagePredicate>> SearchPopup::parsePredicates(
|
||||||
|
|
|
@ -45,6 +45,7 @@ add_executable(${PROJECT_NAME}
|
||||||
${chatterino_SOURCES}
|
${chatterino_SOURCES}
|
||||||
${test_SOURCES}
|
${test_SOURCES}
|
||||||
)
|
)
|
||||||
|
add_sanitizers(${PROJECT_NAME})
|
||||||
|
|
||||||
# Enable autogeneration of Qts MOC/RCC/UIC
|
# Enable autogeneration of Qts MOC/RCC/UIC
|
||||||
set_target_properties(${PROJECT_NAME}
|
set_target_properties(${PROJECT_NAME}
|
||||||
|
|
Loading…
Reference in a new issue