diff options
38 files changed, 542 insertions, 329 deletions
diff --git a/.ci/windows/build.bat b/.ci/windows/build.bat index 4d392cb7..7e952237 100644 --- a/.ci/windows/build.bat +++ b/.ci/windows/build.bat @@ -4,7 +4,7 @@ if defined CI_COMMIT_TAG ( set VERSION=%CI_COMMIT_TAG% ) else ( - set VERSION=v0.11.3 + set VERSION=v0.12.0 ) set INSTVERSION=%VERSION:~1% set WINVERSION=%VERSION:~1%.%CI_JOB_ID% diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 464d0f86..13fe25dd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -96,9 +96,14 @@ pages: - apk add curl jq script: - export LATEST_WINDOWS_NIGHTLY=$(curl "https://nheko.im/api/v4/projects/2/packages?package_name=windows-nightly&order_by=version&sort=desc" | jq -r '.[0].version') - - sed "s/0.11.3.4/${LATEST_WINDOWS_NIGHTLY}/g" -i resources/NhekoNightly.appinstaller + #- export LATEST_WINDOWS=$(curl "https://nheko.im/api/v4/projects/2/packages?package_name=windows&order_by=version&sort=desc" | jq -r '.[0].version') + # hardcoded to avoid fuzzy matching + - export LATEST_WINDOWS='0.12.0.35798' + - sed "s/0.12.0.0/${LATEST_WINDOWS_NIGHTLY}/g" -i resources/NhekoNightly.appinstaller + - sed "s/0.12.0.0/${LATEST_WINDOWS}/g" -i resources/Nheko.appinstaller - mkdir public - mv resources/NhekoNightly.appinstaller public + - mv resources/Nheko.appinstaller public needs: - job: upload-windows optional: true diff --git a/CHANGELOG.md b/CHANGELOG.md index aa0ed778..955dcb04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,202 @@ # Changelog +## [0.12.0] -- 2024-06-12 + +### Notes + +The packages for windows are split into an appinstaller file with autoupdates +and an msix, which can be installed directly and won't check for updates. The +appimage is currently disabled until someone ports it to Qt6. The flatpak appid +changed and you will need to migrate manually. + +For packagers most of our dependencies have been changed or updated. Most +significantly Nheko now depends on KDSingleApplication and Qt6. + +### Highlights + +- Qt6 6️⃣ + - This release migrates to version 6 of the Qt toolkit. + - This brings various changes to Nheko. Scrolling might feel slower on some + platforms. Theming will look different. You have been warned! + - We left out all the fixes we had to do for this from the changelog. + Otherwise it might have been twice as long... +- Intentional mentions 🔔 + - You can now decide if a message should mention someone or not. + - Replies now also include an explicit mention (MSC4142). +- Event expiration ⏲️ + - You can now make Nheko delete messages regularly. + - Configure either a time or a maximum number of messages. + - Can be configured per room or globally. +- Ignoring users (NepNep) 🔕 + - You can now ignore other users. + - This will hide their messages from the timeline. + - You can either user the `/ignore` command, the button in their profile or + the button in the Nheko settings. + +### Features + +- Support for video calls (including screenshare) on Windows. This support is + currently not available in prebuilt packages. (checkraisefold) +- `/glitch` commands to garble your text. (LorenDB) +- Deleting sticker packs. (FallenValkyrie) +- Settings for your current profile state. (online, offline, unavailable, auto) +- "Goto this event" button in the timeline when searching. +- Right click menu entry to go to event when searching. (Sateallia) +- Remember the last used filter (community, tag, etc) between restarts. (Sateallia) +- Render reactions with custom emoji. +- Add custom emoji to the emoji popup. +- Add edit button to sticker and emoji popups. +- Optionally sort the room list alphabetically. (Sateallia) +- Allow sending custom message types. (LorenDB) +- Rainfall effect. (LorenDB) +- Screenshare using XDG desktop portals (like on Wayland). (David Elsing) +- Show which rooms you share with another user. + +### Improvements + +- Support MSC3916 for authenticated media. +- Disable workarounds for inline images for Qt6.7 and up. +- Various improvements around window activation on Wayland. (q234rty) +- Update emoji shortcodes. (TheDrawingCoder-Gamer) +- Windows and Apple Silicon builds on our own hardware. (Thanks Thulinma for + sponsoring access the Apple Silicon box) +- MSIX builds and appinstaller for Windows with valid signatures and automatic updates. +- Add environment variable to dump the video call pipeline. +- Bump supported maximum Matrix version to 1.10. +- Various fixes around blurry graphics on HiDPI systems. (q234rty) +- Build instructions for Qt6 version on Debian Trixie. (enigma9o7) +- Allow reporting messages to your server admin. (LorenDB) +- Matrix URI handling on macOS. (LorenDB) +- Disable endless pagination for threads. +- Deinit gstreamer appropriately. (NepNep) +- Support the "fixed" mac method during verification. +- Show/hide password button on login page. (Bubu) +- Faster blurhash decode. +- Speedup room switching. +- Setting to disable swipe navigation. (duarm) +- Click handling for Windows notifications. +- Update gstreamer in flatpak. (Francesco Gazzetta) +- Activation token handling for notifications. +- Improve Haiku support. (Begasus) +- Switch to KDSingleApplication for single instance handling. +- Trust handling for received megolm sessions. +- Highlight spaces in bold in the quick switcher. +- Throttle sync processing when the window is unfocused. +- Allow hiding unsupported events via the hidden events dialog. +- Change appid to im.nheko.Nheko. (Miika Tuominen) +- .editorconfig and .gitattributes. (Aminda Suomalainen) +- Remove fetched messages only on startup. +- Focus message input after drag and dropping a file. (Sateallia) +- Add extra styling for effect messages. +- Reduce CPU usage from animated images not currently visible. +- Close and open buttons for the room directory. (LorenDB) +- Touch scrolling for text. (LorenDB) +- Unify our usage of `@user:example.com`. (LorenDB) +- Explicit default font options. (LorenDB) +- Show powerlevel of mods and admins in the timeline. +- Mark room as read from the room list. +- Focus input bar after selecting a file. (Sateallia) +- Rework history settings. +- Show server ACL changes. +- Show inviter on invites. +- Sections for the sticker picker. +- Automatically strip file extensions of images in sticker picker. +- Focus the input bar on key presses. +- Search rooms in quick switcher by 'activity'. +- Make tombstoned rooms italic in the quick switcher. +- Allow uploading multiple files at once via the file picker. (Sateallia) +- Combine notifications above a certain count. (LcsTen) +- Allow querying the status msg over dbus (if enabled). +- Allow `#` character in url fragments (to work around clients not escaping + matrix.to links). +- Improve state event redaction. +- Hide inaccessible rooms in communities. (LcsTen) +- Update community metadata automatically. +- Include ACLs in via calculation. +- Focus message input on "scroll to bottom". (tastytea) +- Warn on invalid /command. (LorenDB) +- Cleanup table rendering. +- Blurhash images on privacy screen. (LorenDB) +- Improve OpenBSD support. (Klemens Nanni) +- Show full status mesage in profile and on hover. (Bubu) +- Animate transition from blurhash. (LorenDB) + +### Translations + +- Portugese (Tmpod) +- Polish (Przemysław Romanik, Vaxry) +- Dutch (Jaron Viëtor, Ruben De Smet) +- Turkish (Tennouji Misaki, Emilia) +- Chinese (Traditional) (AdrianL40) +- Chinese (Simplified) (Poesty Li, Eric, Integral, Estela ad Astra) +- Russian (pizdjuk) +- Indonesian (Linerly) +- Esperanto (Tirifto) +- Estonian (Priit Jõerüüt) +- French (val, luilegeant, CB, Guillaume Girol, Pixead, Mohamad Damaj, Tonus, + Mayeul Cantan) +- German +- Italian (DynamoFox, Elia Tomasi) +- Spanish (CM0use) +- Finnish (Lurkki14, Aminda Suomalainen) +- Arabic (nk) +- Persian (Farooq Karimi Zadeh) +- Ukrainian (NullPointerException) + +### Bugfixes + +- Prevent shortcuts from inserting unprintable characters. +- Display emojis in avatars properly. +- Prevent opening empty Nheko profiles by accident. +- DMs created in Nheko were not marked as DMs properly. +- Prevent opening user profiles for empty mxids. +- Fix crash during video calls on Linux. (checkraisefold) +- Fix validation errors in Linux appdata.xml. (Echo J) +- Properly copy images to the clipboard on Windows. (NepNep) +- Prevent emoji verification and room settings from being clipped by default. + (Brayd) +- Properly remove attributes on del tags. +- Properly scope presence setting to profiles. +- Animated images first rendered outside the visible area shouldn't be + invisible anymore. +- Correctly handle of multiple devices in parallel. +- Avoid lag when media messages are shown from enumerating audio devices. +- Hidden topic for spaces. +- Url encoding for widget urls. +- Profile argument parsing for `-p=`. (LorenDB) +- Unset hidden space setting when leaving a space. +- Round images are square. +- Don't freeze after stopping a call on Wayland. (GStreamer frees the EGL + context...) +- Database name length limitation on some filesystems with long userids. +- Pagination in search. +- Save profile also when no setting is modified. +- Fix decrypt notification setting not being stored properly. +- Calculate the name of rooms with 3 members correctly. +- Crash on database migration. (mips64-el) +- `<hr>` tag escaping. +- Confetti being left over after a celebration. +- Powerlevel indicator size in timeline. +- Duplicate qml ids. (ShootingStarDragons) +- Presence updates in the timeline. +- Pagination in rooms only containing redactions. +- Set a pack avatar. +- Make settings comboboxes dependent on content width. +- Don't lose message draft history after an edit. +- Workaround some WM specific behaviour regarding the focus during search. + (Sateallia) +- Handle network errors better when marking a mssage as read. +- Name and attributions of image packs should be plain text. +- Displaying encrypted thumbnails. +- 0 size dialogs. (0xDEADCADE) +- Loading image packs in unjoined communities. +- Show encryption dialog once, not twice. (LorenDB) +- Elide nicks and userids in various dialogs. (LorenDB) +- macOS builds (1000x). +- Disable qml disk cache by default. +- QT_SCALE_FACTOR on OpenBSD. (Klemens Nanni) +- Deduplicate reactions. + ## [0.11.3] -- 2023-02-23 ### Bugfix diff --git a/CMakeLists.txt b/CMakeLists.txt index 5054be05..04738bda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,8 +113,8 @@ include(QtCommon) include(GNUInstallDirs) set(CPACK_PACKAGE_VERSION_MAJOR "0") -set(CPACK_PACKAGE_VERSION_MINOR "11") -set(CPACK_PACKAGE_VERSION_PATCH "3") +set(CPACK_PACKAGE_VERSION_MINOR "12") +set(CPACK_PACKAGE_VERSION_PATCH "0") set(PROJECT_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR}) set(PROJECT_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR}) set(PROJECT_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH}) @@ -125,8 +125,8 @@ fix_project_version() # Set additional project information set(COMPANY "Nheko") -set(COPYRIGHT "Copyright (c) 2023 Nheko Contributors") -set(IDENTIFIER "io.github.nheko-reborn.nheko") +set(COPYRIGHT "Copyright (c) 2024 Nheko Contributors") +set(IDENTIFIER "im.nheko.Nheko") add_project_meta(META_FILES_TO_INCLUDE) @@ -606,13 +606,13 @@ if(USE_BUNDLED_MTXCLIENT) FetchContent_Declare( MatrixClient GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git - GIT_TAG 8b3c9a34770df147fbd78134dc71a9b27471d153 + GIT_TAG v0.10.0 ) set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "") set(BUILD_LIB_TESTS OFF CACHE INTERNAL "") FetchContent_MakeAvailable(MatrixClient) else() - find_package(MatrixClient 0.9.0 REQUIRED) + find_package(MatrixClient 0.10.0 REQUIRED) endif() if(VOIP) diff --git a/README.md b/README.md index 37ebcf42..41b32886 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ feels more like a mainstream chat app ([Element], Telegram etc) and less like an ### Stable [![Stable Version](https://img.shields.io/badge/download-stable-green.svg)](https://github.com/Nheko-Reborn/nheko/releases/latest) -<a href='https://flathub.org/apps/details/io.github.NhekoReborn.Nheko'><img height='32' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a> +<a href='https://flathub.org/apps/details/im.nheko.Nheko'><img height='32' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a> [![Packaging status](https://repology.org/badge/tiny-repos/nheko.svg)](https://repology.org/project/nheko/versions) For other options and details see the [Installation](#installation) section. @@ -39,17 +39,19 @@ Most of the features you would expect from a chat application are missing right but we are getting close to a more feature complete client. Specifically there is support for: - E2E encryption. -- VoIP calls (voice & video). +- VoIP calls (voice & video, support varies by platform). - User registration. - Creating, joining & leaving rooms. - Sending & receiving invites. - Sending & receiving files and emoji (inline widgets for images, audio and file messages). +- Custom stickers and emoji. - Replies with text, images and other media (and actually render them as inline widgets). - Typing notifications. - Username auto-completion. - Message & mention notifications. - Redacting messages. - Read receipts. +- Presence and status messages (if enabled on the server side). - Basic communities support. - Room switcher (ctrl-K). - Light, Dark & System themes. @@ -60,8 +62,9 @@ Specifically there is support for: ### Releases -Releases for Linux (AppImage), macOS (disk image) & Windows (x64 installer) +Releases for Linux (Flatpak), macOS (disk image) & Windows (x64 msix or appinstaller) can be found in the [GitHub releases](https://github.com/Nheko-Reborn/nheko/releases). +The appinstaller on Windows will regularly check our servers for updates. The msix won't. ### Repositories @@ -110,10 +113,38 @@ sudo urpmi nheko #### Nix(os) ```bash +# Imperatively: (not recommended) nix-env -iA nixpkgs.nheko -# or + +# In an ephemeral shell: (recommended if you just want to try it out without committing to a full installation) nix-shell -p nheko --run nheko +# Note: The above command will both install and run Nheko. +# To stop it from running immediately, just remove the `--run nheko` from the end. +``` +Alternatively, add it to your config in one of the following ways: (recommended for long-term installation) + +**System-wide:** +```nix +environment.systemPackages = with pkgs; [ + # ... + nheko + # ... +]; +``` +**User-specific:** +```nix +users.users.<user>.packages = with pkgs; [ + # ... + nheko + # ... +]; ``` +**via `home-manager`:** +```nix +programs.nheko.enable = true; +``` + + #### Alpine Linux (and postmarketOS) @@ -143,7 +174,7 @@ sudo zypper install qt-jdenticon #### Flatpak ``` -flatpak install flathub io.github.NhekoReborn.Nheko +flatpak install flathub im.nheko.Nheko ``` #### Guix @@ -157,8 +188,8 @@ guix install nheko Install nheko via the `Discover` app in Desktop Mode (this installs the flatpak). To also make it work in Game Mode you'll have create a wrapper script that starts kwalletd and then nheko. You can create `/home/deck/nheko.sh` with the following content and then add this script as a "Non-Steam Game" to Steam. ```bash #!/bin/sh -kwalletd5& -flatpak run --env=XDG_CURRENT_DESKTOP=KDE --env=KDE_SESSION_VERSION=5 --branch=stable --arch=x86_64 --command=io.github.NhekoReborn.Nheko --file-forwarding io.github.NhekoReborn.Nheko @@u @@ +kwalletd6& +flatpak run --env=XDG_CURRENT_DESKTOP=KDE --env=KDE_SESSION_VERSION=5 --branch=stable --arch=x86_64 --command=im.nheko.Nheko --file-forwarding im.nheko.Nheko @@u @@ ``` #### macOS (10.14 and above) @@ -237,23 +268,23 @@ sharing easier. **A:** Nheko uses Qt's image plugins to render images. You might need to install additional packages to display some image types like webp. Usually those -packages are called `qt5-image-formats-plugins`, `qt5-imageformats` or similar. +packages are called `qt6-image-formats-plugins`, `qt6-imageformats` or similar. KDE has similar plugins, that can extend the supported image types even more. --- ### Build Requirements -- Qt5 (5.15 or greater). Required for overlapping hover handlers in Qml. +- Qt6 (6.5 or greater). Required for overlapping hover handlers in Qml. - CMake 3.15 or greater. (Lower version may work, but may break boost linking) - [mtxclient](https://github.com/Nheko-Reborn/mtxclient) - [coeurl](https://nheko.im/nheko-reborn/coeurl) -- [LMDB](https://symas.com/lightning-memory-mapped-database/) +- [LMDB](https://www.symas.com/lmdb) - [lmdb++](https://github.com/hoytech/lmdbxx) (0.9.14 too old) - [cmark](https://github.com/commonmark/cmark) 0.29 or greater. - [libolm](https://gitlab.matrix.org/matrix-org/olm) - [spdlog](https://github.com/gabime/spdlog) (1.8.1 too old) -- [GStreamer](https://gitlab.freedesktop.org/gstreamer) 1.18.0 or greater (optional, needed for VoIP support. Pass `-DVOIP=OFF` to disable.). +- [GStreamer](https://gitlab.freedesktop.org/gstreamer) 1.20.0 or greater (optional, needed for VoIP support. Pass `-DVOIP=OFF` to disable.). - Installing the gstreamer core library plus gst-plugins-base, gst-plugins-good & gst-plugins-bad is often sufficient. The qmlgl plugin though is often packaged separately. The actual plugin requirements are as follows: @@ -265,7 +296,7 @@ KDE has similar plugins, that can extend the supported image types even more. - [KDSingleApplication](https://github.com/KDAB/KDSingleApplication) (1.0 or greater with Qt6 support) - A compiler that supports C++ 20: - Clang 16 (Only clazy 16 is tested in CI) - - GCC 11 (tested on Gitlab CI) + - GCC 11.3 (tested on Gitlab CI) - MSVC 19.13 (tested on AppVeyor) Nheko can use bundled version for most of those libraries automatically, if the versions in your distro are too old. @@ -303,17 +334,17 @@ make docker-app-image #### Arch Linux ```bash -sudo pacman -S qt5-base \ - qt5-tools \ - qt5-multimedia \ - qt5-svg \ +sudo pacman -S qt6-base \ + qt6-tools \ + qt6-multimedia \ + qt6-svg \ cmake \ gcc \ fontconfig \ lmdb \ cmark \ boost \ - qtkeychain-qt5 + qtkeychain-qt6 ``` #### Debian 13 [Testing/Sid] (Nheko QT6 Version) @@ -335,8 +366,8 @@ cmake --build build *Build requirements + qml modules needed at runtime (you may not need all of them, but the following seem to work according to reports):* ```bash sudo apt install --no-install-recommends g++ cmake make zlib1g-dev libssl-dev libolm-dev liblmdb-dev libcmark-dev nlohmann-json3-dev libspdlog-dev libevent-dev libcurl4-openssl-dev libre2-dev libxcb-ewmh-dev asciidoc-base \ -qt{base,declarative,tools,multimedia,quickcontrols2-}5-dev libqt5svg5-dev qt5keychain-dev qml-module-qt{gstreamer,multimedia,quick-extras,-labs-settings,-labs-platform,graphicaleffects,quick-controls2,quick-particles2} \ -libgstreamer1.0-dev libgstreamer-plugins-{base,bad}1.0-dev qtgstreamer-plugins-qt5 libnice-dev ninja-build +qt{base,declarative,tools,multimedia,quickcontrols2-}5-dev libqt6svg5-dev qt6keychain-dev qml-module-qt{gstreamer,multimedia,quick-extras,-labs-settings,-labs-platform,graphicaleffects,quick-controls2,quick-particles2} \ +libgstreamer1.0-dev libgstreamer-plugins-{base,bad}1.0-dev qtgstreamer-plugins-qt6 libnice-dev ninja-build ``` lmdb++-dev is too old so bundled lmdbxx must be used. libspdlog-dev in debian bullseye is too old (without backporting) so requires using hunter to use bundled spdlog. @@ -365,7 +396,7 @@ guix environment nheko ```bash brew update -brew install qt5 lmdb cmake llvm spdlog boost cmark libolm qtkeychain +brew install qt6 lmdb cmake llvm spdlog boost cmark libolm qtkeychain ``` #### Windows @@ -398,18 +429,18 @@ Adapt the USE_BUNDLED_* as needed. If the build fails with the following error ``` -Could not find a package configuration file provided by "Qt5Widgets" with +Could not find a package configuration file provided by "Qt6Widgets" with any of the following names: -Qt5WidgetsConfig.cmake -qt5widgets-config.cmake +Qt6WidgetsConfig.cmake +qt6widgets-config.cmake ``` -You might need to pass `-DCMAKE_PREFIX_PATH` to cmake to point it at your qt5 install. +You might need to pass `-DCMAKE_PREFIX_PATH` to cmake to point it at your qt6 install. e.g on macOS ``` -cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=$(brew --prefix qt5) +cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=$(brew --prefix qt6) cmake --build build ``` @@ -420,11 +451,11 @@ The `nheko` binary will be located in the `build` directory. After installing all dependencies, you need to edit the `CMakeSettings.json` to be able to load and compile nheko within Visual Studio. -You need to fill out the paths for the `Qt5_DIR`. -The Qt5 dir should point to the `lib\cmake\Qt5` dir. +You need to fill out the paths for the `Qt6_DIR`. +The Qt6 dir should point to the `lib\cmake\Qt6` dir. Examples for the paths are: - - `C:\\Qt\\5.15.1\\msvc2017_64\\lib\\cmake\\Qt5` + - `C:\\Qt\\6.5.2\\msvc2017_64\\lib\\cmake\\Qt6` You should also enable hunter by setting `HUNTER_ENABLED` to `ON` and `BUILD_SHARED_LIBS` to `OFF`. diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 084e7179..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,134 +0,0 @@ ---- - -version: 0.11.3-{build} - -configuration: Release -image: Visual Studio 2022 -platform: x64 - -environment: - APPVEYOR_SAVE_CACHE_ON_ERROR: true - MATRIX_ACCESS_TOKEN: - secure: Qoy+QQ8zWXYCQrck9GtXJsoPTv9r/rhgCDUlKJ6ue+gkteYG40E9MxgwP1svn6bse20H4z6Svrxn8kFbcJB7Wg2Cnv1s326/vsJJzhWir2eHFFGK+f4SB992/U0HoQmk3Cq5hPk7dLcA7KqHIa1g1PTSFPfl1VODJ2UqqAyn8nzbC5ym+wwU1buJqoWPlTyHBW7eE8wNe77+qI18XpF7NN8yuOOyg3Tzup9YyXLrI36XiJu/5JD3j3s3V1QiUTpuLyQzqwuBUOf1MHTbzuPwHm3ZwzSM98WD6aL6riaK9qa7mDbSx1aY0ukIYSY9IdAfHNwZY/DEAn+QAVD+ZTvPq04ASv+kmSFpOBKr07kpqfM= - - - -cache: - - c:\hunter\ -> appveyor.yml, CMakeLists.txt, cmake/Hunter/config.cmake - - build\_deps -> appveyor.yml, CMakeLists.txt - -build: - verbosity: minimal - -install: - - set QT_DIR=C:\Qt\6.5\msvc2019_64 - - set PATH=C:\Strawberry\perl\bin;C:\Python39-x64;%QT_DIR%\bin;%PATH% - -build_script: - # VERSION format: branch-master/branch-1.2 - # INSTVERSION format: x.y.z - # WINVERSION format: 9999.0.0.123/1.2.0.234 - - if "%APPVEYOR_REPO_TAG%"=="false" set INSTVERSION=0.11.3 - - if "%APPVEYOR_REPO_TAG%"=="false" set VERSION=0.11.3 - - if "%APPVEYOR_REPO_TAG%"=="false" set WINVERSION=%INSTVERSION%.%APPVEYOR_BUILD_NUMBER% - # VERSION format: v1.2.3/v1.3.4 - # INSTVERSION format: 1.2.3/1.3.4 - # WINVERSION format: 1.2.3.123/1.3.4.234 - - if "%APPVEYOR_REPO_TAG%"=="true" set VERSION=%APPVEYOR_REPO_TAG_NAME% - - if "%APPVEYOR_REPO_TAG%"=="true" set INSTVERSION=%VERSION:~1% - - if "%APPVEYOR_REPO_TAG%"=="true" set WINVERSION=%VERSION:~1%.%APPVEYOR_BUILD_NUMBER% - - set DATE=%date:~10,4%-%date:~4,2%-%date:~7,2% - - echo %VERSION% - - echo %INSTVERSION% - - echo %DATE% - - # Build nheko - - cmake -G "Visual Studio 17 2022" -A x64 -H. -Bbuild - -DHUNTER_ROOT="C:\hunter" - -DHUNTER_ENABLED=ON -DBUILD_SHARED_LIBS=OFF -DUSE_BUNDLED_OPENSSL=ON -DUSE_BUNDLED_KDSINGLEAPPLICATION=ON - -DCMAKE_BUILD_TYPE=Release -DHUNTER_CONFIGURATION_TYPES=Release - - - cmake --build build --config Release - - - call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 - - git clone https://github.com/Nheko-Reborn/qt-jdenticon.git - - cd qt-jdenticon - - qmake - - nmake - - cd .. - -after_build: - # Variables - - set BUILD=%APPVEYOR_BUILD_FOLDER% - - echo %BUILD% - - mkdir NhekoRelease - - copy build\Release\nheko.exe NhekoRelease\nheko.exe - - copy qt-jdenticon\release\qtjdenticon0.dll NhekoRelease\qtjdenticon.dll - - copy build\_deps\cmark-build\src\Release\cmark.dll NhekoRelease\cmark.dll - - windeployqt --qmldir resources\qml\ NhekoRelease\nheko.exe - - - 7z a nheko_win_64.zip .\NhekoRelease\* - - ls -lh build\Release\ - - ls -lh NhekoRelease\ - - mkdir NhekoData - - xcopy .\NhekoRelease\*.* NhekoData\*.* /s /e /c /y - # - # Create the Qt Installer Framework version - # - - mkdir installer - - mkdir installer\config - - mkdir installer\packages - - mkdir installer\packages\io.github.nhekoreborn.nheko - - mkdir installer\packages\io.github.nhekoreborn.nheko\data - - mkdir installer\packages\io.github.nhekoreborn.nheko\meta - # Copy installer data - - copy %BUILD%\resources\nheko.ico installer\config - - copy %BUILD%\resources\nheko.png installer\config - - copy %BUILD%\COPYING installer\packages\io.github.nhekoreborn.nheko\meta\license.txt - - copy %BUILD%\deploy\installer\config.xml installer\config - - copy %BUILD%\deploy\installer\controlscript.qs installer\config - - copy %BUILD%\deploy\installer\uninstall.qs installer\packages\io.github.nhekoreborn.nheko\data - - copy %BUILD%\deploy\installer\gui\package.xml installer\packages\io.github.nhekoreborn.nheko\meta - - copy %BUILD%\deploy\installer\gui\installscript.qs installer\packages\io.github.nhekoreborn.nheko\meta - # Amend version and date - - sed -i "s/__VERSION__/%VERSION%/" installer\config\config.xml - - sed -i "s/__VERSION__/%VERSION%/" installer\packages\io.github.nhekoreborn.nheko\meta\package.xml - - sed -i "s/__DATE__/%DATE%/" installer\packages\io.github.nhekoreborn.nheko\meta\package.xml - # Copy nheko data - - xcopy NhekoData\*.* installer\packages\io.github.nhekoreborn.nheko\data\*.* /s /e /c /y - - copy NhekoRelease\nheko.exe installer\packages\io.github.nhekoreborn.nheko\data - - mkdir tools - - curl -L -O https://download.qt.io/official_releases/qt-installer-framework/4.3.0/QtInstallerFramework-windows-x86-4.3.0.exe - - 7z x QtInstallerFramework-windows-x86-4.3.0.exe -otools -aoa - - set PATH=%BUILD%\tools\bin;%PATH% - - binarycreator.exe -f -c installer\config\config.xml -p installer\packages nheko-installer.exe - - # build an msix - - mkdir msix - - xcopy .\NhekoRelease\*.* msix\*.* /s /e /c /y - - copy %BUILD%\resources\nheko.png msix - - copy %BUILD%\resources\AppxManifest.xml msix - - del msix\vc_redist* - - 'sed -i "s/ Version=[^ ]*/ Version=\"%WINVERSION%\"/" msix\AppxManifest.xml' - - '"C:\Program Files (x86)\Windows Kits\10\App Certification Kit\makeappx.exe" pack -d msix -p nheko.msix' - - - copy nheko-installer.exe nheko-%APPVEYOR_REPO_TAG_NAME%-installer.exe - - copy nheko-installer.exe nheko-%APPVEYOR_PULL_REQUEST_HEAD_COMMIT%-installer.exe - - ps: .\.ci\upload-nightly.ps1 - -deploy: - - description: "Development builds" - provider: GitHub - auth_token: - secure: "ShStWeqp+TkYqJPQr7uFZb+B8ZTgC7Iwth+IkhjfRDCTLhy8gtWvlPzlQilder3E" - artifact: nheko-${APPVEYOR_REPO_TAG_NAME}-installer.exe - force_update: true - prerelease: true - on: - appveyor_repo_tag: true - -artifacts: - - path: nheko_win_64.zip - - path: nheko.msix - - path: nheko-$(APPVEYOR_REPO_TAG_NAME)-installer.exe - - path: nheko-$(APPVEYOR_PULL_REQUEST_HEAD_COMMIT)-installer.exe diff --git a/im.nheko.Nheko.yaml b/im.nheko.Nheko.yaml index 8150b292..8cdc5edb 100644 --- a/im.nheko.Nheko.yaml +++ b/im.nheko.Nheko.yaml @@ -1,21 +1,23 @@ id: im.nheko.Nheko command: im.nheko.Nheko runtime: org.kde.Platform -runtime-version: '6.6' +runtime-version: '6.7' sdk: org.kde.Sdk finish-args: - - --device=dri - # needed for webcams, see #517 + # needed for webcams, see https://github.com/Nheko-Reborn/nheko/issues/517 - --device=all - --share=ipc - --share=network - --socket=pulseaudio - - --socket=wayland - --socket=x11 + - --socket=wayland - --talk-name=org.freedesktop.Notifications - --talk-name=org.freedesktop.secrets + - --talk-name=org.kde.kwalletd5 + - --talk-name=org.kde.kwalletd6 - --talk-name=org.freedesktop.StatusNotifierItem - - --talk-name=org.kde.* + # needed for tray icon + - --talk-name=org.kde.StatusNotifierWatcher cleanup: - /include - /lib/pkgconfig @@ -83,18 +85,18 @@ modules: - sha256: 5197b3147cfcfaa67dd564db7b878e4a4b3d9f3443801722b3915cdeced656cb type: archive url: https://github.com/gabime/spdlog/archive/v1.8.1.tar.gz - - config-opts: + - name: olm + config-opts: - -DCMAKE_BUILD_TYPE=Release buildsystem: cmake-ninja - name: olm sources: - commit: 92769cec711c604a1f682b95d6944578d2a1bb3d disable-shallow-clone: true tag: 3.2.12 type: git url: https://gitlab.matrix.org/matrix-org/olm.git - - buildsystem: meson - name: libsecret + - name: libsecret + buildsystem: meson config-opts: - -Dmanpage=false - -Dvapi=false @@ -137,51 +139,52 @@ modules: # tag: v5.93.0 # type: git # url: https://invent.kde.org/frameworks/kimageformats.git - - config-opts: + - name: QtKeychain + config-opts: - -DCMAKE_BUILD_TYPE=Release - -DBUILD_TEST_APPLICATION=OFF - -DQTKEYCHAIN_STATIC=ON - -DBUILD_WITH_QT6=ON buildsystem: cmake-ninja - name: QtKeychain sources: - commit: 69f993c47efed7e557d79a30a367014d9a27d809 tag: 0.14.1 type: git url: https://github.com/frankosterfeld/qtkeychain.git - - config-opts: + - name: nlohmann + config-opts: - -DJSON_BuildTests=OFF - buildsystem: cmake - name: nlohmann + buildsystem: cmake-ninja sources: - sha256: d69f9deb6a75e2580465c6c4c5111b89c4dc2fa94e3a85fcd2ffcd9a143d9273 type: archive url: https://github.com/nlohmann/json/archive/v3.11.2.tar.gz - - config-opts: + - name: kdsingleapplication + config-opts: - -DKDSingleApplication_EXAMPLES=OFF - -DKDSingleApplication_QT6=ON - buildsystem: cmake - name: kdsingleapplication + buildsystem: cmake-ninja sources: - sha256: c92355dc10f3ebd39363458458fb5bdd9662e080cf77d91f0437763c4d936520 type: archive url: https://github.com/KDAB/KDSingleApplication/releases/download/v1.0.0/kdsingleapplication-1.0.0.tar.gz - - buildsystem: simple + - name: re2 + buildsystem: simple build-commands: - make static - make prefix=/app static-install - name: re2 sources: - sha256: f89c61410a072e5cbcf8c27e3a778da7d6fd2f2b5b1445cd4f4508bee946ab0f type: archive url: https://github.com/google/re2/archive/refs/tags/2022-06-01.tar.gz - - buildsystem: meson - name: gstreamer + - name: gstreamer + buildsystem: meson sources: - - commit: 4d13eddc8b6d3f42ba44682ba42048acf170547f - tag: 1.22.7 + - commit: d2c02bb704b5804ca057fc7e6c7b16b4466fd7d5 + tag: 1.22.12 type: git url: https://gitlab.freedesktop.org/gstreamer/gstreamer.git + disable-submodules: true config-opts: - --auto-features=disabled - -Dgood=enabled @@ -195,46 +198,46 @@ modules: - -Dgst-plugins-base:gl_winsys=x11,wayland - -Dgst-plugins-base:x11=enabled - -Dgst-plugins-base:xshm=enabled - - buildsystem: cmake - name: qt-jdenticon + - name: qt-jdenticon + buildsystem: cmake-ninja no-make-install: true build-commands: - mkdir -p /app/bin/ - cp libqtjdenticon.so /app/bin/ sources: - - commit: 1e7013d64fd081d76e4ce69f2693129c817fd8f1 - #tag: v0.3.0 + - commit: 39cde33d4b23b57aa5b94e94071d6ff18d2bd92a + tag: v0.3.1 type: git url: https://github.com/Nheko-Reborn/qt-jdenticon.git - - buildsystem: meson + - name: coeurl + buildsystem: meson config-opts: - -Ddefault_library=static - name: coeurl sources: - commit: 3007387745cf84138d0855e0f04ff94261fc7175 #tag: v0.3.0 type: git url: https://nheko.im/nheko-reborn/coeurl.git - - config-opts: + - name: mtxclient + config-opts: - -DBUILD_LIB_TESTS=OFF - -DBUILD_LIB_EXAMPLES=OFF - -DCMAKE_BUILD_TYPE=Release - -DBUILD_SHARED_LIBS=OFF buildsystem: cmake-ninja - name: mtxclient sources: - - commit: 8b3c9a34770df147fbd78134dc71a9b27471d153 - #tag: v0.9.2 + - commit: 457bc52773b40142848f0b2ab025516bf6ed634d + tag: v0.10.0 type: git url: https://github.com/Nheko-Reborn/mtxclient.git - - config-opts: + - name: nheko + config-opts: - -DCMAKE_BUILD_TYPE=Release - -DLMDBXX_INCLUDE_DIR=.deps/lmdbxx - -DCOMPILE_QML=ON - -DMAN=OFF - -DFLATPAK=ON buildsystem: cmake-ninja - name: nheko sources: - path: . type: dir diff --git a/resources/AppxManifest.xml b/resources/AppxManifest.xml index 9f933604..8253f839 100644 --- a/resources/AppxManifest.xml +++ b/resources/AppxManifest.xml @@ -4,7 +4,7 @@ xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"> - <Identity Name="im.nheko.Nheko" Version="0.11.3.4" Publisher="CN=Nicolas Werner, O=Nicolas Werner, L=Munich, S=Bavaria, C=DE" ProcessorArchitecture="x64"/> + <Identity Name="im.nheko.Nheko" Version="0.12.0.0" Publisher="CN=Nicolas Werner, O=Nicolas Werner, L=Munich, S=Bavaria, C=DE" ProcessorArchitecture="x64"/> <Properties> <DisplayName>Nheko</DisplayName> <PublisherDisplayName>Nheko-Reborn</PublisherDisplayName> diff --git a/resources/Nheko.appinstaller b/resources/Nheko.appinstaller new file mode 100644 index 00000000..004a0d73 --- /dev/null +++ b/resources/Nheko.appinstaller @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<AppInstaller Uri="https://nheko-reborn.pages.nheko.im/nheko/Nheko.appinstaller" Version="0.0.0.1" xmlns="http://schemas.microsoft.com/appx/appinstaller/2018"> + <MainPackage Name="im.nheko.Nheko" Version="0.12.0.0" Publisher="CN=Nicolas Werner, O=Nicolas Werner, L=Munich, S=Bavaria, C=DE" Uri="https://nheko.im/api/v4/projects/2/packages/generic/windows/0.12.0.0/nheko.msix" ProcessorArchitecture="x64" /> + <UpdateSettings> + <!-- We can't set this to check only once a month, so just check once a week. If the user doesn't want that ping, they should install the msix directly. --> + <OnLaunch HoursBetweenUpdateChecks="168" ShowPrompt="true" /> + <ForceUpdateFromAnyVersion>true</ForceUpdateFromAnyVersion> + </UpdateSettings> +</AppInstaller> + diff --git a/resources/NhekoNightly.appinstaller b/resources/NhekoNightly.appinstaller index bd94f5d9..88f1fd8a 100644 --- a/resources/NhekoNightly.appinstaller +++ b/resources/NhekoNightly.appinstaller @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <AppInstaller Uri="https://nheko-reborn.pages.nheko.im/nheko/NhekoNightly.appinstaller" Version="0.0.0.1" xmlns="http://schemas.microsoft.com/appx/appinstaller/2018"> - <MainPackage Name="im.nheko.Nheko" Version="0.11.3.4" Publisher="CN=Nicolas Werner, O=Nicolas Werner, L=Munich, S=Bavaria, C=DE" Uri="https://nheko.im/api/v4/projects/2/packages/generic/windows-nightly/0.11.3.4/nheko.msix" ProcessorArchitecture="x64" /> + <MainPackage Name="im.nheko.Nheko" Version="0.12.0.0" Publisher="CN=Nicolas Werner, O=Nicolas Werner, L=Munich, S=Bavaria, C=DE" Uri="https://nheko.im/api/v4/projects/2/packages/generic/windows-nightly/0.12.0.0/nheko.msix" ProcessorArchitecture="x64" /> <UpdateSettings> <!-- We can't set this to check only once a month, so just check once a week. If the user doesn't want that ping, they should install the msix directly. --> <OnLaunch HoursBetweenUpdateChecks="168" ShowPrompt="true" /> diff --git a/resources/langs/nheko_de.ts b/resources/langs/nheko_de.ts index eb043ca2..a1ba0953 100644 --- a/resources/langs/nheko_de.ts +++ b/resources/langs/nheko_de.ts @@ -2117,7 +2117,7 @@ Beispiel: https://deinserver.example.com:8787</translation> <location line="+12"/> <source>%1 replied with a spoiler.</source> <comment>Format a reply in a notification. %1 is the sender.</comment> - <translation type="unfinished"></translation> + <translation>%1 hat mit einem Spoiler geantwortet.</translation> </message> <message> <location line="+10"/> @@ -3367,7 +3367,9 @@ Beispiel: https://deinserver.example.com:8787</translation> <location line="+1"/> <source>Encryption is currently experimental and things might break unexpectedly. <br> Please take note that it can't be disabled afterwards.</source> - <translation type="unfinished"></translation> + <translatorcomment>Verschlüsselung ist aktuell noch experimentell und kann Fehler beinhalten. <br> +Bitte sei dir bewusst, dass die Verschlüsselung nicht nachträglich deaktiviert werden kann.</translatorcomment> + <translation></translation> </message> <message> <location line="+19"/> @@ -5600,7 +5602,7 @@ Diese Einstellung benötigt einen Neustart von Nheko.</translation> <message> <location filename="../../src/notifications/ManagerMac.cpp" line="-12"/> <source>Message contains spoiler.</source> - <translation type="unfinished"></translation> + <translation>Nachricht beinhaltet Spoiler.</translation> </message> </context> <context> @@ -5669,13 +5671,13 @@ Diese Einstellung benötigt einen Neustart von Nheko.</translation> <location line="+6"/> <location line="+26"/> <source>You sent a spoiler.</source> - <translation type="unfinished"></translation> + <translation>Du hast einen Spoiler gesendet.</translation> </message> <message> <location line="-23"/> <location line="+26"/> <source>%1 sent a spoiler.</source> - <translation type="unfinished"></translation> + <translation>%1 hat einen Spoiler gesendet.</translation> </message> <message> <location line="-20"/> @@ -5702,7 +5704,7 @@ Diese Einstellung benötigt einen Neustart von Nheko.</translation> <message> <location line="+23"/> <source>* %1 spoils something.</source> - <translation type="unfinished"></translation> + <translation>* %1 spoilert etwas.</translation> </message> <message> <location line="+8"/> diff --git a/resources/langs/nheko_en.ts b/resources/langs/nheko_en.ts index 5ea03de2..eb65db49 100644 --- a/resources/langs/nheko_en.ts +++ b/resources/langs/nheko_en.ts @@ -2119,7 +2119,7 @@ Example: https://yourserver.example.com:8787</translation> <location line="+12"/> <source>%1 replied with a spoiler.</source> <comment>Format a reply in a notification. %1 is the sender.</comment> - <translation type="unfinished"></translation> + <translation>%1 replied with a spoiler.</translation> </message> <message> <location line="+10"/> @@ -3369,7 +3369,8 @@ Example: https://yourserver.example.com:8787</translation> <location line="+1"/> <source>Encryption is currently experimental and things might break unexpectedly. <br> Please take note that it can't be disabled afterwards.</source> - <translation type="unfinished"></translation> + <translation>Encryption is currently experimental and things might break unexpectedly. <br> + Please take note that it can't be disabled afterwards.</translation> </message> <message> <location line="+19"/> @@ -5602,7 +5603,7 @@ This setting will take effect upon restart.</translation> <message> <location filename="../../src/notifications/ManagerMac.cpp" line="-12"/> <source>Message contains spoiler.</source> - <translation type="unfinished"></translation> + <translation>Message contains spoiler.</translation> </message> </context> <context> @@ -5671,13 +5672,13 @@ This setting will take effect upon restart.</translation> <location line="+6"/> <location line="+26"/> <source>You sent a spoiler.</source> - <translation type="unfinished"></translation> + <translation>You sent a spoiler.</translation> </message> <message> <location line="-23"/> <location line="+26"/> <source>%1 sent a spoiler.</source> - <translation type="unfinished"></translation> + <translation>%1 sent a spoiler.</translation> </message> <message> <location line="-20"/> @@ -5704,7 +5705,7 @@ This setting will take effect upon restart.</translation> <message> <location line="+23"/> <source>* %1 spoils something.</source> - <translation type="unfinished"></translation> + <translation>* %1 spoils something.</translation> </message> <message> <location line="+8"/> diff --git a/resources/nheko.appdata.xml.in b/resources/nheko.appdata.xml.in index 69a632a1..77d1c6ad 100644 --- a/resources/nheko.appdata.xml.in +++ b/resources/nheko.appdata.xml.in @@ -59,6 +59,13 @@ <url type="homepage">https://github.com/Nheko-Reborn/nheko</url> <update_contact>https://github.com/Nheko-Reborn</update_contact> <releases> + <release date="2024-06-12" version="0.12.0"> + <description> + <p>This release features a complete port to Qt6, intentional mentions, expiring messages, ignoring users, better sticker and emoji handling and much, much more!</p> + </description> + + <url>https://github.com/Nheko-Reborn/nheko/releases/tag/v0.12.0</url> + </release> <release date="2023-02-23" version="0.11.3"/> <release date="2023-02-20" version="0.11.2"/> <release date="2023-01-15" version="0.11.1"/> diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index 5ad414f7..f253b7a8 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -84,6 +84,16 @@ Item { messageContextMenu: messageContextMenuC replyContextMenu: replyContextMenuC scrolledToThis: eventId === room.scrollTarget && (y + height > chat.y + chat.contentY && y < chat.y + chat.height + chat.contentY) + data: [ + Connections { + function onMovementEnded() { + if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height) { + room.currentIndex = index; + } + } + target: chat + } + ] } } Component { @@ -94,6 +104,16 @@ Item { messageContextMenu: messageContextMenuC replyContextMenu: replyContextMenuC scrolledToThis: eventId === room.scrollTarget && (y + height > chat.y + chat.contentY && y < chat.y + chat.height + chat.contentY) + data: [ + Connections { + function onMovementEnded() { + if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height) { + room.currentIndex = index; + } + } + target: chat + } + ] } } diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index 350b3846..c82bc43a 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -249,6 +249,8 @@ Page { prompt: qsTr("Enter your status message:") title: qsTr("Status Message") + text: userInfoGrid.profile ? Presence.userStatus(userInfoGrid.profile.userid) : "" + onAccepted: function (text) { Nheko.setStatusMessage(text); } diff --git a/resources/qml/TimelineBubbleMessageStyle.qml b/resources/qml/TimelineBubbleMessageStyle.qml index 3b0f2d94..dd197264 100644 --- a/resources/qml/TimelineBubbleMessageStyle.qml +++ b/resources/qml/TimelineBubbleMessageStyle.qml @@ -45,7 +45,6 @@ TimelineEvent { property int avatarMargin: (wrapper.isStateEvent || Settings.smallAvatars ? 0 : (Nheko.avatarSize + 8)) // align bubble with section header property alias hovered: messageHover.hovered - property bool scrolledToThis: false mainInset: (threadId ? (4 + Nheko.paddingSmall) : 0) + 4 replyInset: mainInset + 4 + Nheko.paddingSmall diff --git a/resources/qml/TimelineDefaultMessageStyle.qml b/resources/qml/TimelineDefaultMessageStyle.qml index 331a5dfe..16db9964 100644 --- a/resources/qml/TimelineDefaultMessageStyle.qml +++ b/resources/qml/TimelineDefaultMessageStyle.qml @@ -45,7 +45,6 @@ TimelineEvent { property int avatarMargin: (wrapper.isStateEvent || Settings.smallAvatars ? 0 : (Nheko.avatarSize + 8)) // align bubble with section header property alias hovered: messageHover.hovered - property bool scrolledToThis: false mainInset: (threadId ? (4 + Nheko.paddingSmall) : 0) replyInset: mainInset + 4 + Nheko.paddingSmall @@ -127,7 +126,9 @@ TimelineEvent { to: 0 } ScriptAction { - script: wrapper.room.eventShown() + script: { + wrapper.room.eventShown(); + } } } } diff --git a/resources/qml/TimelineEvent.qml b/resources/qml/TimelineEvent.qml index 3cc239c9..ef1a9578 100644 --- a/resources/qml/TimelineEvent.qml +++ b/resources/qml/TimelineEvent.qml @@ -13,6 +13,7 @@ EventDelegateChooser { id: wrapper required property bool isStateEvent + property bool scrolledToThis: false // qmllint disable required EventDelegateChoice { diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index c29eb537..53b1951c 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -27,7 +27,9 @@ Item { Keys.onPressed: event => { if (event.text && event.key !== Qt.Key_Enter && event.key !== Qt.Key_Return && !topBar.searchHasFocus) { TimelineManager.focusMessageInput(); - room.input.setText(room.input.text + event.text); + if (event.modifiers != Qt.ControlModifier) { + room.input.setText(room.input.text + event.text); + } } } onRoomChanged: if (room != null) diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index a2bfe414..281f60d5 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -96,7 +96,7 @@ Pane { Layout.column: 1 Layout.row: 1 Layout.rowSpan: 2 - displayName: roomName + displayName: room ? room.plainRoomName : roomName enabled: false implicitHeight: Nheko.avatarSize implicitWidth: Nheko.avatarSize diff --git a/resources/qml/dialogs/InputDialog.qml b/resources/qml/dialogs/InputDialog.qml index bf3cbc9a..c963febb 100644 --- a/resources/qml/dialogs/InputDialog.qml +++ b/resources/qml/dialogs/InputDialog.qml @@ -13,6 +13,8 @@ ApplicationWindow { property alias prompt: promptLabel.text property alias echoMode: statusInput.echoMode + property alias text: statusInput.text + signal accepted(text: string) modality: Qt.NonModal diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index be05f8bd..3c663b94 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -986,8 +986,15 @@ ChatPage::createRoom(const mtx::requests::CreateRoom &req) return; } + bool direct = req.is_direct; + std::string direct_user; + if (direct && !req.invite.empty()) + direct_user = req.invite.front(); + http::client()->create_room( - req, [this](const mtx::responses::CreateRoom &res, mtx::http::RequestErr err) { + req, + [this, direct, direct_user](const mtx::responses::CreateRoom &res, + mtx::http::RequestErr err) { if (err) { const auto err_code = mtx::errors::to_string(err->matrix_error.errcode); const auto error = err->matrix_error.error; @@ -1000,6 +1007,16 @@ ChatPage::createRoom(const mtx::requests::CreateRoom &req) } QString newRoomId = QString::fromStdString(res.room_id.to_string()); + + if (direct && !direct_user.empty()) { + utils::markRoomAsDirect(newRoomId, + {RoomMember{ + .user_id = QString::fromStdString(direct_user), + .display_name = "", + .avatar_url = "", + }}); + } + emit showNotification(tr("Room %1 created.").arg(newRoomId)); emit newRoom(newRoomId); emit changeToRoom(newRoomId); diff --git a/src/LoginPage.cpp b/src/LoginPage.cpp index ea295136..9b48730d 100644 --- a/src/LoginPage.cpp +++ b/src/LoginPage.cpp @@ -184,13 +184,14 @@ LoginPage::checkHomeserverVersion() "v1.7", "v1.8", "v1.9", + "v1.10", }; return supported.count(v) != 0; }) == versions.versions.cend()) { emit versionErrorCb( tr("The selected server does not support a version of the Matrix protocol, that this " "client understands (%1 to %2). You can't sign in.") - .arg(u"v1.1", u"v1.9")); + .arg(u"v1.1", u"v1.10")); return; } diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index ea9f560d..42a1521d 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -60,7 +60,7 @@ MainWindow::MainWindow(QWindow *parent) connect(chat_page_, &ChatPage::closing, this, [this] { switchToLoginPage(""); }); connect(chat_page_, &ChatPage::unreadMessages, this, &MainWindow::setWindowTitle); - connect(chat_page_, SIGNAL(unreadMessages(int)), trayIcon_, SLOT(setUnreadCount(int))); + connect(chat_page_, &ChatPage::unreadMessages, trayIcon_, &TrayIcon::setUnreadCount); connect(chat_page_, &ChatPage::showLoginPage, this, &MainWindow::switchToLoginPage); connect(chat_page_, &ChatPage::showNotification, this, &MainWindow::showNotification); diff --git a/src/RegisterPage.cpp b/src/RegisterPage.cpp index 824547bc..93e2cf1b 100644 --- a/src/RegisterPage.cpp +++ b/src/RegisterPage.cpp @@ -139,13 +139,14 @@ RegisterPage::versionsCheck() "v1.7", "v1.8", "v1.9", + "v1.10", }; return supported.count(v) != 0; }) == versions.versions.cend()) { emit setHsError( tr("The selected server does not support a version of the Matrix protocol that " "this client understands (%1 to %2). You can't register.") - .arg(u"v1.1", u"v1.9")); + .arg(u"v1.1", u"v1.10")); emit hsErrorChanged(); return; } diff --git a/src/TrayIcon.cpp b/src/TrayIcon.cpp index c89e69cc..c62fecea 100644 --- a/src/TrayIcon.cpp +++ b/src/TrayIcon.cpp @@ -12,9 +12,9 @@ #include "TrayIcon.h" -MsgCountComposedIcon::MsgCountComposedIcon(const QString &filename) +MsgCountComposedIcon::MsgCountComposedIcon(const QIcon &icon) : QIconEngine() - , icon_{QIcon{filename}} + , icon_{icon} { } @@ -41,8 +41,8 @@ MsgCountComposedIcon::paint(QPainter *painter, brush.setColor(backgroundColor); QFont f; - f.setPointSizeF(8); - f.setWeight(QFont::Thin); + f.setPixelSize(int(BubbleDiameter * 0.6)); + f.setWeight(QFont::Bold); painter->setBrush(brush); painter->setPen(Qt::NoPen); @@ -66,9 +66,6 @@ MsgCountComposedIcon::clone() const QList<QSize> MsgCountComposedIcon::availableSizes(QIcon::Mode mode, QIcon::State state) -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - const -#endif { Q_UNUSED(mode); Q_UNUSED(state); @@ -97,11 +94,12 @@ MsgCountComposedIcon::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State s TrayIcon::TrayIcon(const QString &filename, QWindow *parent) : QSystemTrayIcon(parent) + , icon(filename) { #if defined(Q_OS_MACOS) || defined(Q_OS_WIN) - setIcon(QIcon(filename)); + setIcon(icon); #else - icon_ = new MsgCountComposedIcon(filename); + auto icon_ = new MsgCountComposedIcon(icon); setIcon(QIcon(icon_)); #endif @@ -122,6 +120,15 @@ void TrayIcon::setUnreadCount(int count) { qGuiApp->setBadgeNumber(count); + +#if !defined(Q_OS_MACOS) && !defined(Q_OS_WIN) + if (count != previousCount) { + auto i = new MsgCountComposedIcon(icon); + i->msgCount = count; + setIcon(QIcon(i)); + previousCount = count; + } +#endif } #include "moc_TrayIcon.cpp" diff --git a/src/TrayIcon.h b/src/TrayIcon.h index f2009612..7c0bc7b2 100644 --- a/src/TrayIcon.h +++ b/src/TrayIcon.h @@ -15,15 +15,11 @@ class QPainter; class MsgCountComposedIcon final : public QIconEngine { public: - MsgCountComposedIcon(const QString &filename); + MsgCountComposedIcon(const QIcon &icon); void paint(QPainter *p, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; QIconEngine *clone() const override; - QList<QSize> availableSizes(QIcon::Mode mode, QIcon::State state) -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - const -#endif - override; + QList<QSize> availableSizes(QIcon::Mode mode, QIcon::State state) override; QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; int msgCount = 0; @@ -47,7 +43,6 @@ private: QAction *viewAction_; QAction *quitAction_; -#if !defined(Q_OS_MACOS) && !defined(Q_OS_WIN) - MsgCountComposedIcon *icon_; -#endif + int previousCount = 0; + QIcon icon; }; diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index f50bc3c0..2172c34c 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -1420,7 +1420,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const return tr("Will prevent swipe motions like swiping left/right between Rooms and " "Timeline, or swiping a message to reply."); case ScaleFactor: - return tr("Change the scale factor of the whole user interface."); + return tr("Change the scale factor of the whole user interface. Requires a restart to " + "take effect."); case UseStunServer: return tr( "Will use turn.matrix.org as assist when your home server does not offer one."); diff --git a/src/UsersModel.cpp b/src/UsersModel.cpp index a017aa84..61d1bddd 100644 --- a/src/UsersModel.cpp +++ b/src/UsersModel.cpp @@ -11,6 +11,7 @@ #include "CompletionModelRoles.h" #include "Logging.h" #include "UserSettingsPage.h" +#include "Utils.h" UsersModel::UsersModel(const std::string &roomId, QObject *parent) : QAbstractListModel(parent) @@ -24,10 +25,13 @@ UsersModel::UsersModel(const std::string &roomId, QObject *parent) std::get_if<mtx::events::AccountDataEvent<mtx::events::account_data::Direct>>( &e.value())) { for (const auto &[userId, roomIds] : event->content.user_to_rooms) { + if (roomIds.empty()) + continue; + displayNames.push_back( - QString::fromStdString(cache::displayName(roomIds[0], userId))); + QString::fromStdString(cache::displayName(roomIds.at(0), userId))); userids.push_back(QString::fromStdString(userId)); - avatarUrls.push_back(cache::avatarUrl(QString::fromStdString(roomIds[0]), + avatarUrls.push_back(cache::avatarUrl(QString::fromStdString(roomIds.at(0)), QString::fromStdString(userId))); } } @@ -66,10 +70,7 @@ UsersModel::data(const QModelIndex &index, int role) const case CompletionModel::CompletionRole: if (UserSettings::instance()->markdown()) return QStringLiteral("[%1](https://matrix.to/#/%2)") - .arg(QString(displayNames[index.row()]) - .replace("[", "\\[") - .replace("]", "\\]") - .toHtmlEscaped(), + .arg(utils::escapeMentionMarkdown(QString(displayNames[index.row()])), QString(QUrl::toPercentEncoding(userids[index.row()]))); else return displayNames[index.row()]; diff --git a/src/Utils.cpp b/src/Utils.cpp index 8b8a11dc..3e7340f4 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -582,6 +582,34 @@ utils::linkifyMessage(const QString &body) } QString +utils::escapeMentionMarkdown(QString input) +{ + input = input.toHtmlEscaped(); + + constexpr std::array<char, 10> markdownChars = { + '\\', + '`', + '*', + '_', + /*'{', '}',*/ '[', + ']', + '<', + '>', + /* '(', ')', '#', '-', '+', '.', '!', */ '~', + '|', + }; + + QByteArray replacement = "\\\\"; + + for (char c : markdownChars) { + replacement[1] = c; + input.replace(QChar::fromLatin1(c), QLatin1StringView(replacement)); + } + + return input; +} + +QString utils::escapeBlacklistedHtml(const QString &rawStr) { static const std::set<QByteArray> allowedTags = { @@ -1139,18 +1167,19 @@ utils::getFormattedQuoteBody(const RelatedInfo &related, const QString &html) return QStringLiteral("sent a video"); } default: { - return related.quoted_formatted_body; + return escapeBlacklistedHtml(related.quoted_formatted_body); } } }; + return QStringLiteral("<mx-reply><blockquote><a " "href=\"https://matrix.to/#/%1/%2\">In reply " "to</a> <a href=\"https://matrix.to/#/%3\">%4</a><br" "/>%5</blockquote></mx-reply>") .arg(related.room, QString::fromStdString(related.related_event), - related.quoted_user, - related.quoted_user, + QUrl::toPercentEncoding(related.quoted_user), + related.quoted_user.toHtmlEscaped(), getFormattedBody()) + html; } diff --git a/src/Utils.h b/src/Utils.h index 75438a7b..9c5e4713 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -140,6 +140,9 @@ linkifyMessage(const QString &body); QString markdownToHtml(const QString &text, bool rainbowify = false, bool noExtensions = false); +QString +escapeMentionMarkdown(QString input); + //! Escape every html tag, that was not whitelisted QString escapeBlacklistedHtml(const QString &data); diff --git a/src/main.cpp b/src/main.cpp index 15519b8a..bdfb84e7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,7 +21,7 @@ // in theory we can enable this everywhere, but the header is missing on some of our CI systems and // it is too much effort to install. -#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) +#if __has_include(<QtGui/qpa/qplatformwindow_p.h>) #include <QtGui/qpa/qplatformwindow_p.h> #endif @@ -169,7 +169,7 @@ main(int argc, char *argv[]) // this needs to be after setting the application name. Or how would we find our settings // file then? -#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) +#if !defined(Q_OS_MACOS) if (qgetenv("QT_SCALE_FACTOR").size() == 0) { float factor = utils::scaleFactor(); @@ -178,36 +178,16 @@ main(int argc, char *argv[]) } #endif - // This is some hacky programming, but it's necessary (AFAIK?) to get the unique config name - // parsed before the SingleApplication userdata is set. - QString userdata{QLatin1String("")}; QString matrixUri; for (int i = 1; i < argc; ++i) { QString arg{argv[i]}; - if (arg.startsWith(QLatin1String("--profile="))) { - arg.remove(QStringLiteral("--profile=")); - userdata = arg; - } else if (arg.startsWith(QLatin1String("-p="))) { - arg.remove(QStringLiteral("-p=")); - userdata = arg; - } else if (arg == QLatin1String("--profile") || arg == QLatin1String("-p")) { - if (i < argc - 1) // if i is less than argc - 1, we still have a parameter - // left to process as the name - { - ++i; // the next arg is the name, so increment - userdata = QString{argv[i]}; - } - } else if (arg.startsWith(QLatin1String("matrix:"))) { + if (arg.startsWith(QLatin1String("matrix:"))) { matrixUri = arg; } } QApplication app(argc, argv); - KDSingleApplication singleapp( - QStringLiteral("im.nheko.nheko-%1") - .arg(userdata == QLatin1String("default") ? QLatin1String("") : userdata)); - QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); @@ -250,12 +230,27 @@ main(int argc, char *argv[]) if (parser.isSet(compactDb)) cache::setNeedsCompactFlag(); + if (parser.isSet(configName)) + UserSettings::initialize(parser.value(configName)); + else + UserSettings::initialize(std::nullopt); + + auto settings = UserSettings::instance().toWeakRef(); + + auto profileName = settings.lock()->profile(); + + KDSingleApplication singleapp( + QStringLiteral("im.nheko.nheko-%1") + .arg(profileName == QLatin1String("default") ? QLatin1String("") : profileName)); + // This check needs to happen _after_ process(), so that we actually print help for --help when // Nheko is already running. if (!singleapp.isPrimaryInstance()) { auto token = qgetenv("XDG_ACTIVATION_TOKEN"); -#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) +#if __has_include(<QtGui/qpa/qplatformwindow_p.h>) && \ + ((QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) && QT_CONFIG(wayland)) || \ + (QT_VERSION < QT_VERSION_CHECK(6, 7, 0) && defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))) // getting a valid activation token on wayland is a bit of a pain, it works most reliably // when you have an actual window, that has the focus... auto waylandApp = app.nativeInterface<QNativeInterface::QWaylandApplication>(); @@ -370,13 +365,6 @@ main(int argc, char *argv[]) auto filter = new NhekoFixupPaletteEventFilter(&app); app.installEventFilter(filter); - if (parser.isSet(configName)) - UserSettings::initialize(parser.value(configName)); - else - UserSettings::initialize(std::nullopt); - - auto settings = UserSettings::instance().toWeakRef(); - QFont font; QString userFontFamily = settings.lock()->font(); if (!userFontFamily.isEmpty() && userFontFamily != QLatin1String("default")) { diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index ac1d47a2..c7687ab6 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -187,9 +187,6 @@ InputBar::addMention(QString mention, QString text) mentionTexts_.push_back(text); emit mentionsChanged(); - if (mention == u"@room") { - this->containsAtRoom_ = true; - } } } @@ -200,9 +197,6 @@ InputBar::removeMention(QString mention) mentions_.removeAt(idx); mentionTexts_.removeAt(idx); emit mentionsChanged(); - if (mention == u"@room") { - this->containsAtRoom_ = false; - } } } @@ -244,6 +238,7 @@ InputBar::updateTextContentProperties(const QString &t, bool charDeleted) auto roomMention = containsRoomMention(t) && this->room->permissions()->canPingRoom(); if (roomMention != this->containsAtRoom_) { + this->containsAtRoom_ = roomMention; if (roomMention) addMention(QStringLiteral(u"@room"), QStringLiteral(u"@room")); else @@ -462,8 +457,7 @@ replaceMatrixToMarkdownLink(QString input) int newline = input.indexOf('\n', endOfName); if (endOfLink > endOfName && (newline == -1 || endOfLink < newline)) { auto name = input.mid(startOfName + 1, endOfName - startOfName - 1); - name.replace("\\[", "["); - name.replace("\\]", "]"); + name.remove(QChar(u'\\'), Qt::CaseSensitive); input.replace(startOfName, endOfLink - startOfName + 1, name); replaced = true; } @@ -501,8 +495,11 @@ mtx::common::Mentions InputBar::generateMentions() { std::vector<std::string> userMentions; + bool atRoom = false; for (const auto &m : mentions_) - if (m != u"@room") + if (m == u"@room") + atRoom = true; + else userMentions.push_back(m.toStdString()); if (!room->reply().isEmpty()) { @@ -516,12 +513,14 @@ InputBar::generateMentions() auto mention = mtx::common::Mentions{ .user_ids = userMentions, - .room = containsAtRoom_, + // We use the atRoom from the mentions list to allow suppressing a room mention + .room = atRoom, }; // this->containsAtRoom_ = false; // this->mentions_.clear(); // this->mentionTexts_.clear(); + return mention; } @@ -1031,9 +1030,9 @@ InputBar::command(const QString &command, QString args) } else if (command == QLatin1String("converttoroom")) { utils::removeDirectFromRoom(this->room->roomId()); } else if (command == QLatin1String("ignore")) { - this->toggleIgnore(args, true); + this->toggleIgnore(args.trimmed(), true); } else if (command == QLatin1String("unignore")) { - this->toggleIgnore(args, false); + this->toggleIgnore(args.trimmed(), false); } else { return false; } @@ -1044,6 +1043,13 @@ InputBar::command(const QString &command, QString args) void InputBar::toggleIgnore(const QString &user, const bool ignored) { + if (!user.startsWith(u"@")) { + MainWindow::instance()->showNotification( + tr("You need to pass a valid mxid when ignoring a user. '%1' is not a valid userid.") + .arg(user)); + return; + } + UserProfile *profile = new UserProfile(QString(), user, TimelineViewManager::instance()); connect(profile, &UserProfile::failedToFetchProfile, [user, profile] { MainWindow::instance()->showNotification(tr("Failed to fetch user %1").arg(user)); diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index c38de662..5e885d4f 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -194,15 +194,17 @@ public slots: void storeForEdit() { - textBeforeEdit = text(); - mentionsBefore = mentions_; - mentionTextsBefore = mentionTexts_; + textBeforeEdit = text(); + mentionsBefore = mentions_; + mentionTextsBefore = mentionTexts_; + containsAtRoomBefore = containsAtRoom_; emit mentionsChanged(); } void restoreAfterEdit() { - mentions_ = mentionsBefore; - mentionTexts_ = mentionTextsBefore; + mentions_ = mentionsBefore; + mentionTexts_ = mentionTextsBefore; + containsAtRoom_ = containsAtRoomBefore; mentionsBefore.clear(); mentionTextsBefore.clear(); setText(textBeforeEdit); @@ -216,6 +218,9 @@ public slots: mentions_ = newMentions; mentionTexts_ = newMentionTexts; + + this->containsAtRoom_ = newMentions.contains(u"@room"); + emit mentionsChanged(); } @@ -331,6 +336,7 @@ private: // store stuff during edits QStringList mentionsBefore, mentionTextsBefore; QString textBeforeEdit; + bool containsAtRoomBefore = false; using UploadHandle = std::unique_ptr<MediaUpload, DeleteLaterDeleter>; std::vector<UploadHandle> unconfirmedUploads; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 03606d90..48b58ee5 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -736,7 +736,9 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r .arg(displayName(QString::fromStdString(e.sender))) .arg(QStringLiteral("<img height=\"32\" src=\"%1\">") .arg(QUrl::toPercentEncoding( - QString::fromStdString(e.content.url)))); + QString::fromStdString(e.content.url) + .replace("mxc://", "image://MxcImage/"), + ":/"))); else return tr("%1 removed the room avatar.") .arg(displayName(QString::fromStdString(e.sender))); @@ -2244,8 +2246,9 @@ TimelineModel::getRoomVias(const QString &roomId) void TimelineModel::copyLinkToEvent(const QString &eventId) const { - auto link = QStringLiteral("%1/%2?%3") - .arg(getBareRoomLink(room_id_), + // Event links shouldn't use an alias, since that can be repointed. + auto link = QStringLiteral("https://matrix.to/#/%1/%2?%3") + .arg(QUrl::toPercentEncoding(room_id_), QString(QUrl::toPercentEncoding(eventId)), getRoomVias(room_id_)); QGuiApplication::clipboard()->setText(link); @@ -3080,8 +3083,6 @@ TimelineModel::setEdit(const QString &newEdit) input()->storeForEdit(); } - auto quoted = [](QString in) { return in.replace("[", "\\[").replace("]", "\\]"); }; - if (edit_ != newEdit) { auto ev = events.get(newEdit.toStdString(), ""); if (ev && mtx::accessors::sender(*ev) == http::client()->user_id().to_string()) { @@ -3100,10 +3101,12 @@ TimelineModel::setEdit(const QString &newEdit) for (const auto &user : mentionsList->user_ids) { auto userid = QString::fromStdString(user); mentions.append(userid); - mentionTexts.append( - QStringLiteral("[%1](https://matrix.to/#/%2)") - .arg(displayName(userid).replace("[", "\\[").replace("]", "\\]"), - QString(QUrl::toPercentEncoding(userid)))); + mentionTexts.append(QStringLiteral("[%1](https://matrix.to/#/%2)") + .arg(utils::escapeMentionMarkdown( + // not using TimelineModel::displayName here, + // because it would double html escape + cache::displayName(room_id_, userid)), + QString(QUrl::toPercentEncoding(userid)))); } } @@ -3127,7 +3130,9 @@ TimelineModel::setEdit(const QString &newEdit) for (const auto &[user, link] : reverseNameMapping) { // TODO(Nico): html unescape the user name - editText.replace(user, QStringLiteral("[%1](%2)").arg(quoted(user), link)); + editText.replace( + user, + QStringLiteral("[%1](%2)").arg(utils::escapeMentionMarkdown(user), link)); } } @@ -3275,8 +3280,8 @@ TimelineModel::widgetLinks() const QStringList list; auto user = utils::localUser(); - auto av = QUrl::toPercentEncoding( - QString::fromStdString(http::client()->mxc_to_download_url(avatarUrl(user).toStdString()))); + // auto av = QUrl::toPercentEncoding( + // QString::fromStdString(http::client()->mxc_to_download_url(avatarUrl(user).toStdString()))); auto disp = QUrl::toPercentEncoding(displayName(user)); auto theme = UserSettings::instance()->theme(); if (theme == QStringLiteral("system")) @@ -3297,7 +3302,7 @@ TimelineModel::widgetLinks() const url.replace("$matrix_user_id", user); url.replace("$matrix_room_id", QUrl::toPercentEncoding(room_id_)); url.replace("$matrix_display_name", disp); - url.replace("$matrix_avatar_url", av); + // url.replace("$matrix_avatar_url", av); url.replace("$matrix_widget_id", QUrl::toPercentEncoding(QString::fromStdString(p.content.id))); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 479fe7e1..1b2635b0 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -232,6 +232,9 @@ TimelineViewManager::openRoomSettings(QString room_id) void TimelineViewManager::openInviteUsers(QString roomId) { + if (!roomId.startsWith('!')) + return; + InviteesModel *model = new InviteesModel{rooms_->getRoomById(roomId).data()}; connect(model, &InviteesModel::accept, this, [this, model, roomId]() { emit inviteUsers(roomId, model->mxids()); @@ -243,6 +246,9 @@ TimelineViewManager::openInviteUsers(QString roomId) void TimelineViewManager::openGlobalUserProfile(QString userId) { + if (!userId.startsWith('@')) + return; + UserProfile *profile = new UserProfile{QString{}, userId, this}; QQmlEngine::setObjectOwnership(profile, QQmlEngine::JavaScriptOwnership); emit openProfile(profile); @@ -615,11 +621,14 @@ TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEven //! WORKAROUND(Nico): for https://bugreports.qt.io/browse/QTBUG-93281 void -TimelineViewManager::fixImageRendering(QQuickTextDocument *t, QQuickItem *i) +TimelineViewManager::fixImageRendering([[maybe_unused]] QQuickTextDocument *t, + [[maybe_unused]] QQuickItem *i) { +#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0) if (t) { QObject::connect(t->textDocument(), SIGNAL(imagesLoaded()), i, SLOT(updateWholeDocument())); } +#endif } using IgnoredUsers = mtx::events::EphemeralEvent<mtx::events::account_data::IgnoredUsers>; diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index 138b4283..e28b1bc1 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -19,7 +19,7 @@ #include "UserSettingsPage.h" #include "Utils.h" -#if XCB_AVAILABLE +#if XCB_AVAILABLE && QT_CONFIG(xcb) #include <xcb/xproto.h> #endif @@ -186,7 +186,7 @@ Nheko::createRoom(bool space, void Nheko::setWindowRole([[maybe_unused]] QWindow *win, [[maybe_unused]] QString newRole) const { -#if XCB_AVAILABLE +#if XCB_AVAILABLE && QT_CONFIG(xcb) const QNativeInterface::QX11Application *x11Interface = qGuiApp->nativeInterface<QNativeInterface::QX11Application>(); diff --git a/src/voip/WebRTCSession.cpp b/src/voip/WebRTCSession.cpp index ba1d5424..d55b7c41 100644 --- a/src/voip/WebRTCSession.cpp +++ b/src/voip/WebRTCSession.cpp @@ -339,21 +339,16 @@ newVideoSinkChain(GstElement *pipe) g_object_set(compositor, "background", 1, nullptr); switch (graphicsApi) { case QSGRendererInterface::OpenGL: { - GstElement *glupload = gst_element_factory_make("glupload", nullptr); - GstElement *glcolorconvert = gst_element_factory_make("glcolorconvert", nullptr); - GstElement *qmlglsink = gst_element_factory_make("qml6glsink", nullptr); - GstElement *glsinkbin = gst_element_factory_make("glsinkbin", nullptr); + GstElement *qmlglsink = gst_element_factory_make("qml6glsink", nullptr); + GstElement *glsinkbin = gst_element_factory_make("glsinkbin", nullptr); g_object_set(qmlglsink, "widget", WebRTCSession::instance().getVideoItem(), nullptr); g_object_set(glsinkbin, "sink", qmlglsink, nullptr); - gst_bin_add_many( - GST_BIN(pipe), queue, compositor, glupload, glcolorconvert, glsinkbin, nullptr); - gst_element_link_many(queue, compositor, glupload, glcolorconvert, glsinkbin, nullptr); + gst_bin_add_many(GST_BIN(pipe), queue, compositor, glsinkbin, nullptr); + gst_element_link_many(queue, compositor, glsinkbin, nullptr); gst_element_sync_state_with_parent(queue); gst_element_sync_state_with_parent(compositor); - gst_element_sync_state_with_parent(glupload); - gst_element_sync_state_with_parent(glcolorconvert); gst_element_sync_state_with_parent(glsinkbin); // to propagate context (hopefully) |