Compare commits

..

85 Commits

Author SHA1 Message Date
Joshua Goins
2803a865b2 Preserve mx-reply in the edited message if it exists
(cherry picked from commit fa57db8e83)
2024-04-24 15:29:52 -04:00
Heiko Becker
86e8dc2e40 GIT_SILENT Update Appstream for new release 2024-04-08 17:57:16 +02:00
Heiko Becker
8839c71d97 GIT_SILENT Upgrade release service version to 24.02.2. 2024-04-08 17:01:48 +02:00
l10n daemon script
1663ef41dc GIT_SILENT Sync po/docbooks with svn 2024-03-31 03:22:50 +00:00
l10n daemon script
3bdd2c123e GIT_SILENT Sync po/docbooks with svn 2024-03-28 03:25:22 +00:00
l10n daemon script
404fc37174 GIT_SILENT Sync po/docbooks with svn 2024-03-27 11:28:50 +00:00
l10n daemon script
6de8bf90c0 GIT_SILENT Sync po/docbooks with svn 2024-03-27 03:25:15 +00:00
l10n daemon script
ca9be5aea3 GIT_SILENT Sync po/docbooks with svn 2024-03-26 03:27:24 +00:00
Tobias Fella
429e20417c Fix crash when visiting user
We're adding the "join" action so that rooms are joined.
libQuotient doesn't like it when we the action is join and the uri is for a user.

BUG: 483744
2024-03-23 20:55:24 +01:00
Julius Künzel
f1397a4742 Add back Appimage job, it is fixed now 2024-03-21 22:40:23 +00:00
l10n daemon script
9be2c0513c GIT_SILENT Sync po/docbooks with svn 2024-03-21 03:00:02 +00:00
Albert Astals Cid
5ffe6ec59f Remove craft-appimage-qt6
It has been failing for more than 4 weeks
2024-03-19 23:32:09 +01:00
l10n daemon script
add48f88ce GIT_SILENT Sync po/docbooks with svn 2024-03-19 03:01:18 +00:00
Joshua Goins
09d0dd2b7a Fix the quick format bar not actually doing anything
(cherry picked from commit 5109b4fcd1)
2024-03-18 16:17:52 -04:00
Joshua Goins
498f6d9e64 Exclude lonely question marks from the linkify regex
Many URLs we see in the KDE rooms end with a question mark, without a
space. The linkify regex for plain URLs incorrectly considered them as
part of the link, which usually breaks them when opened in a web
browser. Now the regex excludes these, unless they are accompanied by
another character (so links like kde.org/realurl?is=true will still
work.)

(cherry picked from commit 1b7f482d0b)
2024-03-18 16:17:52 -04:00
l10n daemon script
f33780e996 GIT_SILENT Sync po/docbooks with svn 2024-03-16 03:42:32 +00:00
Heiko Becker
f731877519 GIT_SILENT Update Appstream for new release 2024-03-15 22:12:49 +01:00
Heiko Becker
5e48d5cb25 GIT_SILENT Upgrade release service version to 24.02.1. 2024-03-15 21:09:19 +01:00
Joshua Goins
afba8430f7 Don't destroy formatting when editing previous messages
Adds a few new methods to grab the markdown/slightly rich text from the
message, and will intelligently re-insert user mentions as needed.

(cherry picked from commit e2eb6ab33c)
2024-03-15 15:10:29 -04:00
Joshua Goins
18d14446bf Prevent collision between KUnifiedPush DBus and KRunner DBus
These share the same D-Bus service name (org.kde.neochat) which comes
with a fun little addition: KRunner activation! While this is not a
problem while NeoChat is running - since it's already registered - this
becomes an issue while searching for NeoChat in something like the
Kickoff. The Kickoff (and consequently, KRunner) tries to activate the
NeoChat D-Bus service which runs our unified push parts.

This introduces a "FakeRunner" which watches closely for calls to the
KRunner interface while we're in unified push mode (or directly called
from D-Bus but not running) so it quits immediately.

(cherry picked from commit 35b08d085c)
2024-03-15 14:48:00 -04:00
l10n daemon script
84c2173a04 GIT_SILENT Sync po/docbooks with svn 2024-03-14 03:36:36 +00:00
l10n daemon script
7f3112f53d GIT_SILENT Sync po/docbooks with svn 2024-03-13 02:54:10 +00:00
l10n daemon script
371016f977 GIT_SILENT made messages (after extraction) 2024-03-13 02:23:20 +00:00
Ingo Klöcker
35efe9693d This is no longer needed now that ECM 6.0.0 is available 2024-03-12 16:38:17 +01:00
Ingo Klöcker
586cf3fc6c Create an APPX package for NeoChat 24.02 2024-03-12 16:38:17 +01:00
l10n daemon script
a88b5d6af9 GIT_SILENT Sync po/docbooks with svn 2024-03-12 02:51:19 +00:00
Nicolas Fella
35aa08b279 Remove manual window toggling for system tray icon
KStatusNotifierItem automatically does this for us
since we associate our window with it

Doing it again causes the window to be toggled again, which means
it won't be shown

BUG: 479721

BUG: 482779
(cherry picked from commit 550dc43dc0)
2024-03-11 11:43:57 +01:00
l10n daemon script
a75072d069 GIT_SILENT Sync po/docbooks with svn 2024-03-11 02:51:12 +00:00
Tobias Fella
4177ade7a0 Don't link KDBusAddons on windows
(cherry picked from commit ad6c7dbd1f)
2024-03-10 14:31:39 +01:00
l10n daemon script
8c1eab76cf GIT_SILENT Sync po/docbooks with svn 2024-03-09 03:00:03 +00:00
l10n daemon script
4d72ace337 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-03-09 02:56:34 +00:00
l10n daemon script
d575323651 GIT_SILENT Sync po/docbooks with svn 2024-03-07 02:50:29 +00:00
Ingo Klöcker
28fdf28a23 Don't require kirigami-addons master
The default version of kirigami-addons (0.11.90) should be sufficient
for 24.02. And the Qt version is already set by the CraftConfig used for
Qt 6 builds.
2024-03-06 14:52:45 +00:00
Albert Astals Cid
1032ae7ca7 flatpak: Switch to non-preview runtime
(cherry picked from commit 5b007129e3)
2024-03-06 00:33:51 +01:00
l10n daemon script
84960385f8 GIT_SILENT Sync po/docbooks with svn 2024-03-04 02:51:12 +00:00
l10n daemon script
baa1486657 GIT_SILENT Sync po/docbooks with svn 2024-03-03 03:04:25 +00:00
l10n daemon script
1bfbfa51b4 GIT_SILENT made messages (after extraction) 2024-03-03 02:32:39 +00:00
l10n daemon script
e575a86252 GIT_SILENT Sync po/docbooks with svn 2024-03-02 02:56:51 +00:00
Tobias Fella
6f6aebcada Fix (un)ignoring unknown users
(cherry picked from commit 943f6c762c)
2024-03-01 09:33:06 +00:00
l10n daemon script
7a9695e3ee GIT_SILENT Sync po/docbooks with svn 2024-02-29 02:59:21 +00:00
l10n daemon script
9e589d71ff GIT_SILENT Sync po/docbooks with svn 2024-02-28 02:54:05 +00:00
l10n daemon script
5de5fa3053 GIT_SILENT Sync po/docbooks with svn 2024-02-25 03:07:03 +00:00
Tobias Fella
abcb5a0334 Fix saving images from maximize component
Fixes #643
2024-02-21 16:53:12 +01:00
l10n daemon script
b901ea6e2a GIT_SILENT Sync po/docbooks with svn 2024-02-21 02:56:16 +00:00
James Graham
8cfd515db2 Add feature flag for reply in thread
Currently the ability to reply in threads was added but not the ability to actually view threads so this doesn't currently make much sense to just have enabled int he main build.

Note: I want to cherrypick this so it's just the flag. I'll add a feature flag page to dev tools for master soon.


(cherry picked from commit 864f9b8f74)
2024-02-20 20:11:01 +00:00
l10n daemon script
3e5181d64e GIT_SILENT Sync po/docbooks with svn 2024-02-20 02:59:05 +00:00
Carl Schwan
ae53bf5df2 Add neochat 24.02 release note
(cherry picked from commit dc5366e924)
2024-02-19 12:33:21 +00:00
l10n daemon script
d2ed304672 GIT_SILENT Sync po/docbooks with svn 2024-02-19 02:58:48 +00:00
l10n daemon script
4924bd05a8 GIT_SILENT Sync po/docbooks with svn 2024-02-18 02:57:59 +00:00
l10n daemon script
9aa7553a1f GIT_SILENT Sync po/docbooks with svn 2024-02-16 03:02:48 +00:00
Heiko Becker
1c910165c1 GIT_SILENT Update Appstream for new release 2024-02-16 00:48:30 +01:00
Heiko Becker
05a84da722 GIT_SILENT Upgrade release service version to 24.02.0. 2024-02-16 00:01:13 +01:00
Carl Schwan
1ab8b85f06 Fix reaction update event when the event is not there anymore
Happens when interacting witht Mjonir quite often


(cherry picked from commit 6d3839dd42)
2024-02-15 20:13:28 +00:00
Carl Schwan
05883bcb71 Fix reaction delegate sizing for text reaction
(cherry picked from commit 755a060e12)
2024-02-15 20:13:01 +00:00
l10n daemon script
20cb6dc864 GIT_SILENT Sync po/docbooks with svn 2024-02-15 02:52:41 +00:00
l10n daemon script
b6cf60acdb GIT_SILENT made messages (after extraction) 2024-02-15 02:21:10 +00:00
Tobias Fella
d4a6a41981 Skip Welcome screen when there's only one connection and it's loaded
If the connection is stuck, we can still log in to a different one that way.

(cherry picked from commit 7150445f8e)
2024-02-14 18:16:07 +01:00
Tobias Fella
8c2682c943 Allow dropping connections from the welcome page
This is the last piece required to make sure that we can recover from broken connections, e.g., when the access token is invalid.

(cherry picked from commit b02bdd22dd)
2024-02-14 18:14:20 +01:00
Heiko Becker
9c56561853 GIT_SILENT Update Appstream for new release
(cherry picked from commit 0cd0a6a672)
2024-02-14 14:39:59 +01:00
l10n daemon script
ab9410cc03 GIT_SILENT Sync po/docbooks with svn 2024-02-14 03:00:27 +00:00
Tobias Fella
43fae7af04 Show custom emoji reactions as per MSC4027
(cherry picked from commit ca57732871)
2024-02-12 16:02:48 +01:00
Tobias Fella
0cf19d21f2 Fix AudioDelegate playback
(cherry picked from commit b909cb2db8)
2024-02-10 23:06:44 +01:00
l10n daemon script
ce448bd027 GIT_SILENT Sync po/docbooks with svn 2024-02-09 03:07:07 +00:00
l10n daemon script
056e91df9f GIT_SILENT Sync po/docbooks with svn 2024-02-05 03:32:35 +00:00
l10n daemon script
258815ca10 GIT_SILENT Sync po/docbooks with svn 2024-02-02 02:54:20 +00:00
l10n daemon script
174373fb15 GIT_SILENT Sync po/docbooks with svn 2024-01-31 03:10:56 +00:00
l10n daemon script
aa0790d7fd GIT_SILENT Sync po/docbooks with svn 2024-01-30 02:58:53 +00:00
l10n daemon script
e6c589c6ac GIT_SILENT Sync po/docbooks with svn 2024-01-29 02:59:49 +00:00
James Graham
4b1805bdaa Fix copying selected text from a message
(cherry picked from commit 48502480df)
2024-01-28 10:06:27 +00:00
l10n daemon script
6055460bff GIT_SILENT Sync po/docbooks with svn 2024-01-28 02:58:51 +00:00
l10n daemon script
0642685874 GIT_SILENT Sync po/docbooks with svn 2024-01-27 02:57:15 +00:00
l10n daemon script
e2b7e6778e GIT_SILENT Sync po/docbooks with svn 2024-01-26 02:59:18 +00:00
l10n daemon script
22bf9b8a59 GIT_SILENT Sync po/docbooks with svn 2024-01-24 02:56:01 +00:00
l10n daemon script
85fc1a1f46 GIT_SILENT Sync po/docbooks with svn 2024-01-23 03:02:41 +00:00
l10n daemon script
624123407c GIT_SILENT Sync po/docbooks with svn 2024-01-22 03:38:56 +00:00
James Graham
7bad41739f Cherrypick 24.02 Clip QuickSwitcher
Clip QuickSwitcher to stop the delegates overlapping the dialog


(cherry picked from commit 8e8105d04d)
2024-01-17 17:19:40 +00:00
l10n daemon script
ee16504aa0 GIT_SILENT Sync po/docbooks with svn 2024-01-17 02:57:22 +00:00
Ingo Klöcker
cf308bcdce Require master of ECM
We need the fix for APK packaging with Android NDK r25


(cherry picked from commit 21d9e69712)
2024-01-16 14:21:07 +00:00
l10n daemon script
6fbfa48c77 GIT_SILENT Sync po/docbooks with svn 2024-01-16 02:57:45 +00:00
l10n daemon script
67d71cb590 GIT_SILENT Sync po/docbooks with svn 2024-01-15 02:56:34 +00:00
l10n daemon script
c5817df2c9 GIT_SILENT Sync po/docbooks with svn 2024-01-14 03:43:35 +00:00
Joshua Goins
b94fcd6858 Make the search message dialog header way prettier, like it is in KCMs
I think I've heard of this before...

(cherry picked from commit 2247a2a7af)
2024-01-13 20:37:48 -05:00
Joshua Goins
8a8874fcb6 Add missing thread roles in SearchModel
This fixes the message search so it works again!

(cherry picked from commit 08a0fbfd6b)
2024-01-13 20:35:25 -05:00
James Graham
b593f7321b Cherrypick 24.02 Readonly Room
Add readonly property to a room and use it to decide whether to show chatbar, replies and edits

BUG: 479590


(cherry picked from commit ec4aa73e37)
2024-01-13 12:06:00 +00:00
Albert Astals Cid
5002258e34 GIT_SILENT Upgrade release service version to 24.01.95. 2024-01-11 20:53:22 +01:00
587 changed files with 131937 additions and 246387 deletions

View File

@@ -2,7 +2,4 @@
; SPDX-License-Identifier: CC0-1.0 ; SPDX-License-Identifier: CC0-1.0
[BlueprintSettings] [BlueprintSettings]
kde/frameworks/extra-cmake-modules.version=master kde/applications/neochat.packageAppx = True
kde/unreleased/kirigami-addons.version=master
kde/applications/neochat.packageAppx=True
libs/qt.qtMajorVersion=6

View File

@@ -2,7 +2,7 @@
"id": "org.kde.neochat", "id": "org.kde.neochat",
"branch": "master", "branch": "master",
"runtime": "org.kde.Platform", "runtime": "org.kde.Platform",
"runtime-version": "6.8", "runtime-version": "6.6",
"sdk": "org.kde.Sdk", "sdk": "org.kde.Sdk",
"command": "neochat", "command": "neochat",
"tags": [ "tags": [
@@ -25,23 +25,13 @@
"modules": [ "modules": [
{ {
"name": "kirigamiaddons", "name": "kirigamiaddons",
"config-opts": [ "config-opts": [ "-DBUILD_TESTING=OFF" ],
"-DBUILD_TESTING=OFF"
],
"buildsystem": "cmake-ninja", "buildsystem": "cmake-ninja",
"sources": [ "sources": [ { "type": "git", "url": "https://invent.kde.org/libraries/kirigami-addons.git" } ]
{
"type": "git",
"url": "https://invent.kde.org/libraries/kirigami-addons.git"
}
]
}, },
{ {
"name": "kquickimageeditor", "name": "kquickimageeditor",
"config-opts": [ "config-opts": [ "-DBUILD_WITH_QT6=ON" ],
"-DBUILD_WITH_QT6=ON",
"-DBUILD_TESTING=OFF"
],
"buildsystem": "cmake-ninja", "buildsystem": "cmake-ninja",
"sources": [ "sources": [
{ {
@@ -53,19 +43,17 @@
{ {
"name": "olm", "name": "olm",
"buildsystem": "cmake-ninja", "buildsystem": "cmake-ninja",
"config-opts": [ "config-opts": [ "-DOLM_TESTS=OFF" ],
"-DOLM_TESTS=OFF"
],
"sources": [ "sources": [
{ {
"type": "git", "type": "git",
"url": "https://gitlab.matrix.org/matrix-org/olm.git", "url": "https://gitlab.matrix.org/matrix-org/olm.git",
"tag": "3.2.16", "tag": "3.2.10",
"x-checker-data": { "x-checker-data": {
"type": "git", "type": "git",
"tag-pattern": "^([\\d.]+)$" "tag-pattern": "^([\\d.]+)$"
}, },
"commit": "7e0c8277032e40308987257b711b38af8d77cc69" "commit": "9908862979147a71dc6abaecd521be526ae77be1"
} }
] ]
}, },
@@ -77,13 +65,13 @@
"-Dvapi=false", "-Dvapi=false",
"-Dgtk_doc=false", "-Dgtk_doc=false",
"-Dintrospection=false", "-Dintrospection=false",
"-Dcrypto=disabled" "-Dgcrypt=false"
], ],
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.6.tar.xz", "url": "https://download.gnome.org/sources/libsecret/0.20/libsecret-0.20.5.tar.xz",
"sha256": "747b8c175be108c880d3adfb9c3537ea66e520e4ad2dccf5dce58003aeeca090", "sha256": "3fb3ce340fcd7db54d87c893e69bfc2b1f6e4d4b279065ffe66dac9f0fd12b4d",
"x-checker-data": { "x-checker-data": {
"type": "gnome", "type": "gnome",
"name": "libsecret", "name": "libsecret",
@@ -98,13 +86,13 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://github.com/frankosterfeld/qtkeychain/archive/refs/tags/0.15.0.tar.gz", "url": "https://github.com/frankosterfeld/qtkeychain/archive/0.14.2.tar.gz",
"sha256": "f4254dc8f0933b06d90672d683eab08ef770acd8336e44dfa030ce041dc2ca22", "sha256": "cf2e972b783ba66334a79a30f6b3a1ea794a1dc574d6c3bebae5ffd2f0399571",
"x-checker-data": { "x-checker-data": {
"type": "anitya", "type": "anitya",
"project-id": 4138, "project-id": 4138,
"stable-only": true, "stable-only": true,
"url-template": "https://github.com/frankosterfeld/qtkeychain/archive/refs/tags/$version.tar.gz" "url-template": "https://github.com/frankosterfeld/qtkeychain/archive/v$version.tar.gz"
} }
} }
], ],
@@ -112,8 +100,7 @@
"-DBUILD_WITH_QT6=ON", "-DBUILD_WITH_QT6=ON",
"-DCMAKE_INSTALL_LIBDIR=/app/lib", "-DCMAKE_INSTALL_LIBDIR=/app/lib",
"-DLIB_INSTALL_DIR=/app/lib", "-DLIB_INSTALL_DIR=/app/lib",
"-DBUILD_TRANSLATIONS=NO", "-DBUILD_TRANSLATIONS=NO"
"-DBUILD_TESTING=OFF"
] ]
}, },
{ {
@@ -136,31 +123,29 @@
{ {
"name": "cmark", "name": "cmark",
"buildsystem": "cmake-ninja", "buildsystem": "cmake-ninja",
"config-opts": [ "config-opts": [ "-DCMARK_TESTS=OFF" ],
"-DCMARK_TESTS=OFF",
"-DCMAKE_BUILD_TYPE=Release",
"-DCMAKE_INSTALL_PREFIX=/app"
],
"sources": [ "sources": [
{ {
"type": "git", "type": "git",
"url": "https://github.com/commonmark/cmark.git" "url": "https://github.com/commonmark/cmark.git"
} }
], ],
"config-opts": [
"-DCMARK_TESTS=OFF",
"-DCMAKE_BUILD_TYPE=Release",
"-DCMAKE_INSTALL_PREFIX=/app"
],
"builddir": true "builddir": true
}, },
{ {
"name": "qcoro", "name": "qcoro",
"buildsystem": "cmake-ninja", "buildsystem": "cmake-ninja",
"config-opts": [ "config-opts": [ "-DQCORO_BUILD_EXAMPLES=OFF", "-DBUILD_TESTING=OFF" ],
"-DQCORO_BUILD_EXAMPLES=OFF",
"-DBUILD_TESTING=OFF"
],
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://github.com/danvratil/qcoro/archive/refs/tags/v0.11.0.tar.gz", "url": "https://github.com/danvratil/qcoro/archive/refs/tags/v0.7.0.tar.gz",
"sha256": "9942c5b4c533192f6c5954dc6d10178b3829075e6a621b67df73f0a4b74d8297", "sha256": "23ef0217926e67c8d2eb861cf91617da2f7d8d5a9ae6c62321b21448b1669210",
"x-checker-data": { "x-checker-data": {
"type": "anitya", "type": "anitya",
"project-id": 236236, "project-id": 236236,
@@ -173,15 +158,14 @@
{ {
"name": "neochat", "name": "neochat",
"buildsystem": "cmake-ninja", "buildsystem": "cmake-ninja",
"config-opts": [
"-DBUILD_TESTING=OFF",
"-DNEOCHAT_FLATPAK=ON"
],
"sources": [ "sources": [
{ {
"type": "dir", "type": "dir",
"path": "." "path": "."
} }
],
"config-opts": [
"-DNEOCHAT_FLATPAK=ON"
] ]
} }
] ]

1
.gitignore vendored
View File

@@ -12,4 +12,3 @@ kate.project.ctags.*
.idea/ .idea/
cmake-build-* cmake-build-*
src/res.generated.qrc src/res.generated.qrc
.qmlls.ini

View File

@@ -5,17 +5,11 @@ include:
- project: sysadmin/ci-utilities - project: sysadmin/ci-utilities
file: file:
- /gitlab-templates/reuse-lint.yml - /gitlab-templates/reuse-lint.yml
- /gitlab-templates/json-validation.yml
- /gitlab-templates/xml-lint.yml
- /gitlab-templates/yaml-lint.yml
- /gitlab-templates/android-qt6.yml - /gitlab-templates/android-qt6.yml
- /gitlab-templates/linux-qt6.yml - /gitlab-templates/linux-qt6.yml
- /gitlab-templates/linux-qt6-next.yml
- /gitlab-templates/windows-qt6.yml - /gitlab-templates/windows-qt6.yml
# - /gitlab-templates/freebsd-qt6.yml - /gitlab-templates/freebsd-qt6.yml
- /gitlab-templates/flatpak.yml - /gitlab-templates/flatpak.yml
- /gitlab-templates/snap-snapcraft-lxd.yml
- /gitlab-templates/craft-android-qt6-apks.yml - /gitlab-templates/craft-android-qt6-apks.yml
- /gitlab-templates/craft-appimage-qt6.yml - /gitlab-templates/craft-appimage-qt6.yml
- /gitlab-templates/craft-windows-x86-64-qt6.yml - /gitlab-templates/craft-windows-x86-64-qt6.yml
- /gitlab-templates/craft-windows-appx-qt6.yml

View File

@@ -2,43 +2,40 @@
# SPDX-License-Identifier: BSD-2-Clause # SPDX-License-Identifier: BSD-2-Clause
Dependencies: Dependencies:
- 'on': ['Linux', 'Android', 'FreeBSD', 'Windows'] - 'on': ['Linux', 'Android', 'FreeBSD', 'Windows']
'require': 'require':
'frameworks/extra-cmake-modules': '@latest-kf6' 'frameworks/extra-cmake-modules': '@latest-kf6'
'frameworks/kcoreaddons': '@latest-kf6' 'frameworks/kcoreaddons': '@latest-kf6'
'frameworks/kirigami': '@latest-kf6' 'frameworks/kirigami': '@latest-kf6'
'frameworks/ki18n': '@latest-kf6' 'frameworks/ki18n': '@latest-kf6'
'frameworks/kconfig': '@latest-kf6' 'frameworks/kconfig': '@latest-kf6'
'frameworks/syntax-highlighting': '@latest-kf6' 'frameworks/syntax-highlighting': '@latest-kf6'
'frameworks/kitemmodels': '@latest-kf6' 'frameworks/kitemmodels': '@latest-kf6'
'frameworks/kquickcharts': '@latest-kf6' 'frameworks/kquickcharts': '@latest-kf6'
'frameworks/knotifications': '@latest-kf6' 'frameworks/knotifications': '@latest-kf6'
'frameworks/kcolorscheme': '@latest-kf6' 'frameworks/kcolorscheme': '@latest-kf6'
'frameworks/kiconthemes': '@latest-kf6' 'libraries/kquickimageeditor': '@latest-kf6'
'libraries/kquickimageeditor': '@latest-kf6' 'frameworks/sonnet': '@latest-kf6'
'frameworks/sonnet': '@latest-kf6' 'frameworks/prison': '@latest-kf6'
'frameworks/prison': '@latest-kf6' 'libraries/kirigami-addons': '@latest-kf6'
'libraries/kirigami-addons': '@latest-kf6' 'third-party/libquotient': '@latest'
'third-party/libquotient': '@latest' 'third-party/qtkeychain': '@latest'
'third-party/qtkeychain': '@latest' 'third-party/cmark': '@latest'
'third-party/cmark': '@latest' 'third-party/qcoro': '@latest'
'third-party/qcoro': '@latest' - 'on': ['Windows', 'Linux', 'FreeBSD']
- 'on': ['Windows', 'Linux', 'FreeBSD'] 'require':
'require': 'frameworks/qqc2-desktop-style': '@latest-kf6'
'frameworks/qqc2-desktop-style': '@latest-kf6' 'frameworks/kio': '@latest-kf6'
'frameworks/kio': '@latest-kf6' 'frameworks/kwindowsystem': '@latest-kf6'
'frameworks/kwindowsystem': '@latest-kf6' 'frameworks/kstatusnotifieritem': '@latest-kf6'
'frameworks/kstatusnotifieritem': '@latest-kf6' - 'on': ['Linux', 'FreeBSD']
'frameworks/kcrash': '@latest-kf6' 'require':
- 'on': ['Linux', 'FreeBSD'] 'frameworks/kdbusaddons': '@latest-kf6'
'require':
'frameworks/kdbusaddons': '@latest-kf6'
'frameworks/purpose': '@latest-kf6'
- 'on': ['Linux'] - 'on': ['Linux']
'require': 'require':
'sdk/selenium-webdriver-at-spi': '@latest-kf6' 'sdk/selenium-webdriver-at-spi': '@latest-kf6'
Options: Options:
per-test-timeout: 90 per-test-timeout: 90
require-passing-tests-on: ['Linux', 'Android', 'FreeBSD', 'Windows'] require-passing-tests-on: [ '@all' ]

51
.reuse/dep5 Normal file
View File

@@ -0,0 +1,51 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: NeoChat
Upstream-Contact: Carl Schwan <carlschwan@kde.org>
Files: 128-logo.png icons/* logo.png org.kde.neochat.svg org.kde.neochat.tray.svg android/res/drawable/neochat.png
Copyright: 2020 Carson Black <uhhadd@gmail.com>
License: LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
Files: android/res/drawable/splash.xml
Copyright: 2020 Tobias Fella <tobias.fella@kde.org>
License: BSD-2-Clause
Files: .gitignore
Copyright: None
License: CC0-1.0
Files: .gitlab/issue_templates/bug.md
Copyright: 2021 Carl Schwan <carlschwan@kde.org>
License: CC0-1.0
Files: src/res.qrc src/res_android.qrc src/res_desktop.qrc
Copyright: None
License: CC0-1.0
Files: cmake/Flatpak/99-noto-mono-color-emoji.conf
Copyright: 2021 Carl Schwan <carlschwan@kde.org>
License: BSD-2-Clause
Files: src/neochatconfig.kcfg
Copyright: 2020-2021 Carl Schwan <carlschwan@kde.org>, Tobias Fella <tobias.fella@kde.org>
License: BSD-2-Clause
Files: src/neochat.notifyrc
Copyright: 2020 Tobias Fella <tobias.fella@kde.org>
License: BSD-2-Clause
Files: src/qml/confetti.png src/qml/glowdot.png
Copyright: 2021 Alexey Andreyev <aa13q@ya.ru>
License: CC0-1.0
Files: .flatpak-manifest.json
Copyright: 2020-2022 Tobias Fella <tobias.fella@kde.org>
License: BSD-2-Clause
Files: autotests/data/*
Copyright: none
License: CC0-1.0
Files: appiumtests/data/*
Copyright: 2023 Tobias Fella <tobias.fella@kde.org>
License: CC0-1.0

View File

@@ -7,14 +7,14 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
# KDE Applications version, managed by release script. # KDE Applications version, managed by release script.
set(RELEASE_SERVICE_VERSION_MAJOR "25") set(RELEASE_SERVICE_VERSION_MAJOR "24")
set(RELEASE_SERVICE_VERSION_MINOR "03") set(RELEASE_SERVICE_VERSION_MINOR "02")
set(RELEASE_SERVICE_VERSION_MICRO "80") set(RELEASE_SERVICE_VERSION_MICRO "2")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION}) project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
set(KF_MIN_VERSION "6.6") set(KF_MIN_VERSION "5.240.0")
set(QT_MIN_VERSION "6.5") set(QT_MIN_VERSION "6.5")
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE) find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
@@ -24,7 +24,7 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(KDE_COMPILERSETTINGS_LEVEL 6.0) set(KDE_COMPILERSETTINGS_LEVEL 5.105)
include(FeatureSummary) include(FeatureSummary)
include(ECMSetupVersion) include(ECMSetupVersion)
@@ -38,9 +38,6 @@ include(KDEGitCommitHooks)
include(ECMCheckOutboundLicense) include(ECMCheckOutboundLicense)
include(ECMQtDeclareLoggingCategory) include(ECMQtDeclareLoggingCategory)
include(ECMAddAndroidApk) include(ECMAddAndroidApk)
include(ECMQmlModule)
include(GenerateExportHeader)
include(ECMGenerateHeaders)
if (NOT ANDROID) if (NOT ANDROID)
include(KDEClangFormat) include(KDEClangFormat)
endif() endif()
@@ -61,12 +58,7 @@ set_package_properties(Qt6 PROPERTIES
TYPE REQUIRED TYPE REQUIRED
PURPOSE "Basic application components" PURPOSE "Basic application components"
) )
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
if (QT_KNOWN_POLICY_QTP0004)
qt_policy(SET QTP0004 NEW)
endif ()
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels IconThemes ColorScheme)
set_package_properties(KF6 PROPERTIES set_package_properties(KF6 PROPERTIES
TYPE REQUIRED TYPE REQUIRED
PURPOSE "Basic application components" PURPOSE "Basic application components"
@@ -77,10 +69,6 @@ set_package_properties(KF6Kirigami PROPERTIES
) )
find_package(KF6KirigamiAddons 0.7.2 REQUIRED) find_package(KF6KirigamiAddons 0.7.2 REQUIRED)
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE)
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Purpose)
endif ()
if(ANDROID) if(ANDROID)
find_package(OpenSSL) find_package(OpenSSL)
set_package_properties(OpenSSL PROPERTIES set_package_properties(OpenSSL PROPERTIES
@@ -89,8 +77,7 @@ if(ANDROID)
) )
else() else()
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets) find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem Crash) find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem)
find_package(KF6SyntaxHighlighting ${KF_MIN_VERSION} REQUIRED)
set_package_properties(KF6QQC2DesktopStyle PROPERTIES set_package_properties(KF6QQC2DesktopStyle PROPERTIES
TYPE RUNTIME TYPE RUNTIME
) )
@@ -103,11 +90,11 @@ else()
) )
endif() endif()
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU) if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED) find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
endif() endif()
find_package(QuotientQt6 0.9) find_package(QuotientQt6 0.7)
set_package_properties(QuotientQt6 PROPERTIES set_package_properties(QuotientQt6 PROPERTIES
TYPE REQUIRED TYPE REQUIRED
DESCRIPTION "Qt wrapper around Matrix API" DESCRIPTION "Qt wrapper around Matrix API"
@@ -115,6 +102,11 @@ set_package_properties(QuotientQt6 PROPERTIES
PURPOSE "Talk with matrix server" PURPOSE "Talk with matrix server"
) )
if (NOT TARGET Olm::Olm)
message(FATAL_ERROR "NeoChat requires Quotient with the E2EE feature enabled")
endif()
find_package(cmark) find_package(cmark)
set_package_properties(cmark PROPERTIES set_package_properties(cmark PROPERTIES
TYPE REQUIRED TYPE REQUIRED
@@ -174,9 +166,6 @@ if (BUILD_TESTING)
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test) find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test)
add_subdirectory(autotests) add_subdirectory(autotests)
add_subdirectory(appiumtests) add_subdirectory(appiumtests)
if (NOT ANDROID)
add_subdirectory(memorytests)
endif()
endif() endif()
if(KF6DocTools_FOUND) if(KF6DocTools_FOUND)

View File

@@ -1,6 +1,6 @@
<!-- <!--
SPDX-FileCopyrightText: 2020-2021 Carl Schwan <carlschwan@kde.org> SPDX-FileCopyrightText: 2020-2021 Carl Schwan <carlschwan@kde.org>
SPDX-FileCopyrightText: 2020-2024 Tobias Fella <tobias.fella@kde.org> SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com> SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
SPDX-License-Identifier: CC0-1.0 SPDX-License-Identifier: CC0-1.0
--> -->
@@ -11,23 +11,24 @@ A Qt/QML based Matrix client.
<a href='https://matrix.org'><img src='https://matrix.org/docs/legacy/made-for-matrix.png' alt='Made for Matrix' height=64 target=_blank /></a> <a href='https://matrix.org'><img src='https://matrix.org/docs/legacy/made-for-matrix.png' alt='Made for Matrix' height=64 target=_blank /></a>
<a href='https://flathub.org/apps/details/org.kde.neochat'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a> <a href='https://flathub.org/apps/details/org.kde.neochat'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a>
<a href='https://snapcraft.io/neochat'><img width='190px' alt='Download on the Snap Store' src='https://apps.kde.org/store_badges/snapstore/en.svg'/></a> <a href='https://snapcraft.io/neochat'><img width='190px' alt='Download on the Snap Store' src='https://snapcraft.io/static/images/badges/en/snap-store-black.svg'/></a>
## Introduction ## Introduction
NeoChat is a client for [Matrix](https://matrix.org), the decentralized communication protocol for instant NeoChat is a client for [Matrix](https://matrix.org), the decentralized communication protocol for instant
messaging. messaging. It is a fork of Spectral, using KDE frameworks, most notably [Kirigami](https://invent.kde.org/frameworks/kirigami)
to provide a convergent experience across multiple platforms.
NeoChat is based on KDE frameworks and as [libQuotient](https://github.com/quotient-im/libQuotient), a NeoChat also make use of other KDE Frameworks as well as [libQuotient](https://github.com/quotient-im/libQuotient), a
Qt-based SDK for the [Matrix Protocol](https://spec.matrix.org/). Qt-based SDK for the [Matrix Protocol](https://spec.matrix.org/).
![Timeline](https://cdn.kde.org/screenshots/neochat/application.png) ![Timeline](https://cdn.kde.org/screenshots/neochat/application.png)
## Features ## Features
NeoChat aims to be a fully featured application for the Matrix specification. As such most parts of the current specification are supported, with the notable exceptions NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions
of VoIP, threads, and some aspects of End-to-End Encryption. There are a few other smaller omissions due to the fact that the Matrix spec is constantly of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly
evolving, but the aim remains to provide eventual support for the entire spec. evolving but the aim remains to provide eventual support for the entire spec.
Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are: Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:
- Polls - MSC3381 - Polls - MSC3381
@@ -38,9 +39,26 @@ Due to the nature of the Matrix specification development NeoChat also supports
Details where to find stable releases for NeoChat can be found on its [homepage](https://apps.kde.org/neochat). Details where to find stable releases for NeoChat can be found on its [homepage](https://apps.kde.org/neochat).
Nightly builds for Linux and Windows can be downloaded from [cdn.kde.org](https://cdn.kde.org/ci-builds/network/neochat/). In addition to the stable builds, unstable nightly builds are available for all platforms. These can be downloaded
Nightly builds for Android are available from [KDE's nightly F-Droid repository](https://community.kde.org/Android/F-Droid). from the [binary factory](https://binary-factory.kde.org/). There are unstable versions for the following platforms
Nightly Flatpaks are available from [KDE's nightly Flatpak repository](https://userbase.kde.org/Tutorials/Flatpak). in addition to stable ones:
- Android
- MacOS
- Windows
Additionally the nightly Flatpak version can be obtained from the nightly Flatpak repo using the following commands in your terminal:
```
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak remote-add --if-not-exists kdeapps --from https://distribute.kde.org/kdeapps.flatpakrepo
flatpak install kdeapps org.kde.neochat
```
The unstable Android version can also be obtained from the [KDE nightly F-Droid repo](https://community.kde.org/Android/FDroid).
## Running
Just start the executable in your preferred way - either from the build directory or from the installed location.
## Building NeoChat ## Building NeoChat
@@ -51,18 +69,14 @@ is primarily aimed at Linux development.
For Windows and Android [Craft](https://invent.kde.org/packaging/craft) is the primary choice. There are guides for setting up For Windows and Android [Craft](https://invent.kde.org/packaging/craft) is the primary choice. There are guides for setting up
development environments for [Windows](https://community.kde.org/Get_Involved/development/Windows) and [Android](https://develop.kde.org/docs/packaging/android/building_applications/). development environments for [Windows](https://community.kde.org/Get_Involved/development/Windows) and [Android](https://develop.kde.org/docs/packaging/android/building_applications/).
## Running
Just start the executable in your preferred way - either from the build directory or from the installed location.
## Tests ## Tests
Tests are in the repository under [autotests](autotests) and [appiumtests](appiumtests). Tests are in the repository under [autotests](autotests) and should all pass for any contribution.
The project has CI setup to test new commits to the repository. All tests are expected to pass for a merge request to The project has CI setup to test new commits to the repository. All tests are expected to pass for a merge request to
be complete. be complete.
## Current build status Current build status
![coverage](https://invent.kde.org/network/neochat/badges/master/pipeline.svg) ![coverage](https://invent.kde.org/network/neochat/badges/master/pipeline.svg)
@@ -86,9 +100,9 @@ The best place to reach the maintainers is on the KDE Matrix instance in the Neo
## Acknowledgement ## Acknowledgement
NeoChat utilizes [libQuotient](https://github.com/quotient-im/libQuotient/) as its Matrix SDK. This program utilizes [libQuotient](https://github.com/quotient-im/libQuotient/) as its Matrix SDK.
NeoChat is a fork of [Spectral](https://gitlab.com/spectral-im/spectral/). This program is a fork of [Spectral](https://gitlab.com/spectral-im/spectral/).
## License ## License

View File

@@ -1,90 +0,0 @@
# SPDX-FileCopyrightText: none
# SPDX-License-Identifier: CC0-1.0
version = 1
SPDX-PackageName = "NeoChat"
SPDX-PackageSupplier = "Carl Schwan <carlschwan@kde.org>"
[[annotations]]
path = ["128-logo.png", "icons/**", "logo.png", "org.kde.neochat.svg", "org.kde.neochat.tray.svg", "android/res/drawable/neochat.png", "android/neochat-playstore.png"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2020 Carson Black <uhhadd@gmail.com>"
SPDX-License-Identifier = "LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL"
[[annotations]]
path = "android/res/drawable/splash.xml"
precedence = "aggregate"
SPDX-FileCopyrightText = "2020 Tobias Fella <tobias.fella@kde.org>"
SPDX-License-Identifier = "BSD-2-Clause"
[[annotations]]
path = ".gitignore"
precedence = "aggregate"
SPDX-FileCopyrightText = "None"
SPDX-License-Identifier = "CC0-1.0"
[[annotations]]
path = ".gitlab/issue_templates/bug.md"
precedence = "aggregate"
SPDX-FileCopyrightText = "2021 Carl Schwan <carlschwan@kde.org>"
SPDX-License-Identifier = "CC0-1.0"
[[annotations]]
path = ["src/res.qrc", "src/res_android.qrc", "src/res_desktop.qrc"]
precedence = "aggregate"
SPDX-FileCopyrightText = "None"
SPDX-License-Identifier = "CC0-1.0"
[[annotations]]
path = "cmake/Flatpak/99-noto-mono-color-emoji.conf"
precedence = "aggregate"
SPDX-FileCopyrightText = "2021 Carl Schwan <carlschwan@kde.org>"
SPDX-License-Identifier = "BSD-2-Clause"
[[annotations]]
path = "src/neochatconfig.kcfg"
precedence = "aggregate"
SPDX-FileCopyrightText = "2020-2021 Carl Schwan <carlschwan@kde.org>, Tobias Fella <tobias.fella@kde.org>"
SPDX-License-Identifier = "BSD-2-Clause"
[[annotations]]
path = "src/neochat.notifyrc"
precedence = "aggregate"
SPDX-FileCopyrightText = "2020 Tobias Fella <tobias.fella@kde.org>"
SPDX-License-Identifier = "BSD-2-Clause"
[[annotations]]
path = ["src/qml/confetti.png", "src/qml/glowdot.png"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2021 Alexey Andreyev <aa13q@ya.ru>"
SPDX-License-Identifier = "CC0-1.0"
[[annotations]]
path = ".flatpak-manifest.json"
precedence = "aggregate"
SPDX-FileCopyrightText = "2020-2022 Tobias Fella <tobias.fella@kde.org>"
SPDX-License-Identifier = "BSD-2-Clause"
[[annotations]]
path = "autotests/data/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "none"
SPDX-License-Identifier = "CC0-1.0"
[[annotations]]
path = "appiumtests/data/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2023 Tobias Fella <tobias.fella@kde.org>"
SPDX-License-Identifier = "CC0-1.0"
[[annotations]]
path = "src/purpose/purposeplugin.json"
precedence = "aggregate"
SPDX-FileCopyrightText = "2023 Tobias Fella <tobias.fella@kde.org>"
SPDX-License-Identifier = "BSD-2-Clause"
[[annotations]]
path = "memorytests/memtest-sync.json"
precedence = "aggregate"
SPDX-FileCopyrightText = "2024 James Graham <james.h.graham@protonmail.com>"
SPDX-License-Identifier = "BSD-2-Clause"

View File

@@ -55,6 +55,5 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <!-- for Android >= 33 -->
</manifest> </manifest>

View File

@@ -12,7 +12,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.6.0' classpath 'com.android.tools.build:gradle:7.4.1'
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -1,56 +0,0 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
import os
import subprocess
import sys
import unittest
import time
from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
class CreateRoomTest(unittest.TestCase):
mockServerProcess: subprocess.Popen
@classmethod
def setUpClass(cls):
cls.mockServerProcess = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), "login-server.py")])
options = AppiumOptions()
options.set_capability("app", "neochat --ignore-ssl-errors --test")
cls.driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', options=options)
def setUp(self):
pass
def tearDown(self):
if not self._outcome.result.wasSuccessful():
self.driver.get_screenshot_as_file("failed_test_shot_{}.png".format(self.id()))
@classmethod
def tearDownClass(self):
self.mockServerProcess.terminate()
self.driver.quit()
def test_create_room(self):
self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click()
self.driver.find_element(by=AppiumBy.NAME, value="Show Menu").click()
self.driver.find_element(by=AppiumBy.NAME, value="Create a Room").click()
self.driver.find_element(by=AppiumBy.NAME, value="Name:").send_keys("Super awesome room name")#
time.sleep(0.1) # without this, the second half of the text is sent to the topic field?!
self.driver.find_element(by=AppiumBy.NAME, value="Topic:").send_keys("There are not enough raccoons here")
time.sleep(0.1)
self.driver.find_element(by=AppiumBy.NAME, value="Create Room").click()
time.sleep(0.1)
self.driver.find_element(by=AppiumBy.NAME, value="Super awesome room name").click()
self.driver.find_element(by=AppiumBy.NAME, value="Show Room Information").click()
self.driver.find_element(by=AppiumBy.NAME, value="There are not enough raccoons here")
if __name__ == '__main__':
unittest.main()

View File

@@ -1,78 +0,0 @@
{
"next_batch": "batch1234",
"rooms": {
"join": {
"!newroom123321:localhost:1234": {
"state": {
"events": [
{
"type": "m.room.member",
"state_key": "@user:localhost:1234",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_0:localhost:1234",
"room_id": "!newroom123321:localhost:1234",
"content": {
"avatar_url": "",
"displayname": "A Display Name",
"membership": "join",
"reason": "Nothing"
},
"unsigned": {
"age": 1234
}
},
{
"type": "m.room.name",
"state_key": "",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_1:localhost:1234",
"room_id": "!newroom123321:localhost:1234",
"content": {
"name": "Super awesome room name"
},
"unsigned": {
"age": 1234
}
},
{
"type": "m.room.topic",
"state_key": "",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_2:localhost:1234",
"room_id": "!newroom123321:localhost:1234",
"content": {
"topic": "There are not enough raccoons here"
},
"unsigned": {
"age": 1234
}
}
]
},
"timeline": {
"events": [
{
"type": "m.room.message",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_1:localhost:1234",
"room_id": "!newroom123321:localhost:1234",
"content": {
"body": "This is a message",
"format": "org.matrix.custom.html",
"formatted_body": "<a href=\"https://matrix.to/#/@user:localhost:1234\">User</a>:",
"msgtype": "m.text"
},
"unsigned": {
"age": 1234
}
}
]
}
}
}
}
}

View File

@@ -5,26 +5,6 @@
"!room_id_1234:localhost:1234": { "!room_id_1234:localhost:1234": {
"state": { "state": {
"events": [ "events": [
{
"content": {
"m.federate": true,
"predecessor": {
"event_id": "$something:example.org",
"room_id": "!oldroom:example.org"
},
"room_version": "11"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "",
"type": "m.room.create",
"unsigned": {
"age": 1234,
"membership": "join"
}
},
{ {
"type": "m.room.member", "type": "m.room.member",
"state_key": "@user:localhost:1234", "state_key": "@user:localhost:1234",
@@ -46,26 +26,6 @@
}, },
"timeline": { "timeline": {
"events": [ "events": [
{
"content": {
"m.federate": true,
"predecessor": {
"event_id": "$something:example.org",
"room_id": "!oldroom:example.org"
},
"room_version": "11"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "",
"type": "m.room.create",
"unsigned": {
"age": 1234,
"membership": "join"
}
},
{ {
"type": "m.room.message", "type": "m.room.message",
"sender": "@user:localhost:1234", "sender": "@user:localhost:1234",

View File

@@ -6,8 +6,6 @@ from flask import Flask, request, abort
import os import os
app = Flask(__name__) app = Flask(__name__)
next_sync_payload = ""
@app.route("/_matrix/client/v3/login", methods=["GET"]) @app.route("/_matrix/client/v3/login", methods=["GET"])
def login_get(): def login_get():
@@ -44,13 +42,8 @@ def load_json(name):
@app.route("/_matrix/client/r0/sync") @app.route("/_matrix/client/r0/sync")
def sync(): def sync():
global next_sync_payload
result = dict() result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
if len(next_sync_payload) > 0:
result = load_json(next_sync_payload)
next_sync_payload = ""
else:
result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
return result return result
@app.route("/.well-known/matrix/client") @app.route("/.well-known/matrix/client")
@@ -72,27 +65,6 @@ def upload_keys():
reply = dict() reply = dict()
return reply return reply
@app.route("/_matrix/client/v3/createRoom", methods=["POST"])
def create_room():
global next_sync_payload
data = request.get_json()
if data["name"] != "Super awesome room name" or data["topic"] != "There are not enough raccoons here":
return dict(), 400
response = dict()
response["room_id"] = "!newroom123321:localhost:1234"
next_sync_payload = "sync_response_new_room"
return response
@app.route("/_matrix/client/v3/publicRooms", methods=["POST"])
def public_rooms():
if request.get_json()["filter"]["generic_search_term"] == "forbidden":
data = dict()
data["errcode"] = "M_FORBIDDEN"
data["error"] = "You are not allowed to search for this. Go to https://wikipedia.org for more information"
return data, 403
return dict()
if __name__ == "__main__": if __name__ == "__main__":
app.run(ssl_context='adhoc', port=1234) app.run(ssl_context='adhoc', port=1234)

View File

@@ -39,10 +39,6 @@ class OpenUserDetailsTest(unittest.TestCase):
def test_open_sheet(self): def test_open_sheet(self):
self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click() self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click()
try:
self.driver.find_element(by=AppiumBy.NAME, value="Expand Normal").click()
except:
pass
self.driver.find_element(by=AppiumBy.NAME, value="Empty room (!room_id_1234:localhost:1234)").click() self.driver.find_element(by=AppiumBy.NAME, value="Empty room (!room_id_1234:localhost:1234)").click()
self.driver.find_element(by=AppiumBy.NAME, value="A Display Name").click() self.driver.find_element(by=AppiumBy.NAME, value="A Display Name").click()
self.driver.find_element(by=AppiumBy.NAME, value="Account Details") self.driver.find_element(by=AppiumBy.NAME, value="Account Details")

View File

@@ -11,13 +11,11 @@ ecm_add_test(
TEST_NAME neochatroomtest TEST_NAME neochatroomtest
) )
if (NOT $ENV{KDE_CI}) ecm_add_test(
ecm_add_test( texthandlertest.cpp
texthandlertest.cpp LINK_LIBRARIES neochat Qt::Test
LINK_LIBRARIES neochat Qt::Test TEST_NAME texthandlertest
TEST_NAME texthandlertest )
)
endif()
ecm_add_test( ecm_add_test(
delegatesizehelpertest.cpp delegatesizehelpertest.cpp
@@ -50,9 +48,15 @@ ecm_add_test(
) )
ecm_add_test( ecm_add_test(
timelinemessagemodeltest.cpp messageeventmodeltest.cpp
LINK_LIBRARIES neochat Qt::Test LINK_LIBRARIES neochat Qt::Test
TEST_NAME timelinemessagemodeltest TEST_NAME messageeventmodeltest
)
ecm_add_test(
actionshandlertest.cpp
LINK_LIBRARIES neochat Qt::Test
TEST_NAME actionshandlertest
) )
ecm_add_test( ecm_add_test(
@@ -78,15 +82,3 @@ ecm_add_test(
LINK_LIBRARIES neochat Qt::Test LINK_LIBRARIES neochat Qt::Test
TEST_NAME linkpreviewertest TEST_NAME linkpreviewertest
) )
ecm_add_test(
messagecontentmodeltest.cpp
LINK_LIBRARIES neochat Qt::Test
TEST_NAME messagecontentmodeltest
)
ecm_add_test(
actionstest.cpp
LINK_LIBRARIES neochat Qt::Test
TEST_NAME actionstest
)

View File

@@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QTest>
#include "actionshandler.h"
#include "chatbarcache.h"
#include "testutils.h"
class ActionsHandlerTest : public QObject
{
Q_OBJECT
private:
Quotient::Connection *connection = Quotient::Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
ActionsHandler *actionsHandler = new ActionsHandler(this);
private Q_SLOTS:
void nullObject();
};
void ActionsHandlerTest::nullObject()
{
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
actionsHandler->handleMessageEvent(nullptr);
auto chatBarCache = new ChatBarCache(this);
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
actionsHandler->handleMessageEvent(chatBarCache);
auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
actionsHandler->setRoom(room);
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
actionsHandler->handleMessageEvent(nullptr);
// The final one should throw no warning so we make sure.
QTest::failOnWarning("ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
actionsHandler->handleMessageEvent(chatBarCache);
}
QTEST_GUILESS_MAIN(ActionsHandlerTest)
#include "actionshandlertest.moc"

View File

@@ -1,120 +0,0 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QObject>
#include <QTest>
#include <QSignalSpy>
#include <QVariantList>
#include "chatbarcache.h"
#include "models/actionsmodel.h"
#include "testutils.h"
using namespace Quotient;
//TODO: rainbow, rainbowme, plain, spoiler, me, join, knock, j, part, leave, nick, roomnick, myroomnick, ignore, unignore, react, ban, unban, kick
class ActionsTest : public QObject
{
Q_OBJECT
private:
Connection *connection = nullptr;
TestUtils::TestRoom *room = nullptr;
void expectMessage(const QString &actionName, const QString &args, MessageType::Type type, const QString &message);
private Q_SLOTS:
void initTestCase();
void testActions();
void testActions_data();
void testInvite();
};
void ActionsTest::initTestCase()
{
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-min-sync.json"));
}
void ActionsTest::testActions_data()
{
QTest::addColumn<QString>("command");
QTest::addColumn<std::optional<QString>>("resultText");
QTest::addColumn<std::optional<Quotient::RoomMessageEvent::MsgType>>("type");
QTest::newRow("shrug") << u"/shrug Hello"_s << std::make_optional(u"¯\\\\_(ツ)_/¯ Hello"_s)
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
QTest::newRow("lenny") << u"/lenny Hello"_s << std::make_optional(u"( ͡° ͜ʖ ͡°) Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
QTest::newRow("tableflip") << u"/tableflip Hello"_s << std::make_optional(u"(╯°□°)╯︵ ┻━┻ Hello"_s)
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
QTest::newRow("unflip") << u"/unflip Hello"_s << std::make_optional(u"┬──┬ ( ゜-゜ノ) Hello"_s)
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
QTest::newRow("rainbow") << u"/rainbow Hello"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
QTest::newRow("rainbowme") << u"/rainbowme Hello"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
QTest::newRow("plain") << u"/plain <b>Hello</b>"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
QTest::newRow("spoiler") << u"/spoiler Hello"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
QTest::newRow("me") << u"/me Hello"_s << std::make_optional(u"Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Emote);
QTest::newRow("notice") << u"/notice Hello"_s << std::make_optional(u"Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Notice);
QTest::newRow("message") << u"Hello"_s << std::make_optional(u"Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
QTest::newRow("invite") << u"/invite @foo:example.com"_s << std::optional<QString>() << std::optional<Quotient::RoomMessageEvent::MsgType>();
//TODO: join, knock, j, part, leave, nick, roomnick, myroomnick, ignore, unignore, react, ban, unban, kick
}
void ActionsTest::testActions()
{
QFETCH(QString, command);
QFETCH(std::optional<QString>, resultText);
QFETCH(std::optional<Quotient::RoomMessageEvent::MsgType>, type);
auto cache = new ChatBarCache();
cache->setText(command);
auto result = ActionsModel::handleAction(room, cache);
QCOMPARE(resultText, std::get<std::optional<QString>>(result));
QCOMPARE(type, std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result));
}
static ActionsModel::Action findAction(const QString &name)
{
for (const auto &action : ActionsModel::allActions()) {
if (action.prefix == name) {
return action;
}
}
return {};
}
void ActionsTest::expectMessage(const QString &actionName, const QString &args, MessageType::Type type, const QString &message)
{
auto action = findAction(actionName);
QSignalSpy spy(room, &TestUtils::TestRoom::showMessage);
auto result = action.handle(args, room, nullptr);
auto expected = QVariantList {type, message};
auto signal = spy.takeFirst();
QCOMPARE(signal, expected);
}
void ActionsTest::testInvite()
{
expectMessage(u"invite"_s, u"foo"_s, MessageType::Error, u"'foo' does not look like a matrix id."_s);
expectMessage(u"invite"_s, u"@invited:example.com"_s, MessageType::Information, u"@invited:example.com is already invited to this room."_s);
QCOMPARE(room->memberState(u"@invited:example.com"_s), Membership::Invite);
expectMessage(u"invite"_s, u"@banned:example.com"_s, MessageType::Information, u"@banned:example.com is banned from this room."_s);
QCOMPARE(room->memberState(u"@banned:example.com"_s), Membership::Ban);
expectMessage(u"invite"_s, connection->userId(), MessageType::Positive, u"You are already in this room."_s);
QCOMPARE(room->memberState(connection->userId()), Membership::Join);
expectMessage(u"invite"_s, u"@example:example.org"_s, MessageType::Information, u"@example:example.org is already in this room."_s);
QCOMPARE(room->memberState(u"@example:example.org"_s), Membership::Join);
QCOMPARE(room->memberState(u"@user:example.com"_s), Membership::Leave);
expectMessage(u"invite"_s, u"@user:example.com"_s, MessageType::Positive, u"@user:example.com was invited into this room."_s);
//TODO mock server, wait for invite state to change
//TODO QCOMPARE(room->memberState(u"@user:example.com"_s), Membership::Invite);
}
QTEST_MAIN(ActionsTest)
#include "actionstest.moc"

View File

@@ -6,7 +6,6 @@
#include <QObject> #include <QObject>
#include <QTest> #include <QTest>
#include <Quotient/roommember.h>
#include <Quotient/syncdata.h> #include <Quotient/syncdata.h>
#include <qtestcase.h> #include <qtestcase.h>
@@ -38,8 +37,8 @@ private Q_SLOTS:
void ChatBarCacheTest::initTestCase() void ChatBarCacheTest::initTestCase()
{ {
connection = Connection::makeMockConnection(u"@bob:kde.org"_s); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, "test-min-sync.json"_L1); room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-min-sync.json"));
} }
void ChatBarCacheTest::empty() void ChatBarCacheTest::empty()
@@ -51,7 +50,7 @@ void ChatBarCacheTest::empty()
QCOMPARE(chatBarCache->replyId(), QString()); QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), false); QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString()); QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationAuthor(), room->member(QString())); QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
QCOMPARE(chatBarCache->relationMessage(), QString()); QCOMPARE(chatBarCache->relationMessage(), QString());
QCOMPARE(chatBarCache->attachmentPath(), QString()); QCOMPARE(chatBarCache->attachmentPath(), QString());
} }
@@ -59,13 +58,13 @@ void ChatBarCacheTest::empty()
void ChatBarCacheTest::noRoom() void ChatBarCacheTest::noRoom()
{ {
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache()); QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache());
chatBarCache->setReplyId(u"$153456789:example.org"_s); chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
// These should return empty even though a reply ID has been set because the // These should return empty even though a reply ID has been set because the
// ChatBarCache has no parent. // ChatBarCache has no parent.
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation."); QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationAuthor(), Quotient::RoomMember()); QCOMPARE(chatBarCache->relationUser(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation."); QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationMessage(), QString()); QCOMPARE(chatBarCache->relationMessage(), QString());
@@ -75,13 +74,13 @@ void ChatBarCacheTest::badParent()
{ {
QScopedPointer<QObject> badParent(new QObject()); QScopedPointer<QObject> badParent(new QObject());
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(badParent.get())); QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(badParent.get()));
chatBarCache->setReplyId(u"$153456789:example.org"_s); chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
// These should return empty even though a reply ID has been set because the // These should return empty even though a reply ID has been set because the
// ChatBarCache has no parent. // ChatBarCache has no parent.
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation."); QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationAuthor(), Quotient::RoomMember()); QCOMPARE(chatBarCache->relationUser(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation."); QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationMessage(), QString()); QCOMPARE(chatBarCache->relationMessage(), QString());
@@ -90,57 +89,52 @@ void ChatBarCacheTest::badParent()
void ChatBarCacheTest::reply() void ChatBarCacheTest::reply()
{ {
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room)); QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(u"some text"_s); chatBarCache->setText(QLatin1String("some text"));
chatBarCache->setAttachmentPath(u"some/path"_s); chatBarCache->setAttachmentPath(QLatin1String("some/path"));
chatBarCache->setReplyId(u"$153456789:example.org"_s); chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
QCOMPARE(chatBarCache->text(), u"some text"_s); QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
QCOMPARE(chatBarCache->isReplying(), true); QCOMPARE(chatBarCache->isReplying(), true);
QCOMPARE(chatBarCache->replyId(), u"$153456789:example.org"_s); QCOMPARE(chatBarCache->replyId(), QLatin1String("$153456789:example.org"));
QCOMPARE(chatBarCache->isEditing(), false); QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString()); QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s)); QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s); QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
QCOMPARE(chatBarCache->attachmentPath(), QString()); QCOMPARE(chatBarCache->attachmentPath(), QString());
} }
void ChatBarCacheTest::edit() void ChatBarCacheTest::edit()
{ {
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room)); QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(QLatin1String("some text"));
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
chatBarCache->setText(u"some text"_s); QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
chatBarCache->setAttachmentPath(u"some/path"_s);
connect(chatBarCache.get(), &ChatBarCache::relationIdChanged, this, [](const QString &oldEventId, const QString &newEventId) {
QCOMPARE(oldEventId, QString());
QCOMPARE(newEventId, QString(u"$153456789:example.org"_s));
});
chatBarCache->setEditId(u"$153456789:example.org"_s);
QCOMPARE(chatBarCache->text(), u"some text"_s);
QCOMPARE(chatBarCache->isReplying(), false); QCOMPARE(chatBarCache->isReplying(), false);
QCOMPARE(chatBarCache->replyId(), QString()); QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), true); QCOMPARE(chatBarCache->isEditing(), true);
QCOMPARE(chatBarCache->editId(), u"$153456789:example.org"_s); QCOMPARE(chatBarCache->editId(), QLatin1String("$153456789:example.org"));
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s)); QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s); QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
QCOMPARE(chatBarCache->attachmentPath(), QString()); QCOMPARE(chatBarCache->attachmentPath(), QString());
} }
void ChatBarCacheTest::attachment() void ChatBarCacheTest::attachment()
{ {
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room)); QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(u"some text"_s); chatBarCache->setText(QLatin1String("some text"));
chatBarCache->setEditId(u"$153456789:example.org"_s); chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
chatBarCache->setAttachmentPath(u"some/path"_s); chatBarCache->setAttachmentPath(QLatin1String("some/path"));
QCOMPARE(chatBarCache->text(), u"some text"_s); QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
QCOMPARE(chatBarCache->isReplying(), false); QCOMPARE(chatBarCache->isReplying(), false);
QCOMPARE(chatBarCache->replyId(), QString()); QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), false); QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString()); QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationAuthor(), room->member(QString())); QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
QCOMPARE(chatBarCache->relationMessage(), QString()); QCOMPARE(chatBarCache->relationMessage(), QString());
QCOMPARE(chatBarCache->attachmentPath(), u"some/path"_s); QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
} }
QTEST_MAIN(ChatBarCacheTest) QTEST_MAIN(ChatBarCacheTest)

View File

@@ -25,7 +25,7 @@
"content": { "content": {
"user_ids": [ "user_ids": [
"@alice:matrix.org", "@alice:matrix.org",
"@bob:kde.org" "@bob:example.com"
] ]
}, },
"room_id": "!jEsUZKDJdhlrceRyVU:example.org", "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
@@ -35,7 +35,7 @@
"content": { "content": {
"$153456789:example.org": { "$153456789:example.org": {
"m.read": { "m.read": {
"@alice:example.org": { "@alice:matrix.org": {
"ts": 1436451550453 "ts": 1436451550453
} }
} }
@@ -47,7 +47,7 @@
"content": { "content": {
"$1532735824654:example.org": { "$1532735824654:example.org": {
"m.read": { "m.read": {
"@bob:kde.org": { "@bob:example.com": {
"ts": 1436451550453 "ts": 1436451550453
} }
} }
@@ -67,18 +67,6 @@
}, },
"type": "m.receipt" "type": "m.receipt"
}, },
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@tim2:example.com": {
"ts": 1436451550454
}
}
}
},
"type": "m.receipt"
},
{ {
"content": { "content": {
"$1532735824654:example.org": { "$1532735824654:example.org": {
@@ -148,22 +136,6 @@
"age": 1234 "age": 1234
} }
}, },
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Bob",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "bob:kde.org",
"state_key": "@bob:kde.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{ {
"content": { "content": {
"displayname": "Look\nat\nme\nI\nput\nnewlines\nin\nmy\ndisplay name", "displayname": "Look\nat\nme\nI\nput\nnewlines\nin\nmy\ndisplay name",
@@ -184,7 +156,7 @@
"summary": { "summary": {
"m.heroes": [ "m.heroes": [
"@alice:example.com", "@alice:example.com",
"@bob:kde.org" "@bob:example.com"
], ],
"m.invited_member_count": 0, "m.invited_member_count": 0,
"m.joined_member_count": 2 "m.joined_member_count": 2

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "https://matrix.to/#/@alice:example.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "mxc://example.org/SEsfnsuifSDFSSEF",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "testhttps://kde.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -37,59 +37,16 @@
"events": [ "events": [
{ {
"content": { "content": {
"displayname": "Example", "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"membership": "join" "displayname": "Alice Margatroid",
"membership": "join",
"reason": "Looking for support"
}, },
"event_id": "$143273582443PhrSn:example.org", "event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653, "origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org", "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org", "sender": "@example:example.org",
"state_key": "@example:example.org", "state_key": "@alice:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"displayname": "Bob",
"membership": "join"
},
"event_id": "$143273blorb3PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@bob:kde.org",
"state_key": "@bob:kde.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"displayname": "Invited",
"membership": "invite"
},
"event_id": "$asdfpj443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@invited:example.com",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"displayname": "Banned",
"membership": "ban"
},
"event_id": "$asdfpj443PhrSnasfd:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@banned:example.com",
"state_key": "@banned:example.com",
"type": "m.room.member", "type": "m.room.member",
"unsigned": { "unsigned": {
"age": 1234 "age": 1234
@@ -102,7 +59,7 @@
"@alice:example.com", "@alice:example.com",
"@bob:example.com" "@bob:example.com"
], ],
"m.invited_member_count": 1, "m.invited_member_count": 0,
"m.joined_member_count": 2 "m.joined_member_count": 2
}, },
"timeline": { "timeline": {

View File

@@ -130,23 +130,7 @@
"origin_server_ts": 1432735824653, "origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org", "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org", "sender": "@example:example.org",
"state_key": "@alice:matrix.org", "state_key": "@alice:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Bob",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "bob:example.org",
"state_key": "@bob:example.org",
"type": "m.room.member", "type": "m.room.member",
"unsigned": { "unsigned": {
"age": 1234 "age": 1234

View File

@@ -51,21 +51,6 @@
"unsigned": { "unsigned": {
"age": 1234 "age": 1234
} }
},
{
"content": {
"displayname": "Example",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@example:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
} }
] ]
}, },

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "https://kde.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "www.example.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,16 @@
{
"content": {
"body": "[Rich Link](https://kde.org)",
"format": "org.matrix.custom.html",
"formatted_body": "<a href=\"https://kde.org\">Rich Link</a>",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -130,7 +130,7 @@ void DelegateSizeHelperTest::equalBreakpoint_data()
} }
/** /**
* We expect a default return except in the case where the two percentages are * We expect a default return except in the case where the the two percentages are
* equal as that case can be calculated without dividing by zero. * equal as that case can be calculated without dividing by zero.
*/ */
void DelegateSizeHelperTest::equalBreakpoint() void DelegateSizeHelperTest::equalBreakpoint()

View File

@@ -11,9 +11,8 @@
#include <Quotient/connection.h> #include <Quotient/connection.h>
#include <Quotient/quotient_common.h> #include <Quotient/quotient_common.h>
#include <Quotient/syncdata.h> #include <Quotient/syncdata.h>
#include <qcbormap.h>
#include <qtestcase.h>
#include "enums/delegatetype.h"
#include "linkpreviewer.h" #include "linkpreviewer.h"
#include "models/reactionmodel.h" #include "models/reactionmodel.h"
#include "neochatroom.h" #include "neochatroom.h"
@@ -30,10 +29,21 @@ class EventHandlerTest : public QObject
private: private:
Connection *connection = nullptr; Connection *connection = nullptr;
TestUtils::TestRoom *room = nullptr; TestUtils::TestRoom *room = nullptr;
EventHandler eventHandler;
EventHandler emptyHandler;
EventHandler noEventHandler;
private Q_SLOTS: private Q_SLOTS:
void initTestCase(); void initTestCase();
void nullSetEvent();
void eventId();
void nullEventId();
void delegateType_data();
void delegateType();
void nullDelegateType();
void author();
void nullAuthor();
void authorDisplayName(); void authorDisplayName();
void nullAuthorDisplayName(); void nullAuthorDisplayName();
void singleLineSidplayName(); void singleLineSidplayName();
@@ -41,6 +51,7 @@ private Q_SLOTS:
void time(); void time();
void nullTime(); void nullTime();
void timeString(); void timeString();
void nullTimeString();
void highlighted(); void highlighted();
void nullHighlighted(); void nullHighlighted();
void hidden(); void hidden();
@@ -51,157 +62,261 @@ private Q_SLOTS:
void genericBody(); void genericBody();
void nullGenericBody(); void nullGenericBody();
void markdownBody(); void markdownBody();
void markdownBodyReply();
void subtitle(); void subtitle();
void nullSubtitle(); void nullSubtitle();
void mediaInfo(); void mediaInfo();
void nullMediaInfo(); void nullMediaInfo();
void hasReply();
void nullHasReply();
void replyId();
void nullReplyId();
void replyDelegateType();
void nullReplyDelegateType();
void replyAuthor(); void replyAuthor();
void nullReplyAuthor(); void nullReplyAuthor();
void replyBody();
void nullReplyBody();
void replyMediaInfo();
void nullReplyMediaInfo();
void thread();
void nullThread();
void location(); void location();
void nullLocation(); void nullLocation();
void readMarkers();
void nullReadMarkers();
void cleanup();
}; };
void EventHandlerTest::initTestCase() void EventHandlerTest::initTestCase()
{ {
connection = Connection::makeMockConnection(u"@bob:kde.org"_s); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-eventhandler-sync.json"_s); room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-eventhandler-sync.json"));
eventHandler.setRoom(room);
noEventHandler.setRoom(room);
}
void EventHandlerTest::nullSetEvent()
{
QTest::ignoreMessage(QtWarningMsg, "cannot setEvent when m_room is set to nullptr.");
emptyHandler.setEvent(room->messageEvents().at(0).get());
}
void EventHandlerTest::eventId()
{
eventHandler.setEvent(room->messageEvents().at(0).get());
QCOMPARE(eventHandler.getId(), QStringLiteral("$153456789:example.org"));
}
void EventHandlerTest::nullEventId()
{
QTest::ignoreMessage(QtWarningMsg, "getId called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getId(), QString());
}
void EventHandlerTest::delegateType_data()
{
QTest::addColumn<int>("eventNum");
QTest::addColumn<DelegateType::Type>("delegateType");
QTest::newRow("message") << 0 << DelegateType::Message;
QTest::newRow("state") << 1 << DelegateType::State;
QTest::newRow("message 2") << 2 << DelegateType::Message;
QTest::newRow("reaction") << 3 << DelegateType::Other;
QTest::newRow("video") << 4 << DelegateType::Video;
QTest::newRow("location") << 7 << DelegateType::Location;
}
void EventHandlerTest::delegateType()
{
QFETCH(int, eventNum);
QFETCH(DelegateType::Type, delegateType);
eventHandler.setEvent(room->messageEvents().at(eventNum).get());
QCOMPARE(eventHandler.getDelegateType(), delegateType);
}
void EventHandlerTest::nullDelegateType()
{
QTest::ignoreMessage(QtWarningMsg, "getDelegateType called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getDelegateType(), DelegateType::Other);
}
void EventHandlerTest::author()
{
auto event = room->messageEvents().at(0).get();
auto author = room->user(event->senderId());
eventHandler.setEvent(event);
auto eventHandlerAuthor = eventHandler.getAuthor();
QCOMPARE(eventHandlerAuthor["isLocalUser"_ls], author->id() == room->localUser()->id());
QCOMPARE(eventHandlerAuthor["id"_ls], author->id());
QCOMPARE(eventHandlerAuthor["displayName"_ls], author->displayname(room));
QCOMPARE(eventHandlerAuthor["avatarSource"_ls], room->avatarForMember(author));
QCOMPARE(eventHandlerAuthor["avatarMediaId"_ls], author->avatarMediaId(room));
QCOMPARE(eventHandlerAuthor["color"_ls], Utils::getUserColor(author->hueF()));
QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(author));
}
void EventHandlerTest::nullAuthor()
{
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getAuthor(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
QCOMPARE(noEventHandler.getAuthor(), room->getUser(nullptr));
} }
void EventHandlerTest::authorDisplayName() void EventHandlerTest::authorDisplayName()
{ {
QCOMPARE(EventHandler::authorDisplayName(room, room->messageEvents().at(1).get()), u"before"_s); auto event = room->messageEvents().at(1).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.getAuthorDisplayName(), QStringLiteral("before"));
} }
void EventHandlerTest::nullAuthorDisplayName() void EventHandlerTest::nullAuthorDisplayName()
{ {
QTest::ignoreMessage(QtWarningMsg, "authorDisplayName called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_room set to nullptr.");
QCOMPARE(EventHandler::authorDisplayName(nullptr, nullptr), QString()); QCOMPARE(emptyHandler.getAuthorDisplayName(), QString());
QTest::ignoreMessage(QtWarningMsg, "authorDisplayName called with event set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_event set to nullptr.");
QCOMPARE(EventHandler::authorDisplayName(room, nullptr), QString()); QCOMPARE(noEventHandler.getAuthorDisplayName(), QString());
} }
void EventHandlerTest::singleLineSidplayName() void EventHandlerTest::singleLineSidplayName()
{ {
QCOMPARE(EventHandler::singleLineAuthorDisplayname(room, room->messageEvents().at(11).get()), "Look at me I put newlines in my display name"_L1); auto event = room->messageEvents().at(11).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.singleLineAuthorDisplayname(), QStringLiteral("Look at me I put newlines in my display name"));
} }
void EventHandlerTest::nullSingleLineDisplayName() void EventHandlerTest::nullSingleLineDisplayName()
{ {
QTest::ignoreMessage(QtWarningMsg, "singleLineAuthorDisplayname called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_room set to nullptr.");
QCOMPARE(EventHandler::singleLineAuthorDisplayname(nullptr, nullptr), QString()); QCOMPARE(emptyHandler.singleLineAuthorDisplayname(), QString());
QTest::ignoreMessage(QtWarningMsg, "singleLineAuthorDisplayname called with event set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_event set to nullptr.");
QCOMPARE(EventHandler::singleLineAuthorDisplayname(room, nullptr), QString()); QCOMPARE(noEventHandler.singleLineAuthorDisplayname(), QString());
} }
void EventHandlerTest::time() void EventHandlerTest::time()
{ {
const auto event = room->messageEvents().at(0).get(); auto event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(EventHandler::time(room, event), QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC))); QCOMPARE(eventHandler.getTime(), QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC));
QCOMPARE(eventHandler.getTime(true, QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC)), QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC));
const auto txID = room->postJson("m.room.message"_L1, event->fullJson());
QCOMPARE(room->pendingEvents().size(), 1);
const auto pendingIt = room->findPendingEvent(txID);
QCOMPARE(EventHandler::time(room, pendingIt->event(), true), pendingIt->lastUpdated());
room->discardMessage(txID);
QCOMPARE(room->pendingEvents().size(), 0);
} }
void EventHandlerTest::nullTime() void EventHandlerTest::nullTime()
{ {
QTest::ignoreMessage(QtWarningMsg, "time called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getTime called with m_event set to nullptr.");
QCOMPARE(EventHandler::time(nullptr, nullptr), QDateTime()); QCOMPARE(noEventHandler.getTime(), QDateTime());
QTest::ignoreMessage(QtWarningMsg, "time called with event set to nullptr."); eventHandler.setEvent(room->messageEvents().at(0).get());
QCOMPARE(EventHandler::time(room, nullptr), QDateTime()); QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
QCOMPARE(eventHandler.getTime(true), QDateTime());
} }
void EventHandlerTest::timeString() void EventHandlerTest::timeString()
{ {
const auto event = room->messageEvents().at(0).get(); auto event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
KFormat format; KFormat format;
QCOMPARE(EventHandler::timeString(room, event, false), QCOMPARE(eventHandler.getTimeString(false),
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().time(), QLocale::ShortFormat)); QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toLocalTime().time(), QLocale::ShortFormat));
QCOMPARE(EventHandler::timeString(room, event, true), QCOMPARE(eventHandler.getTimeString(true),
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().date(), QLocale::ShortFormat)); format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toLocalTime().date(), QLocale::ShortFormat));
QCOMPARE(EventHandler::timeString(room, event, u"hh:mm"_s), QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toString(u"hh:mm"_s)); QCOMPARE(eventHandler.getTimeString(false, QLocale::ShortFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::ShortFormat));
QCOMPARE(eventHandler.getTimeString(true, QLocale::ShortFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::ShortFormat));
QCOMPARE(eventHandler.getTimeString(false, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::LongFormat));
QCOMPARE(eventHandler.getTimeString(true, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat));
}
const auto txID = room->postJson("m.room.message"_L1, event->fullJson()); void EventHandlerTest::nullTimeString()
QCOMPARE(room->pendingEvents().size(), 1); {
const auto pendingIt = room->findPendingEvent(txID); QTest::ignoreMessage(QtWarningMsg, "getTimeString called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getTimeString(false), QString());
QCOMPARE(EventHandler::timeString(room, pendingIt->event(), false, QLocale::ShortFormat, true), eventHandler.setEvent(room->messageEvents().at(0).get());
QLocale().toString(pendingIt->lastUpdated().toLocalTime().time(), QLocale::ShortFormat)); QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
QCOMPARE(EventHandler::timeString(room, pendingIt->event(), true, QLocale::ShortFormat, true), QCOMPARE(eventHandler.getTimeString(false, QLocale::ShortFormat, true), QString());
format.formatRelativeDate(pendingIt->lastUpdated().toLocalTime().date(), QLocale::ShortFormat));
QCOMPARE(EventHandler::timeString(room, pendingIt->event(), false, QLocale::LongFormat, true),
QLocale().toString(pendingIt->lastUpdated().toLocalTime().time(), QLocale::LongFormat));
QCOMPARE(EventHandler::timeString(room, pendingIt->event(), true, QLocale::LongFormat, true),
format.formatRelativeDate(pendingIt->lastUpdated().toLocalTime().date(), QLocale::LongFormat));
room->discardMessage(txID);
QCOMPARE(room->pendingEvents().size(), 0);
} }
void EventHandlerTest::highlighted() void EventHandlerTest::highlighted()
{ {
QCOMPARE(EventHandler::isHighlighted(room, room->messageEvents().at(2).get()), true); auto event = room->messageEvents().at(2).get();
QCOMPARE(EventHandler::isHighlighted(room, room->messageEvents().at(0).get()), false); eventHandler.setEvent(event);
QCOMPARE(eventHandler.isHighlighted(), true);
event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.isHighlighted(), false);
} }
void EventHandlerTest::nullHighlighted() void EventHandlerTest::nullHighlighted()
{ {
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with m_room set to nullptr.");
QCOMPARE(EventHandler::isHighlighted(nullptr, nullptr), false); QCOMPARE(emptyHandler.isHighlighted(), false);
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with event set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with m_event set to nullptr.");
QCOMPARE(EventHandler::isHighlighted(room, nullptr), false); QCOMPARE(noEventHandler.isHighlighted(), false);
} }
void EventHandlerTest::hidden() void EventHandlerTest::hidden()
{ {
QCOMPARE(EventHandler::isHidden(room, room->messageEvents().at(3).get()), true); auto event = room->messageEvents().at(3).get();
QCOMPARE(EventHandler::isHidden(room, room->messageEvents().at(0).get()), false); eventHandler.setEvent(event);
QCOMPARE(eventHandler.isHidden(), true);
event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.isHidden(), false);
} }
void EventHandlerTest::nullHidden() void EventHandlerTest::nullHidden()
{ {
QTest::ignoreMessage(QtWarningMsg, "isHidden called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "isHidden called with m_room set to nullptr.");
QCOMPARE(EventHandler::isHidden(nullptr, nullptr), false); QCOMPARE(emptyHandler.isHidden(), false);
QTest::ignoreMessage(QtWarningMsg, "isHidden called with event set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "isHidden called with m_event set to nullptr.");
QCOMPARE(EventHandler::isHidden(room, nullptr), false); QCOMPARE(noEventHandler.isHidden(), false);
} }
void EventHandlerTest::body() void EventHandlerTest::body()
{ {
const auto event = room->messageEvents().at(0).get(); auto event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(EventHandler::richBody(room, event), u"<b>This is an example<br>text message</b>"_s); QCOMPARE(eventHandler.getRichBody(), QStringLiteral("<b>This is an example<br>text message</b>"));
QCOMPARE(EventHandler::richBody(room, event, true), u"<b>This is an example text message</b>"_s); QCOMPARE(eventHandler.getRichBody(true), QStringLiteral("<b>This is an example text message</b>"));
QCOMPARE(EventHandler::plainBody(room, event), u"This is an example\ntext message"_s); QCOMPARE(eventHandler.getPlainBody(), QStringLiteral("This is an example\ntext message"));
QCOMPARE(EventHandler::plainBody(room, event, true), u"This is an example text message"_s); QCOMPARE(eventHandler.getPlainBody(true), QStringLiteral("This is an example text message"));
} }
void EventHandlerTest::nullBody() void EventHandlerTest::nullBody()
{ {
QTest::ignoreMessage(QtWarningMsg, "richBody called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getRichBody called with m_event set to nullptr.");
QCOMPARE(EventHandler::richBody(nullptr, nullptr), QString()); QCOMPARE(noEventHandler.getRichBody(), QString());
QTest::ignoreMessage(QtWarningMsg, "richBody called with event set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getPlainBody called with m_event set to nullptr.");
QCOMPARE(EventHandler::richBody(room, nullptr), QString()); QCOMPARE(noEventHandler.getPlainBody(), QString());
QTest::ignoreMessage(QtWarningMsg, "plainBody called with room set to nullptr.");
QCOMPARE(EventHandler::plainBody(nullptr, nullptr), QString());
QTest::ignoreMessage(QtWarningMsg, "plainBody called with event set to nullptr.");
QCOMPARE(EventHandler::plainBody(room, nullptr), QString());
} }
void EventHandlerTest::genericBody_data() void EventHandlerTest::genericBody_data()
@@ -209,11 +324,11 @@ void EventHandlerTest::genericBody_data()
QTest::addColumn<int>("eventNum"); QTest::addColumn<int>("eventNum");
QTest::addColumn<QString>("output"); QTest::addColumn<QString>("output");
QTest::newRow("message") << 0 << u"<a href=\"https://matrix.to/#/@example:example.org\">after</a> sent a message"_s; QTest::newRow("message") << 0 << QStringLiteral("sent a message");
QTest::newRow("member") << 1 << u"<a href=\"https://matrix.to/#/@example:example.org\">after</a> changed their display name and updated their avatar"_s; QTest::newRow("member") << 1 << QStringLiteral("changed their display name and updated their avatar");
QTest::newRow("message 2") << 2 << u"<a href=\"https://matrix.to/#/@example:example.org\">after</a> sent a message"_s; QTest::newRow("message 2") << 2 << QStringLiteral("sent a message");
QTest::newRow("reaction") << 3 << u"Unknown event"_s; QTest::newRow("reaction") << 3 << QStringLiteral("Unknown event");
QTest::newRow("video") << 4 << u"<a href=\"https://matrix.to/#/@example:example.org\">after</a> sent a message"_s; QTest::newRow("video") << 4 << QStringLiteral("sent a message");
} }
void EventHandlerTest::genericBody() void EventHandlerTest::genericBody()
@@ -221,116 +336,333 @@ void EventHandlerTest::genericBody()
QFETCH(int, eventNum); QFETCH(int, eventNum);
QFETCH(QString, output); QFETCH(QString, output);
QCOMPARE(EventHandler::genericBody(room, room->messageEvents().at(eventNum).get()), output); eventHandler.setEvent(room->messageEvents().at(eventNum).get());
QCOMPARE(eventHandler.getGenericBody(), output);
} }
void EventHandlerTest::nullGenericBody() void EventHandlerTest::nullGenericBody()
{ {
QTest::ignoreMessage(QtWarningMsg, "genericBody called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getGenericBody called with m_event set to nullptr.");
QCOMPARE(EventHandler::genericBody(nullptr, nullptr), QString()); QCOMPARE(noEventHandler.getGenericBody(), QString());
QTest::ignoreMessage(QtWarningMsg, "genericBody called with event set to nullptr.");
QCOMPARE(EventHandler::genericBody(room, nullptr), QString());
} }
void EventHandlerTest::markdownBody() void EventHandlerTest::markdownBody()
{ {
QCOMPARE(EventHandler::markdownBody(room->messageEvents().at(0).get()), u"This is an example\ntext message"_s); eventHandler.setEvent(room->messageEvents().at(0).get());
}
void EventHandlerTest::markdownBodyReply() QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("This is an example\ntext message"));
{
QCOMPARE(EventHandler::markdownBody(room->messageEvents().at(5).get()), u"reply"_s);
} }
void EventHandlerTest::subtitle() void EventHandlerTest::subtitle()
{ {
QCOMPARE(EventHandler::subtitleText(room, room->messageEvents().at(0).get()), u"after: This is an example text message"_s); auto event = room->messageEvents().at(0).get();
QCOMPARE(EventHandler::subtitleText(room, room->messageEvents().at(2).get()), eventHandler.setEvent(event);
u"after: This is a highlight @bob:kde.org and this is a link https://kde.org"_s);
QCOMPARE(eventHandler.subtitleText(), QStringLiteral("after: This is an example text message"));
event = room->messageEvents().at(2).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.subtitleText(), QStringLiteral("after: This is a highlight @bob:kde.org and this is a link https://kde.org"));
} }
void EventHandlerTest::nullSubtitle() void EventHandlerTest::nullSubtitle()
{ {
QTest::ignoreMessage(QtWarningMsg, "subtitleText called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "subtitleText called with m_event set to nullptr.");
QCOMPARE(EventHandler::subtitleText(nullptr, nullptr), QString()); QCOMPARE(noEventHandler.subtitleText(), QString());
QTest::ignoreMessage(QtWarningMsg, "subtitleText called with event set to nullptr.");
QCOMPARE(EventHandler::subtitleText(room, nullptr), QString());
} }
void EventHandlerTest::mediaInfo() void EventHandlerTest::mediaInfo()
{ {
auto event = room->messageEvents().at(4).get(); auto event = room->messageEvents().at(4).get();
auto mediaInfo = EventHandler::mediaInfo(room, event); eventHandler.setEvent(event);
auto thumbnailInfo = mediaInfo["tempInfo"_L1].toMap();
QCOMPARE(mediaInfo["source"_L1], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/1234567"_L1))); auto mediaInfo = eventHandler.getMediaInfo();
QCOMPARE(mediaInfo["mimeType"_L1], u"video/mp4"_s); auto thumbnailInfo = mediaInfo["tempInfo"_ls].toMap();
QCOMPARE(mediaInfo["mimeIcon"_L1], u"video-mp4"_s);
QCOMPARE(mediaInfo["size"_L1], 62650636); QCOMPARE(mediaInfo["source"_ls], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/1234567"_ls)));
QCOMPARE(mediaInfo["duration"_L1], 10); QCOMPARE(mediaInfo["mimeType"_ls], QStringLiteral("video/mp4"));
QCOMPARE(mediaInfo["width"_L1], 1920); QCOMPARE(mediaInfo["mimeIcon"_ls], QStringLiteral("video-mp4"));
QCOMPARE(mediaInfo["height"_L1], 1080); QCOMPARE(mediaInfo["size"_ls], 62650636);
QCOMPARE(thumbnailInfo["source"_L1], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/2234567"_L1))); QCOMPARE(mediaInfo["duration"_ls], 10);
QCOMPARE(thumbnailInfo["mimeType"_L1], u"image/jpeg"_s); QCOMPARE(mediaInfo["width"_ls], 1920);
QCOMPARE(thumbnailInfo["mimeIcon"_L1], u"image-jpeg"_s); QCOMPARE(mediaInfo["height"_ls], 1080);
QCOMPARE(thumbnailInfo["size"_L1], 382249); QCOMPARE(thumbnailInfo["source"_ls], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/2234567"_ls)));
QCOMPARE(thumbnailInfo["width"_L1], 800); QCOMPARE(thumbnailInfo["mimeType"_ls], QStringLiteral("image/jpeg"));
QCOMPARE(thumbnailInfo["height"_L1], 450); QCOMPARE(thumbnailInfo["mimeIcon"_ls], QStringLiteral("image-jpeg"));
QCOMPARE(thumbnailInfo["size"_ls], 382249);
QCOMPARE(thumbnailInfo["width"_ls], 800);
QCOMPARE(thumbnailInfo["height"_ls], 450);
} }
void EventHandlerTest::nullMediaInfo() void EventHandlerTest::nullMediaInfo()
{ {
QTest::ignoreMessage(QtWarningMsg, "mediaInfo called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getMediaInfo called with m_room set to nullptr.");
QCOMPARE(EventHandler::mediaInfo(nullptr, nullptr), QVariantMap()); QCOMPARE(emptyHandler.getMediaInfo(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "mediaInfo called with event set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getMediaInfo called with m_event set to nullptr.");
QCOMPARE(EventHandler::mediaInfo(room, nullptr), QVariantMap()); QCOMPARE(noEventHandler.getMediaInfo(), QVariantMap());
}
void EventHandlerTest::hasReply()
{
auto event = room->messageEvents().at(5).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.hasReply(), true);
event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.hasReply(), false);
}
void EventHandlerTest::nullHasReply()
{
QTest::ignoreMessage(QtWarningMsg, "hasReply called with m_event set to nullptr.");
QCOMPARE(noEventHandler.hasReply(), false);
}
void EventHandlerTest::replyId()
{
auto event = room->messageEvents().at(5).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$153456789:example.org"));
event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.getReplyId(), QStringLiteral(""));
}
void EventHandlerTest::nullReplyId()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyId called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyId(), QString());
}
void EventHandlerTest::replyDelegateType()
{
auto event = room->messageEvents().at(5).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.getReplyDelegateType(), DelegateType::Message);
event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.getReplyDelegateType(), DelegateType::Other);
}
void EventHandlerTest::nullReplyDelegateType()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyDelegateType called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReplyDelegateType(), DelegateType::Other);
QTest::ignoreMessage(QtWarningMsg, "getReplyDelegateType called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyDelegateType(), DelegateType::Other);
} }
void EventHandlerTest::replyAuthor() void EventHandlerTest::replyAuthor()
{ {
auto event = room->messageEvents().at(5).get();
auto replyEvent = room->messageEvents().at(0).get(); auto replyEvent = room->messageEvents().at(0).get();
auto replyAuthor = room->member(replyEvent->senderId()); auto replyAuthor = room->user(replyEvent->senderId());
auto eventHandlerReplyAuthor = EventHandler::replyAuthor(room, room->messageEvents().at(5).get()); eventHandler.setEvent(event);
QCOMPARE(eventHandlerReplyAuthor.isLocalMember(), replyAuthor.id() == room->localMember().id()); auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
QCOMPARE(eventHandlerReplyAuthor.id(), replyAuthor.id());
QCOMPARE(eventHandlerReplyAuthor.displayName(), replyAuthor.displayName());
QCOMPARE(eventHandlerReplyAuthor.avatarUrl(), replyAuthor.avatarUrl());
QCOMPARE(eventHandlerReplyAuthor.avatarMediaId(), replyAuthor.avatarMediaId());
QCOMPARE(eventHandlerReplyAuthor.color(), replyAuthor.color());
QCOMPARE(EventHandler::replyAuthor(room, room->messageEvents().at(0).get()), RoomMember()); QCOMPARE(eventHandlerReplyAuthor["isLocalUser"_ls], replyAuthor->id() == room->localUser()->id());
QCOMPARE(eventHandlerReplyAuthor["id"_ls], replyAuthor->id());
QCOMPARE(eventHandlerReplyAuthor["displayName"_ls], replyAuthor->displayname(room));
QCOMPARE(eventHandlerReplyAuthor["avatarSource"_ls], room->avatarForMember(replyAuthor));
QCOMPARE(eventHandlerReplyAuthor["avatarMediaId"_ls], replyAuthor->avatarMediaId(room));
QCOMPARE(eventHandlerReplyAuthor["color"_ls], Utils::getUserColor(replyAuthor->hueF()));
QCOMPARE(eventHandlerReplyAuthor["object"_ls], QVariant::fromValue(replyAuthor));
event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.getReplyAuthor(), room->getUser(nullptr));
} }
void EventHandlerTest::nullReplyAuthor() void EventHandlerTest::nullReplyAuthor()
{ {
QTest::ignoreMessage(QtWarningMsg, "replyAuthor called with room set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
QCOMPARE(EventHandler::replyAuthor(nullptr, nullptr), RoomMember()); QCOMPARE(emptyHandler.getReplyAuthor(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "replyAuthor called with event set to nullptr. Returning empty user."); QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_event set to nullptr. Returning empty user.");
QCOMPARE(EventHandler::replyAuthor(room, nullptr), RoomMember()); QCOMPARE(noEventHandler.getReplyAuthor(), room->getUser(nullptr));
}
void EventHandlerTest::replyBody()
{
auto event = room->messageEvents().at(5).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.getReplyRichBody(), QStringLiteral("<b>This is an example<br>text message</b>"));
QCOMPARE(eventHandler.getReplyRichBody(true), QStringLiteral("<b>This is an example text message</b>"));
QCOMPARE(eventHandler.getReplyPlainBody(), QStringLiteral("This is an example\ntext message"));
QCOMPARE(eventHandler.getReplyPlainBody(true), QStringLiteral("This is an example text message"));
}
void EventHandlerTest::nullReplyBody()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyRichBody called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyRichBody(), QString());
QTest::ignoreMessage(QtWarningMsg, "getReplyPlainBody called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyPlainBody(), QString());
}
void EventHandlerTest::replyMediaInfo()
{
auto event = room->messageEvents().at(6).get();
auto replyEvent = room->messageEvents().at(4).get();
eventHandler.setEvent(event);
auto mediaInfo = eventHandler.getReplyMediaInfo();
auto thumbnailInfo = mediaInfo["tempInfo"_ls].toMap();
QCOMPARE(mediaInfo["source"_ls], room->makeMediaUrl(replyEvent->id(), QUrl("mxc://kde.org/1234567"_ls)));
QCOMPARE(mediaInfo["mimeType"_ls], QStringLiteral("video/mp4"));
QCOMPARE(mediaInfo["mimeIcon"_ls], QStringLiteral("video-mp4"));
QCOMPARE(mediaInfo["size"_ls], 62650636);
QCOMPARE(mediaInfo["duration"_ls], 10);
QCOMPARE(mediaInfo["width"_ls], 1920);
QCOMPARE(mediaInfo["height"_ls], 1080);
QCOMPARE(thumbnailInfo["source"_ls], room->makeMediaUrl(replyEvent->id(), QUrl("mxc://kde.org/2234567"_ls)));
QCOMPARE(thumbnailInfo["mimeType"_ls], QStringLiteral("image/jpeg"));
QCOMPARE(thumbnailInfo["mimeIcon"_ls], QStringLiteral("image-jpeg"));
QCOMPARE(thumbnailInfo["size"_ls], 382249);
QCOMPARE(thumbnailInfo["width"_ls], 800);
QCOMPARE(thumbnailInfo["height"_ls], 450);
}
void EventHandlerTest::nullReplyMediaInfo()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyMediaInfo called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReplyMediaInfo(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "getReplyMediaInfo called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyMediaInfo(), QVariantMap());
}
void EventHandlerTest::thread()
{
auto event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.isThreaded(), false);
QCOMPARE(eventHandler.threadRoot(), QString());
event = room->messageEvents().at(9).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.isThreaded(), true);
QCOMPARE(eventHandler.threadRoot(), QStringLiteral("$threadroot:example.org"));
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$threadroot:example.org"));
event = room->messageEvents().at(10).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.isThreaded(), true);
QCOMPARE(eventHandler.threadRoot(), QStringLiteral("$threadroot:example.org"));
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$threadmessage1:example.org"));
}
void EventHandlerTest::nullThread()
{
QTest::ignoreMessage(QtWarningMsg, "isThreaded called with m_event set to nullptr.");
QCOMPARE(emptyHandler.isThreaded(), false);
QTest::ignoreMessage(QtWarningMsg, "threadRoot called with m_event set to nullptr.");
QCOMPARE(noEventHandler.threadRoot(), QString());
} }
void EventHandlerTest::location() void EventHandlerTest::location()
{ {
QCOMPARE(EventHandler::latitude(room->messageEvents().at(7).get()), u"51.7035"_s.toFloat()); auto event = room->messageEvents().at(7).get();
QCOMPARE(EventHandler::longitude(room->messageEvents().at(7).get()), u"-1.14394"_s.toFloat()); eventHandler.setEvent(event);
QCOMPARE(EventHandler::locationAssetType(room->messageEvents().at(7).get()), u"m.pin"_s);
QCOMPARE(eventHandler.getLatitude(), QStringLiteral("51.7035").toFloat());
QCOMPARE(eventHandler.getLongitude(), QStringLiteral("-1.14394").toFloat());
QCOMPARE(eventHandler.getLocationAssetType(), QStringLiteral("m.pin"));
} }
void EventHandlerTest::nullLocation() void EventHandlerTest::nullLocation()
{ {
QTest::ignoreMessage(QtWarningMsg, "latitude called with event set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getLatitude called with m_event set to nullptr.");
QCOMPARE(EventHandler::latitude(nullptr), -100.0); QCOMPARE(emptyHandler.getLatitude(), -100.0);
QTest::ignoreMessage(QtWarningMsg, "longitude called with event set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getLongitude called with m_event set to nullptr.");
QCOMPARE(EventHandler::longitude(nullptr), -200.0); QCOMPARE(emptyHandler.getLongitude(), -200.0);
QTest::ignoreMessage(QtWarningMsg, "locationAssetType called with event set to nullptr."); QTest::ignoreMessage(QtWarningMsg, "getLocationAssetType called with m_event set to nullptr.");
QCOMPARE(EventHandler::locationAssetType(nullptr), QString()); QCOMPARE(emptyHandler.getLocationAssetType(), QString());
}
void EventHandlerTest::readMarkers()
{
auto event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.hasReadMarkers(), true);
auto readMarkers = eventHandler.getReadMarkers();
QCOMPARE(readMarkers.size(), 1);
QCOMPARE(readMarkers[0].toMap()["id"_ls], QStringLiteral("@alice:matrix.org"));
QCOMPARE(eventHandler.getNumberExcessReadMarkers(), QString());
QCOMPARE(eventHandler.getReadMarkersString(), QStringLiteral("1 user: @alice:matrix.org"));
event = room->messageEvents().at(2).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.hasReadMarkers(), true);
readMarkers = eventHandler.getReadMarkers();
QCOMPARE(readMarkers.size(), 5);
QCOMPARE(eventHandler.getNumberExcessReadMarkers(), QStringLiteral("+ 1"));
// There are no guarantees on the order of the users it will be different every time so don't match the whole string.
QCOMPARE(eventHandler.getReadMarkersString().startsWith(QStringLiteral("6 users:")), true);
}
void EventHandlerTest::nullReadMarkers()
{
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.hasReadMarkers(), false);
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReadMarkers(), QVariantList());
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getNumberExcessReadMarkers(), QString());
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReadMarkersString(), QString());
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.hasReadMarkers(), false);
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReadMarkers(), QVariantList());
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getNumberExcessReadMarkers(), QString());
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReadMarkersString(), QString());
}
void EventHandlerTest::cleanup()
{
eventHandler.setEvent(nullptr);
} }
QTEST_MAIN(EventHandlerTest) QTEST_MAIN(EventHandlerTest)

View File

@@ -6,11 +6,12 @@
#include "linkpreviewer.h" #include "linkpreviewer.h"
#include "utils.h"
#include <Quotient/events/roommessageevent.h> #include <Quotient/events/roommessageevent.h>
#include <Quotient/quotient_common.h> #include <Quotient/quotient_common.h>
#include <Quotient/syncdata.h> #include <Quotient/syncdata.h>
#include "utils.h"
#include "testutils.h" #include "testutils.h"
using namespace Quotient; using namespace Quotient;
@@ -29,74 +30,74 @@ private Q_SLOTS:
void linkPreviewsMatch_data(); void linkPreviewsMatch_data();
void linkPreviewsMatch(); void linkPreviewsMatch();
void multipleLinkPreviewsMatch_data();
void multipleLinkPreviewsMatch();
void linkPreviewsReject_data(); void linkPreviewsReject_data();
void linkPreviewsReject(); void linkPreviewsReject();
void editedLink();
}; };
void LinkPreviewerTest::initTestCase() void LinkPreviewerTest::initTestCase()
{ {
connection = Connection::makeMockConnection(u"@bob:example.org"_s); connection = Connection::makeMockConnection(QStringLiteral("@bob:example.org"));
room = new TestUtils::TestRoom(connection, u"!test:example.org"_s); room = new TestUtils::TestRoom(connection, QStringLiteral("!test:example.org"));
} }
void LinkPreviewerTest::linkPreviewsMatch_data() void LinkPreviewerTest::linkPreviewsMatch_data()
{ {
QTest::addColumn<QString>("inputString"); QTest::addColumn<QString>("eventSource");
QTest::addColumn<QUrl>("testOutputLink"); QTest::addColumn<QUrl>("testOutputLink");
QTest::newRow("plainHttps") << u"https://kde.org"_s << QUrl(u"https://kde.org"_s); QTest::newRow("plainHttps") << QStringLiteral("test-validplainlink-event.json") << QUrl("https://kde.org"_ls);
QTest::newRow("richHttps") << u"<a href=\"https://kde.org\">Rich Link</a>"_s << QUrl(u"https://kde.org"_s); QTest::newRow("richHttps") << QStringLiteral("test-validrichlink-event.json") << QUrl("https://kde.org"_ls);
QTest::newRow("richHttpsLinkDescription") << u"<a href=\"https://kde.org\">https://kde.org</a>"_s << QUrl(u"https://kde.org"_s); QTest::newRow("plainWww") << QStringLiteral("test-validplainwwwlink-event.json") << QUrl("www.example.org"_ls);
QTest::newRow("multipleHttps") << QStringLiteral("test-multiplelink-event.json") << QUrl("www.example.org"_ls);
} }
void LinkPreviewerTest::linkPreviewsMatch() void LinkPreviewerTest::linkPreviewsMatch()
{ {
QFETCH(QString, inputString); QFETCH(QString, eventSource);
QFETCH(QUrl, testOutputLink); QFETCH(QUrl, testOutputLink);
auto link = LinkPreviewer::linkPreviews(inputString)[0]; auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
auto linkPreviewer = LinkPreviewer(room, event.get());
QCOMPARE(link, testOutputLink); QCOMPARE(linkPreviewer.empty(), false);
} QCOMPARE(linkPreviewer.url(), testOutputLink);
void LinkPreviewerTest::multipleLinkPreviewsMatch_data()
{
QTest::addColumn<QString>("inputString");
QTest::addColumn<QList<QUrl>>("testOutputLinks");
QTest::newRow("multipleHttps") << u"www.example.org https://kde.org"_s << QList{QUrl(u"www.example.org"_s), QUrl(u"https://kde.org"_s)};
QTest::newRow("multipleHttps1Invalid") << u"www.example.org mxc://example.org/SEsfnsuifSDFSSEF"_s << QList{QUrl(u"www.example.org"_s)};
}
void LinkPreviewerTest::multipleLinkPreviewsMatch()
{
QFETCH(QString, inputString);
QFETCH(QList<QUrl>, testOutputLinks);
auto links = LinkPreviewer::linkPreviews(inputString);
QCOMPARE(links, testOutputLinks);
} }
void LinkPreviewerTest::linkPreviewsReject_data() void LinkPreviewerTest::linkPreviewsReject_data()
{ {
QTest::addColumn<QString>("inputString"); QTest::addColumn<QString>("eventSource");
QTest::newRow("mxc") << u"mxc://example.org/SEsfnsuifSDFSSEF"_s; QTest::newRow("mxc") << QStringLiteral("test-invalidmxclink-event.json");
QTest::newRow("matrixTo") << u"https://matrix.to/#/@alice:example.org"_s; QTest::newRow("matrixTo") << QStringLiteral("test-invalidmatrixtolink-event.json");
QTest::newRow("noSpace") << u"testhttps://kde.org"_s; QTest::newRow("noSpace") << QStringLiteral("test-invalidnospacelink-event.json");
} }
void LinkPreviewerTest::linkPreviewsReject() void LinkPreviewerTest::linkPreviewsReject()
{ {
QFETCH(QString, inputString); QFETCH(QString, eventSource);
auto links = LinkPreviewer::linkPreviews(inputString); auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
auto linkPreviewer = LinkPreviewer(room, event.get());
QCOMPARE(links.empty(), true); QCOMPARE(linkPreviewer.empty(), true);
QCOMPARE(linkPreviewer.url(), QUrl());
}
void LinkPreviewerTest::editedLink()
{
room->syncNewEvents(QStringLiteral("test-linkpreviewerintial-sync.json"));
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
auto linkPreviewer = LinkPreviewer(room, event);
QCOMPARE(linkPreviewer.empty(), false);
QCOMPARE(linkPreviewer.url(), QUrl("https://kde.org"_ls));
room->syncNewEvents(QStringLiteral("test-linkpreviewerreplace-sync.json"));
QCOMPARE(linkPreviewer.empty(), true);
QCOMPARE(linkPreviewer.url(), QUrl());
} }
QTEST_MAIN(LinkPreviewerTest) QTEST_MAIN(LinkPreviewerTest)

View File

@@ -1,61 +0,0 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QObject>
#include <QSignalSpy>
#include <QTest>
#include <Quotient/connection.h>
#include <Quotient/quotient_common.h>
#include <Quotient/roommember.h>
#include <Quotient/syncdata.h>
#include "models/messagecontentmodel.h"
#include "testutils.h"
using namespace Quotient;
using namespace Qt::Literals::StringLiterals;
class MessageContentModelTest : public QObject
{
Q_OBJECT
private:
Connection *connection = nullptr;
private Q_SLOTS:
void initTestCase();
void missingEvent();
};
void MessageContentModelTest::initTestCase()
{
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
}
void MessageContentModelTest::missingEvent()
{
auto room = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
auto model1 = MessageContentModel(room, u"$153456789:example.org"_s);
QCOMPARE(model1.rowCount(), 1);
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading"_s);
auto model2 = MessageContentModel(room, u"$153456789:example.org"_s, true);
QCOMPARE(model2.rowCount(), 1);
QCOMPARE(model2.data(model2.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
QCOMPARE(model2.data(model2.index(0), MessageContentModel::DisplayRole), u"Loading reply"_s);
room->syncNewEvents(u"test-min-sync.json"_s);
QCOMPARE(model1.rowCount(), 2);
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Author);
QCOMPARE(model1.data(model1.index(1), MessageContentModel::ComponentTypeRole), MessageComponentType::Text);
QCOMPARE(model1.data(model1.index(1), MessageContentModel::DisplayRole), u"<b>This is an example<br>text message</b>"_s);
}
QTEST_MAIN(MessageContentModelTest)
#include "messagecontentmodeltest.moc"

View File

@@ -10,20 +10,20 @@
#include <Quotient/syncdata.h> #include <Quotient/syncdata.h>
#include "enums/delegatetype.h" #include "enums/delegatetype.h"
#include "models/timelinemessagemodel.h" #include "models/messageeventmodel.h"
#include "neochatroom.h" #include "neochatroom.h"
#include "testutils.h" #include "testutils.h"
using namespace Quotient; using namespace Quotient;
class TimelineMessageModelTest : public QObject class MessageEventModelTest : public QObject
{ {
Q_OBJECT Q_OBJECT
private: private:
Connection *connection = nullptr; Connection *connection = nullptr;
TimelineMessageModel *model = nullptr; MessageEventModel *model = nullptr;
private Q_SLOTS: private Q_SLOTS:
void initTestCase(); void initTestCase();
@@ -40,70 +40,71 @@ private Q_SLOTS:
void cleanup(); void cleanup();
}; };
void TimelineMessageModelTest::initTestCase() void MessageEventModelTest::initTestCase()
{ {
connection = Connection::makeMockConnection(u"@bob:kde.org"_s); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
} }
void TimelineMessageModelTest::init() void MessageEventModelTest::init()
{ {
QCOMPARE(model, nullptr); QCOMPARE(model, nullptr);
model = new TimelineMessageModel; model = new MessageEventModel;
} }
// Make sure that basic empty rooms can be switched without crashing. // Make sure that basic empty rooms can be switched without crashing.
void TimelineMessageModelTest::switchEmptyRoom() void MessageEventModelTest::switchEmptyRoom()
{ {
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s); auto firstRoom = new TestUtils::TestRoom(connection, QStringLiteral("#firstRoom:kde.org"));
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s); auto secondRoom = new TestUtils::TestRoom(connection, QStringLiteral("#secondRoom:kde.org"));
QSignalSpy spy(model, SIGNAL(roomChanged())); QSignalSpy spy(model, SIGNAL(roomChanged()));
QCOMPARE(model->room(), nullptr); QCOMPARE(model->room(), nullptr);
model->setRoom(firstRoom); model->setRoom(firstRoom);
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QCOMPARE(model->room()->id(), u"#firstRoom:kde.org"_s); QCOMPARE(model->room()->id(), QStringLiteral("#firstRoom:kde.org"));
model->setRoom(secondRoom); model->setRoom(secondRoom);
QCOMPARE(spy.count(), 2); QCOMPARE(spy.count(), 2);
QCOMPARE(model->room()->id(), u"#secondRoom:kde.org"_s); QCOMPARE(model->room()->id(), QStringLiteral("#secondRoom:kde.org"));
model->setRoom(nullptr); model->setRoom(nullptr);
QCOMPARE(spy.count(), 3); QCOMPARE(spy.count(), 3);
QCOMPARE(model->room(), nullptr); QCOMPARE(model->room(), nullptr);
} }
// Make sure that rooms with some events can be switched without crashing // Make sure that rooms with some events can be switched without crashing
void TimelineMessageModelTest::switchSyncedRoom() void MessageEventModelTest::switchSyncedRoom()
{ {
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s); auto firstRoom = new TestUtils::TestRoom(connection, QStringLiteral("#firstRoom:kde.org"), QLatin1String("test-messageventmodel-sync.json"));
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s); auto secondRoom = new TestUtils::TestRoom(connection, QStringLiteral("#secondRoom:kde.org"), QLatin1String("test-messageventmodel-sync.json"));
QSignalSpy spy(model, SIGNAL(roomChanged())); QSignalSpy spy(model, SIGNAL(roomChanged()));
QCOMPARE(model->room(), nullptr); QCOMPARE(model->room(), nullptr);
model->setRoom(firstRoom); model->setRoom(firstRoom);
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QCOMPARE(model->room()->id(), u"#firstRoom:kde.org"_s); QCOMPARE(model->room()->id(), QStringLiteral("#firstRoom:kde.org"));
model->setRoom(secondRoom); model->setRoom(secondRoom);
QCOMPARE(spy.count(), 2); QCOMPARE(spy.count(), 2);
QCOMPARE(model->room()->id(), u"#secondRoom:kde.org"_s); QCOMPARE(model->room()->id(), QStringLiteral("#secondRoom:kde.org"));
model->setRoom(nullptr); model->setRoom(nullptr);
QCOMPARE(spy.count(), 3); QCOMPARE(spy.count(), 3);
QCOMPARE(model->room(), nullptr); QCOMPARE(model->room(), nullptr);
} }
void TimelineMessageModelTest::simpleTimeline() void MessageEventModelTest::simpleTimeline()
{ {
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-messageventmodel-sync.json"_s); auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-messageventmodel-sync.json"));
model->setRoom(room); model->setRoom(room);
QCOMPARE(model->rowCount(), 2); QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->data(model->index(0), TimelineMessageModel::DelegateTypeRole), DelegateType::State); QCOMPARE(model->data(model->index(0), MessageEventModel::DelegateTypeRole), DelegateType::State);
QCOMPARE(model->data(model->index(0)), u"changed their display name to Example Changed"_s); QCOMPARE(model->data(model->index(0)), QStringLiteral("changed their display name to Example Changed"));
QCOMPARE(model->data(model->index(1)), u"<b>This is an example<br>text message</b>"_s); QCOMPARE(model->data(model->index(1)), QStringLiteral("<b>This is an example<br>text message</b>"));
QCOMPARE(model->data(model->index(1), TimelineMessageModel::DelegateTypeRole), DelegateType::Message); QCOMPARE(model->data(model->index(1), MessageEventModel::DelegateTypeRole), DelegateType::Message);
QCOMPARE(model->data(model->index(1), TimelineMessageModel::EventIdRole), u"$153456789:example.org"_s); QCOMPARE(model->data(model->index(1), MessageEventModel::PlainText), QStringLiteral("This is an example\ntext message"));
QCOMPARE(model->data(model->index(1), MessageEventModel::EventIdRole), QStringLiteral("$153456789:example.org"));
QTest::ignoreMessage(QtWarningMsg, "Index QModelIndex(-1,-1,0x0,QObject(0x0)) is not valid (expected valid)"); QTest::ignoreMessage(QtWarningMsg, "Index QModelIndex(-1,-1,0x0,QObject(0x0)) is not valid (expected valid)");
QCOMPARE(model->data(model->index(-1)), QVariant()); QCOMPARE(model->data(model->index(-1)), QVariant());
@@ -111,37 +112,33 @@ void TimelineMessageModelTest::simpleTimeline()
QCOMPARE(model->data(model->index(model->rowCount())), QVariant()); QCOMPARE(model->data(model->index(model->rowCount())), QVariant());
} }
// Sync some events into the TimelineMessageModel's current room and don't crash. // Sync some events into the MessageEventModel's current room and don't crash.
void TimelineMessageModelTest::syncNewEvents() void MessageEventModelTest::syncNewEvents()
{ {
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s); auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
QSignalSpy spy(room, SIGNAL(aboutToAddNewMessages(Quotient::RoomEventsRange))); QSignalSpy spy(room, SIGNAL(aboutToAddNewMessages(Quotient::RoomEventsRange)));
model->setRoom(room); model->setRoom(room);
QCOMPARE(model->rowCount(), 0); QCOMPARE(model->rowCount(), 0);
room->syncNewEvents(u"test-messageventmodel-sync.json"_s); room->syncNewEvents(QLatin1String("test-messageventmodel-sync.json"));
QCOMPARE(model->rowCount(), 2); QCOMPARE(model->rowCount(), 2);
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
} }
// Check the adding of pending events to the room doesn't cause any issues in the model. // Check the adding of pending events to the room doesn't cause any issues in the model.
void TimelineMessageModelTest::pendingEvent() void MessageEventModelTest::pendingEvent()
{ {
QSignalSpy spyInsert(model, SIGNAL(rowsInserted(const QModelIndex &, int, int))); QSignalSpy spyInsert(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)));
QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int))); QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)));
QSignalSpy spyChanged(model, SIGNAL(dataChanged(const QModelIndex, const QModelIndex, const QList<int> &))); QSignalSpy spyChanged(model, SIGNAL(dataChanged(const QModelIndex, const QModelIndex, const QList<int> &)));
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s); auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
model->setRoom(room); model->setRoom(room);
QCOMPARE(model->rowCount(), 0); QCOMPARE(model->rowCount(), 0);
#if Quotient_VERSION_MINOR > 9 auto txnId = room->postPlainText("New plain message"_ls);
auto txnId = room->postText("New plain message"_L1);
#else
auto txnId = room->postPlainText("New plain message"_L1);
#endif
QCOMPARE(model->rowCount(), 1); QCOMPARE(model->rowCount(), 1);
QCOMPARE(spyInsert.count(), 1); QCOMPARE(spyInsert.count(), 1);
@@ -149,30 +146,26 @@ void TimelineMessageModelTest::pendingEvent()
QCOMPARE(model->rowCount(), 0); QCOMPARE(model->rowCount(), 0);
QCOMPARE(spyRemove.count(), 1); QCOMPARE(spyRemove.count(), 1);
#if Quotient_VERSION_MINOR > 9 txnId = room->postPlainText("New plain message"_ls);
txnId = room->postText("New plain message"_L1);
#else
txnId = room->postPlainText("New plain message"_L1);
#endif
QCOMPARE(model->rowCount(), 1); QCOMPARE(model->rowCount(), 1);
QCOMPARE(spyInsert.count(), 2); QCOMPARE(spyInsert.count(), 2);
// We need to manually set the transaction ID of the new message as it will be // We need to manually set the transaction ID of the new message as it will be
// different every time. // different every time.
QFile testSyncFile; QFile testSyncFile;
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + u"test-pending-sync.json"_s); testSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-pending-sync.json"));
testSyncFile.open(QIODevice::ReadOnly); testSyncFile.open(QIODevice::ReadOnly);
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll()); auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
auto root = testSyncJson.object(); auto root = testSyncJson.object();
auto timeline = root["timeline"_L1].toObject(); auto timeline = root["timeline"_ls].toObject();
auto events = timeline["events"_L1].toArray(); auto events = timeline["events"_ls].toArray();
auto firstEvent = events[0].toObject(); auto firstEvent = events[0].toObject();
firstEvent.insert("unsigned"_L1, QJsonObject{{"transaction_id"_L1, txnId}}); firstEvent.insert(QLatin1String("unsigned"), QJsonObject{{QLatin1String("transaction_id"), txnId}});
events[0] = firstEvent; events[0] = firstEvent;
timeline.insert("events"_L1, events); timeline.insert("events"_ls, events);
root.insert("timeline"_L1, timeline); root.insert("timeline"_ls, timeline);
testSyncJson.setObject(root); testSyncJson.setObject(root);
SyncRoomData roomData(u"@bob:kde.org"_s, JoinState::Join, testSyncJson.object()); SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testSyncJson.object());
room->update(std::move(roomData)); room->update(std::move(roomData));
QCOMPARE(model->rowCount(), 1); QCOMPARE(model->rowCount(), 1);
@@ -182,7 +175,7 @@ void TimelineMessageModelTest::pendingEvent()
auto isPendingChanged = false; auto isPendingChanged = false;
for (auto signal : spyChanged) { for (auto signal : spyChanged) {
auto roles = signal.at(2).toList(); auto roles = signal.at(2).toList();
if (roles.contains(TimelineMessageModel::IsPendingRole)) { if (roles.contains(MessageEventModel::IsPendingRole)) {
isPendingChanged = true; isPendingChanged = true;
} }
} }
@@ -190,33 +183,33 @@ void TimelineMessageModelTest::pendingEvent()
} }
// Make sure that the signals are disconnecting correctly when a room is switched. // Make sure that the signals are disconnecting correctly when a room is switched.
void TimelineMessageModelTest::disconnect() void MessageEventModelTest::disconnect()
{ {
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s); auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
model->setRoom(room); model->setRoom(room);
QSignalSpy spy(model, SIGNAL(rowsInserted(const QModelIndex &, int, int))); QSignalSpy spy(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)));
model->setRoom(nullptr); model->setRoom(nullptr);
room->syncNewEvents(u"test-messageventmodel-sync.json"_s); room->syncNewEvents(QLatin1String("test-messageventmodel-sync.json"));
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
} }
void TimelineMessageModelTest::idToRow() void MessageEventModelTest::idToRow()
{ {
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-min-sync.json"_s); auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-min-sync.json"));
model->setRoom(room); model->setRoom(room);
QCOMPARE(model->eventIdToRow(u"$153456789:example.org"_s), 0); QCOMPARE(model->eventIdToRow(QStringLiteral("$153456789:example.org")), 0);
} }
void TimelineMessageModelTest::cleanup() void MessageEventModelTest::cleanup()
{ {
delete model; delete model;
model = nullptr; model = nullptr;
QCOMPARE(model, nullptr); QCOMPARE(model, nullptr);
} }
QTEST_MAIN(TimelineMessageModelTest) QTEST_MAIN(MessageEventModelTest)
#include "timelinemessagemodeltest.moc" #include "messageeventmodeltest.moc"

View File

@@ -27,8 +27,8 @@ private Q_SLOTS:
void NeoChatRoomTest::initTestCase() void NeoChatRoomTest::initTestCase()
{ {
connection = Connection::makeMockConnection(u"@bob:kde.org"_s); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-min-sync.json"_s); room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), "test-min-sync.json"_ls);
} }
void NeoChatRoomTest::eventTest() void NeoChatRoomTest::eventTest()

View File

@@ -31,8 +31,8 @@ private Q_SLOTS:
void PollHandlerTest::initTestCase() void PollHandlerTest::initTestCase()
{ {
connection = Connection::makeMockConnection(u"@bob:kde.org"_s); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-pollhandlerstart-sync.json"_s); room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), "test-pollhandlerstart-sync.json"_ls);
} }
// Basically don't crash. // Basically don't crash.
@@ -54,16 +54,16 @@ void PollHandlerTest::poll()
auto startEvent = eventCast<const PollStartEvent>(room->messageEvents().at(0).get()); auto startEvent = eventCast<const PollStartEvent>(room->messageEvents().at(0).get());
auto pollHandler = PollHandler(room, startEvent); auto pollHandler = PollHandler(room, startEvent);
auto options = QJsonArray{QJsonObject{{"id"_L1, "option1"_L1}, {"org.matrix.msc1767.text"_L1, "option1"_L1}}, auto options = QJsonArray{QJsonObject{{"id"_ls, "option1"_ls}, {"org.matrix.msc1767.text"_ls, "option1"_ls}},
QJsonObject{{"id"_L1, "option2"_L1}, {"org.matrix.msc1767.text"_L1, "option2"_L1}}}; QJsonObject{{"id"_ls, "option2"_ls}, {"org.matrix.msc1767.text"_ls, "option2"_ls}}};
QCOMPARE(pollHandler.hasEnded(), false); QCOMPARE(pollHandler.hasEnded(), false);
QCOMPARE(pollHandler.answerCount(), 0); QCOMPARE(pollHandler.answerCount(), 0);
QCOMPARE(pollHandler.question(), u"test"_s); QCOMPARE(pollHandler.question(), QStringLiteral("test"));
QCOMPARE(pollHandler.options(), options); QCOMPARE(pollHandler.options(), options);
QCOMPARE(pollHandler.answers(), QJsonObject()); QCOMPARE(pollHandler.answers(), QJsonObject());
QCOMPARE(pollHandler.counts(), QJsonObject()); QCOMPARE(pollHandler.counts(), QJsonObject());
QCOMPARE(pollHandler.kind(), u"org.matrix.msc3381.poll.disclosed"_s); QCOMPARE(pollHandler.kind(), QStringLiteral("org.matrix.msc3381.poll.disclosed"));
} }
QTEST_GUILESS_MAIN(PollHandlerTest) QTEST_GUILESS_MAIN(PollHandlerTest)

View File

@@ -20,50 +20,61 @@ class ReactionModelTest : public QObject
private: private:
Connection *connection = nullptr; Connection *connection = nullptr;
TestUtils::TestRoom *room = nullptr; TestUtils::TestRoom *room = nullptr;
MessageContentModel *parentModel;
private Q_SLOTS: private Q_SLOTS:
void initTestCase(); void initTestCase();
void nullModel();
void basicReaction(); void basicReaction();
void newReaction(); void newReaction();
}; };
void ReactionModelTest::initTestCase() void ReactionModelTest::initTestCase()
{ {
connection = Connection::makeMockConnection(u"@bob:kde.org"_s); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-reactionmodel-sync.json"_s); room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-reactionmodel-sync.json"));
parentModel = new MessageContentModel(room, "123456"_L1); }
void ReactionModelTest::nullModel()
{
auto model = ReactionModel(nullptr, nullptr);
QCOMPARE(model.rowCount(), 0);
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), QVariant());
} }
void ReactionModelTest::basicReaction() void ReactionModelTest::basicReaction()
{ {
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get()); auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
auto model = ReactionModel(parentModel, event->id(), room); auto model = ReactionModel(event, room);
QCOMPARE(model.rowCount(), 1); QCOMPARE(model.rowCount(), 1);
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), u"<span style=\"font-family: 'emoji';\">👍</span>"_s); QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), QStringLiteral("<span style=\"font-family: 'emoji';\">👍</span>"));
QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), u"👍"_s); QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), QStringLiteral("👍"));
QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole), u"Alice Margatroid reacted with <span style=\"font-family: 'emoji';\">👍</span>"_s); QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole),
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalMember), false); QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
auto authorList = QVariantList{room->getUser(room->user(QStringLiteral("@alice:matrix.org")))};
QCOMPARE(model.data(model.index(0), ReactionModel::AuthorsRole), authorList);
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalUser), false);
} }
void ReactionModelTest::newReaction() void ReactionModelTest::newReaction()
{ {
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get()); auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
auto model = new ReactionModel(parentModel, event->id(), room); auto model = new ReactionModel(event, room);
QCOMPARE(model->rowCount(), 1); QCOMPARE(model->rowCount(), 1);
QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole), u"Alice Margatroid reacted with <span style=\"font-family: 'emoji';\">👍</span>"_s); QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole),
QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
QSignalSpy spy(model, SIGNAL(modelReset())); QSignalSpy spy(model, SIGNAL(modelReset()));
room->syncNewEvents(u"test-reactionmodel-extra-sync.json"_s); room->syncNewEvents(QLatin1String("test-reactionmodel-extra-sync.json"));
QCOMPARE(model->rowCount(), 2); QCOMPARE(model->rowCount(), 2);
QCOMPARE(spy.count(), 2); // Once for each of the 2 new reactions. QCOMPARE(spy.count(), 2); // Once for each of the 2 new reactions.
QCOMPARE(model->data(model->index(1), ReactionModel::ReactionRole), u"😆"_s); QCOMPARE(model->data(model->index(1), ReactionModel::ReactionRole), QStringLiteral("😆"));
QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole), QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole),
u"Alice Margatroid and Bob reacted with <span style=\"font-family: 'emoji';\">👍</span>"_s); QStringLiteral("@alice:matrix.org and @bob:example.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
delete model; delete model;
} }

View File

@@ -31,7 +31,7 @@ public:
{ {
if (!syncFileName.isEmpty()) { if (!syncFileName.isEmpty()) {
QFile testSyncFile; QFile testSyncFile;
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName); testSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + syncFileName);
testSyncFile.open(QIODevice::ReadOnly); testSyncFile.open(QIODevice::ReadOnly);
const auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll()); const auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson.object()); Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson.object());
@@ -45,7 +45,7 @@ inline Quotient::event_ptr_tt<EventT> loadEventFromFile(const QString &eventFile
{ {
if (!eventFileName.isEmpty()) { if (!eventFileName.isEmpty()) {
QFile testEventFile; QFile testEventFile;
testEventFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + eventFileName); testEventFile.setFileName(QLatin1String(DATA_DIR) + u'/' + eventFileName);
testEventFile.open(QIODevice::ReadOnly); testEventFile.open(QIODevice::ReadOnly);
auto testSyncJson = QJsonDocument::fromJson(testEventFile.readAll()).object(); auto testSyncJson = QJsonDocument::fromJson(testEventFile.readAll()).object();
return Quotient::loadEvent<EventT>(testSyncJson); return Quotient::loadEvent<EventT>(testSyncJson);

View File

@@ -10,9 +10,9 @@
#include <Quotient/syncdata.h> #include <Quotient/syncdata.h>
#include <qnamespace.h> #include <qnamespace.h>
#include "enums/messagecomponenttype.h"
#include "models/customemojimodel.h" #include "models/customemojimodel.h"
#include "neochatconnection.h" #include "neochatconnection.h"
#include "utils.h"
#include "testutils.h" #include "testutils.h"
@@ -33,6 +33,7 @@ private Q_SLOTS:
void stripDisallowedTags(); void stripDisallowedTags();
void stripDisallowedAttributes(); void stripDisallowedAttributes();
void emptyCodeTags(); void emptyCodeTags();
void formatBlockQuote();
void sendSimpleStringCase(); void sendSimpleStringCase();
void sendSingleParaMarkup(); void sendSingleParaMarkup();
@@ -44,7 +45,6 @@ private Q_SLOTS:
void sendCustomEmojiCode_data(); void sendCustomEmojiCode_data();
void sendCustomEmojiCode(); void sendCustomEmojiCode();
void receiveSpacelessSelfClosingTag();
void receiveStripReply(); void receiveStripReply();
void receivePlainTextIn(); void receivePlainTextIn();
@@ -59,37 +59,34 @@ private Q_SLOTS:
void receiveRichtextIn(); void receiveRichtextIn();
void receiveRichMxcUrl(); void receiveRichMxcUrl();
void receiveRichPlainUrl(); void receiveRichPlainUrl();
void receiveRichEmote();
void receiveRichEdited_data(); void receiveRichEdited_data();
void receiveRichEdited(); void receiveRichEdited();
void receiveLineSeparator(); void receiveLineSeparator();
void receiveRichCodeUrl(); void receiveRichCodeUrl();
void receiveRichColor();
void componentOutput_data();
void componentOutput();
}; };
void TextHandlerTest::initTestCase() void TextHandlerTest::initTestCase()
{ {
connection = Connection::makeMockConnection(u"@bob:kde.org"_s); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
connection->setAccountData(u"im.ponies.user_emotes"_s, connection->setAccountData("im.ponies.user_emotes"_ls,
QJsonObject{{"images"_L1, QJsonObject{{"images"_ls,
QJsonObject{{"test"_L1, QJsonObject{{"test"_ls,
QJsonObject{{"body"_L1, "Test custom emoji"_L1}, QJsonObject{{"body"_ls, "Test custom emoji"_ls},
{"url"_L1, "mxc://example.org/test"_L1}, {"url"_ls, "mxc://example.org/test"_ls},
{"usage"_L1, QJsonArray{"emoticon"_L1}}}}}}}); {"usage"_ls, QJsonArray{"emoticon"_ls}}}}}}});
CustomEmojiModel::instance().setConnection(static_cast<NeoChatConnection *>(connection)); CustomEmojiModel::instance().setConnection(static_cast<NeoChatConnection *>(connection));
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-texthandler-sync.json"_s); room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-texthandler-sync.json"));
} }
void TextHandlerTest::allowedAttributes() void TextHandlerTest::allowedAttributes()
{ {
const QString testInputString1 = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s; const QString testInputString1 = QStringLiteral("<p><span data-mx-spoiler><font color=#FFFFFF>Test</font><span></p>");
const QString testOutputString1 = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s; const QString testOutputString1 = QStringLiteral("<p><span data-mx-spoiler><font color=#FFFFFF>Test</font><span></p>");
// Handle urls where the href has either single (') or double (") quotes. // Handle urls where the href has either single (') or double (") quotes.
const QString testInputString2 = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s; const QString testInputString2 = QStringLiteral("<p><a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a></p>");
const QString testOutputString2 = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s; const QString testOutputString2 = QStringLiteral("<p><a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a></p>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString1); testTextHandler.setData(testInputString1);
@@ -104,8 +101,8 @@ void TextHandlerTest::allowedAttributes()
void TextHandlerTest::stripDisallowedTags() void TextHandlerTest::stripDisallowedTags()
{ {
const QString testInputString = u"<p>Allowed</p> <span>Allowed</span> <body>Disallowed</body>"_s; const QString testInputString = QStringLiteral("<p>Allowed</p> <span>Allowed</span> <body>Disallowed</body>");
const QString testOutputString = u"<p>Allowed</p> <span>Allowed</span> Disallowed"_s; const QString testOutputString = QStringLiteral("<p>Allowed</p> <span>Allowed</span> Disallowed");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -116,8 +113,8 @@ void TextHandlerTest::stripDisallowedTags()
void TextHandlerTest::stripDisallowedAttributes() void TextHandlerTest::stripDisallowedAttributes()
{ {
const QString testInputString = u"<p style=\"font-size:50px;\" color=#FFFFFF>Test</p>"_s; const QString testInputString = QStringLiteral("<p style=\"font-size:50px;\" color=#FFFFFF>Test</p>");
const QString testOutputString = u"Test"_s; const QString testOutputString = QStringLiteral("<p>Test</p>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -132,8 +129,8 @@ void TextHandlerTest::stripDisallowedAttributes()
*/ */
void TextHandlerTest::emptyCodeTags() void TextHandlerTest::emptyCodeTags()
{ {
const QString testInputString = u"<pre><code></code></pre>"_s; const QString testInputString = QStringLiteral("<pre><code></code></pre>");
const QString testOutputString = u"<pre><code></code></pre>"_s; const QString testOutputString = QStringLiteral("<pre><code></code></pre>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -142,10 +139,20 @@ void TextHandlerTest::emptyCodeTags()
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString); QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
} }
void TextHandlerTest::formatBlockQuote()
{
auto input = QStringLiteral("<blockquote>\n<p>Lorem Ispum</p>\n</blockquote>");
auto expectedOutput = QStringLiteral("<blockquote><table><tr><td>\u201CLorem Ispum\u201D</td></tr></table></blockquote>");
TextHandler testTextHandler;
testTextHandler.setData(input);
QCOMPARE(testTextHandler.handleRecieveRichText(), expectedOutput);
}
void TextHandlerTest::sendSimpleStringCase() void TextHandlerTest::sendSimpleStringCase()
{ {
const QString testInputString = u"This data should just be left alone."_s; const QString testInputString = QStringLiteral("This data should just be put in a paragraph.");
const QString testOutputString = u"This data should just be left alone."_s; const QString testOutputString = QStringLiteral("<p>This data should just be put in a paragraph.</p>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -155,10 +162,11 @@ void TextHandlerTest::sendSimpleStringCase()
void TextHandlerTest::sendSingleParaMarkup() void TextHandlerTest::sendSingleParaMarkup()
{ {
const QString testInputString = const QString testInputString = QStringLiteral(
u"Text para with **bold**, *italic*, [link](https://kde.org), ![image](mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e), `inline code`."_s; "Text para with **bold**, *italic*, [link](https://kde.org), ![image](mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e), `inline code`.");
const QString testOutputString = const QString testOutputString = QStringLiteral(
u"Text para with <strong>bold</strong>, <em>italic</em>, <a href=\"https://kde.org\">link</a>, <img src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\">, <code>inline code</code>."_s; "<p>Text para with <strong>bold</strong>, <em>italic</em>, <a href=\"https://kde.org\">link</a>, <img "
"src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\">, <code>inline code</code>.</p>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -169,9 +177,11 @@ void TextHandlerTest::sendSingleParaMarkup()
void TextHandlerTest::sendMultipleSectionMarkup() void TextHandlerTest::sendMultipleSectionMarkup()
{ {
const QString testInputString = const QString testInputString =
u"Text para\n> blockquote\n* List 1\n* List 2\n1. one\n2. two\n# Heading 1\n## Heading 2\nhorizontal rule\n\n---\n```\ncodeblock\n```"_s; QStringLiteral("Text para\n> blockquote\n* List 1\n* List 2\n1. one\n2. two\n# Heading 1\n## Heading 2\nhorizontal rule\n\n---\n```\ncodeblock\n```");
const QString testOutputString = const QString testOutputString = QStringLiteral(
u"<p>Text para</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>\n<ul>\n<li>List 1</li>\n<li>List 2</li>\n</ul>\n<ol>\n<li>one</li>\n<li>two</li>\n</ol>\n<h1>Heading 1</h1>\n<h2>Heading 2</h2>\n<p>horizontal rule</p>\n<hr>\n<pre><code>codeblock\n</code></pre>"_s; "<p>Text para</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>\n<ul>\n<li>List 1</li>\n<li>List "
"2</li>\n</ul>\n<ol>\n<li>one</li>\n<li>two</li>\n</ol>\n<h1>Heading 1</h1>\n<h2>Heading 2</h2>\n<p>horizontal "
"rule</p>\n<hr>\n<pre><code>codeblock\n</code></pre>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -181,8 +191,8 @@ void TextHandlerTest::sendMultipleSectionMarkup()
void TextHandlerTest::sendBadLinks() void TextHandlerTest::sendBadLinks()
{ {
const QString testInputString = u"[link](kde.org), ![image](https://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e)"_s; const QString testInputString = QStringLiteral("[link](kde.org), ![image](https://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e)");
const QString testOutputString = u"<a>link</a>, <img alt=\"image\">"_s; const QString testOutputString = QStringLiteral("<p><a>link</a>, <img alt=\"image\"></p>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -195,9 +205,9 @@ void TextHandlerTest::sendBadLinks()
*/ */
void TextHandlerTest::sendEscapeCode() void TextHandlerTest::sendEscapeCode()
{ {
const QString testInputString = u"```\n<p>Test <span style=\"font-size:50px;\">some</span> code</p>\n```"_s; const QString testInputString = QStringLiteral("```\n<p>Test <span style=\"font-size:50px;\">some</span> code</p>\n```");
const QString testOutputString = const QString testOutputString =
u"<pre><code>&lt;p&gt;Test &lt;span style=&quot;font-size:50px;&quot;&gt;some&lt;/span&gt; code&lt;/p&gt;\n</code></pre>"_s; QStringLiteral("<pre><code>&lt;p&gt;Test &lt;span style=&quot;font-size:50px;&quot;&gt;some&lt;/span&gt; code&lt;/p&gt;\n</code></pre>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -207,8 +217,8 @@ void TextHandlerTest::sendEscapeCode()
void TextHandlerTest::sendCodeClass() void TextHandlerTest::sendCodeClass()
{ {
const QString testInputString = u"```html\nsome code\n```\n<pre><code class=\"code-underline\">some more code</code></pre>"_s; const QString testInputString = QStringLiteral("```html\nsome code\n```\n<pre><code class=\"code-underline\">some more code</code></pre>");
const QString testOutputString = u"<pre><code class=\"language-html\">some code\n</code></pre>\n<pre><code>some more code</code></pre>"_s; const QString testOutputString = QStringLiteral("<pre><code class=\"language-html\">some code\n</code></pre>\n<pre><code>some more code</code></pre>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -218,9 +228,9 @@ void TextHandlerTest::sendCodeClass()
void TextHandlerTest::sendCustomEmoji() void TextHandlerTest::sendCustomEmoji()
{ {
const QString testInputString = u":test:"_s; const QString testInputString = QStringLiteral(":test:");
const QString testOutputString = const QString testOutputString = QStringLiteral(
u"<img data-mx-emoticon=\"\" src=\"mxc://example.org/test\" alt=\":test:\" title=\":test:\" height=\"32\" vertical-align=\"middle\" />"_s; "<p><img data-mx-emoticon=\"\" src=\"mxc://example.org/test\" alt=\":test:\" title=\":test:\" height=\"32\" vertical-align=\"middle\" /></p>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -233,8 +243,8 @@ void TextHandlerTest::sendCustomEmojiCode_data()
QTest::addColumn<QString>("testInputString"); QTest::addColumn<QString>("testInputString");
QTest::addColumn<QString>("testOutputString"); QTest::addColumn<QString>("testOutputString");
QTest::newRow("inline") << u"`:test:`"_s << u"<code>:test:</code>"_s; QTest::newRow("inline") << QStringLiteral("`:test:`") << QStringLiteral("<p><code>:test:</code></p>");
QTest::newRow("block") << u"```\n:test:\n```"_s << u"<pre><code>:test:\n</code></pre>"_s; QTest::newRow("block") << QStringLiteral("```\n:test:\n```") << QStringLiteral("<pre><code>:test:\n</code></pre>");
} }
// Custom emojis in code blocks should be left alone. // Custom emojis in code blocks should be left alone.
@@ -249,24 +259,12 @@ void TextHandlerTest::sendCustomEmojiCode()
QCOMPARE(testTextHandler.handleSendText(), testOutputString); QCOMPARE(testTextHandler.handleSendText(), testOutputString);
} }
void TextHandlerTest::receiveSpacelessSelfClosingTag()
{
const QString testInputString = u"Test...<br/>...ing"_s;
const QString testRichOutputString = u"Test...<br/>...ing"_s;
const QString testPlainOutputString = u"Test...\n...ing"_s;
TextHandler testTextHandler;
testTextHandler.setData(testInputString);
QCOMPARE(testTextHandler.handleRecieveRichText(), testRichOutputString);
QCOMPARE(testTextHandler.handleRecievePlainText(Qt::RichText), testPlainOutputString);
}
void TextHandlerTest::receiveStripReply() void TextHandlerTest::receiveStripReply()
{ {
const QString testInputString = const QString testInputString = QStringLiteral(
u"<mx-reply><blockquote><a href=\"https://matrix.to/#/!somewhere:example.org/$event:example.org\">In reply to</a><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a><br />Message replied to.</blockquote></mx-reply>Reply message."_s; "<mx-reply><blockquote><a href=\"https://matrix.to/#/!somewhere:example.org/$event:example.org\">In reply to</a><a "
const QString testOutputString = u"Reply message."_s; "href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a><br />Message replied to.</blockquote></mx-reply>Reply message.");
const QString testOutputString = QStringLiteral("Reply message.");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -280,10 +278,9 @@ void TextHandlerTest::receiveRichInPlainOut_data()
QTest::addColumn<QString>("testInputString"); QTest::addColumn<QString>("testInputString");
QTest::addColumn<QString>("testOutputString"); QTest::addColumn<QString>("testOutputString");
QTest::newRow("ampersand") << u"a &amp; b"_s << u"a & b"_s; QTest::newRow("ampersand") << QStringLiteral("a &amp; b") << QStringLiteral("a & b");
QTest::newRow("quote") << u"&quot;a and b&quot;"_s << u"\"a and b\""_s; QTest::newRow("quote") << QStringLiteral("&quot;a and b&quot;") << QStringLiteral("\"a and b\"");
QTest::newRow("new line") << u"new<br>line"_s << u"new\nline"_s; QTest::newRow("new line") << QStringLiteral("new<br>line") << QStringLiteral("new\nline");
QTest::newRow("unescape") << u"can&#x27;t"_s << u"can't"_s;
} }
void TextHandlerTest::receiveRichInPlainOut() void TextHandlerTest::receiveRichInPlainOut()
@@ -299,13 +296,13 @@ void TextHandlerTest::receiveRichInPlainOut()
void TextHandlerTest::receivePlainTextIn() void TextHandlerTest::receivePlainTextIn()
{ {
const QString testInputString = u"<plain text in tag bracket>\nTest link https://kde.org."_s; const QString testInputString = QStringLiteral("<plain text in tag bracket>\nTest link https://kde.org.");
const QString testOutputStringRich = u"&lt;plain text in tag bracket&gt;<br>Test link <a href=\"https://kde.org\">https://kde.org</a>."_s; const QString testOutputStringRich = QStringLiteral("&lt;plain text in tag bracket&gt;<br>Test link <a href=\"https://kde.org\">https://kde.org</a>.");
QString testOutputStringPlain = u"<plain text in tag bracket>\nTest link https://kde.org."_s; QString testOutputStringPlain = QStringLiteral("<plain text in tag bracket>\nTest link https://kde.org.");
// Make sure quotes are maintained in a plain string. // Make sure quotes are maintained in a plain string.
const QString testInputString2 = u"last line is \"Time to switch to a new topic.\""_s; const QString testInputString2 = QStringLiteral("last line is \"Time to switch to a new topic.\"");
const QString testOutputString2 = u"last line is \"Time to switch to a new topic.\""_s; const QString testOutputString2 = QStringLiteral("last line is \"Time to switch to a new topic.\"");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -320,12 +317,12 @@ void TextHandlerTest::receivePlainTextIn()
void TextHandlerTest::receiveStripNewlines() void TextHandlerTest::receiveStripNewlines()
{ {
const QString testInputStringPlain = u"Test\nmany\nnew\nlines."_s; const QString testInputStringPlain = QStringLiteral("Test\nmany\nnew\nlines.");
const QString testInputStringRich = u"Test<br>many<br />new<br>lines."_s; const QString testInputStringRich = QStringLiteral("Test<br>many<br />new<br>lines.");
const QString testOutputString = u"Test many new lines."_s; const QString testOutputString = QStringLiteral("Test many new lines.");
const QString testInputStringPlain2 = u"* List\n* Items"_s; const QString testInputStringPlain2 = QStringLiteral("* List\n* Items");
const QString testOutputString2 = u"List Items"_s; const QString testOutputString2 = QStringLiteral("List Items");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputStringPlain); testTextHandler.setData(testInputStringPlain);
@@ -347,8 +344,8 @@ void TextHandlerTest::receiveStripNewlines()
*/ */
void TextHandlerTest::receivePlainStripHtml() void TextHandlerTest::receivePlainStripHtml()
{ {
const QString testInputString = u"<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>"_s; const QString testInputString = QStringLiteral("<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>");
const QString testOutputString = u"Test Some code <strong>with tags</strong>"_s; const QString testOutputString = QStringLiteral("Test Some code <strong>with tags</strong>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -358,8 +355,8 @@ void TextHandlerTest::receivePlainStripHtml()
void TextHandlerTest::receivePlainStripMarkup() void TextHandlerTest::receivePlainStripMarkup()
{ {
const QString testInputString = u"**bold** `<p>inline code</p>` *italic*"_s; const QString testInputString = QStringLiteral("**bold** `<p>inline code</p>` *italic*");
const QString testOutputString = u"bold <p>inline code</p> italic"_s; const QString testOutputString = QStringLiteral("bold <p>inline code</p> italic");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -369,8 +366,8 @@ void TextHandlerTest::receivePlainStripMarkup()
void TextHandlerTest::receiveRichUserPill() void TextHandlerTest::receiveRichUserPill()
{ {
const QString testInputString = u"<p><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></p>"_s; const QString testInputString = QStringLiteral("<p><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></p>");
const QString testOutputString = u"<b><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></b>"_s; const QString testOutputString = QStringLiteral("<p><b><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></b></p>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -380,8 +377,8 @@ void TextHandlerTest::receiveRichUserPill()
void TextHandlerTest::receiveRichStrikethrough() void TextHandlerTest::receiveRichStrikethrough()
{ {
const QString testInputString = u"<p><del>Test</del></p>"_s; const QString testInputString = QStringLiteral("<p><del>Test</del></p>");
const QString testOutputString = u"<s>Test</s>"_s; const QString testOutputString = QStringLiteral("<p><s>Test</s></p>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -391,8 +388,8 @@ void TextHandlerTest::receiveRichStrikethrough()
void TextHandlerTest::receiveRichtextIn() void TextHandlerTest::receiveRichtextIn()
{ {
const QString testInputString = u"<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>"_s; const QString testInputString = QStringLiteral("<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>");
const QString testOutputString = u"<p>Test</p> <pre><code>Some code &lt;strong&gt;with tags&lt;/strong&gt;</code></pre>"_s; const QString testOutputString = QStringLiteral("<p>Test</p> <pre><code>Some code &lt;strong&gt;with tags&lt;/strong&gt;</code></pre>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -402,10 +399,15 @@ void TextHandlerTest::receiveRichtextIn()
void TextHandlerTest::receiveRichMxcUrl() void TextHandlerTest::receiveRichMxcUrl()
{ {
const QString testInputString = const QString testInputString = QStringLiteral(
u"<img src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\"><img src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73\" alt=\"image\">"_s; "<img src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\"><img src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73\" "
const QString testOutputString = "alt=\"image\">");
u"<img src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" alt=\"image\"><img src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" alt=\"image\">"_s; const QString testOutputString = QStringLiteral(
"<img "
"src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" "
"alt=\"image\"><img "
"src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" "
"alt=\"image\">");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
@@ -423,27 +425,35 @@ void TextHandlerTest::receiveRichPlainUrl()
{ {
// This is an actual link that caused trouble which is why it's so long. Keeping // This is an actual link that caused trouble which is why it's so long. Keeping
// so we can confirm consistent behaviour for complex urls. // so we can confirm consistent behaviour for complex urls.
const QString testInputStringLink1 = const QString testInputStringLink1 = QStringLiteral(
u"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\">Link already rich</a>"_s; "https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im "
const QString testOutputStringLink1 = "<a "
u"<a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\">https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im</a> <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\">Link already rich</a>"_s; "href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/"
"$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\">Link already rich</a>");
const QString testOutputStringLink1 = QStringLiteral(
"<a "
"href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/"
"$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\">https://matrix.to/#/"
"!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im</a> <a "
"href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/"
"$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&amp;via=matrix.org&amp;via=fedora.im\">Link already rich</a>");
// Another real case. The linkification wasn't handling it when a single link // Another real case. The linkification wasn't handling it when a single link
// contains what looks like and email. It was been broken into 3 but needs to // contains what looks like and email. It was been broken into 3 but needs to
// be just single link. // be just single link.
const QString testInputStringLink2 = u"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/"_s; const QString testInputStringLink2 = QStringLiteral("https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/");
const QString testOutputStringLink2 = const QString testOutputStringLink2 = QStringLiteral(
u"<a href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\">https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>"_s; "<a "
"href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\">https://lore.kernel.org/lkml/"
"CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>");
QString testInputStringEmail = uR"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)"_s; QString testInputStringEmail = QStringLiteral(R"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)");
QString testOutputStringEmail = uR"(<a href="mailto:email@example.com">email@example.com</a> <a href="mailto:email@example.com">Link already rich</a>)"_s; QString testOutputStringEmail =
QStringLiteral(R"(<a href="mailto:email@example.com">email@example.com</a> <a href="mailto:email@example.com">Link already rich</a>)");
QString testInputStringMxId = u"@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>"_s; QString testInputStringMxId = QStringLiteral("@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>");
QString testOutputStringMxId = QString testOutputStringMxId = QStringLiteral(
u"<b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a></b>"_s; "<b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a></b>");
QString testInputStringMxIdWithPrefix = u"a @user:kde.org b"_s;
QString testOutputStringMxIdWithPrefix = u"a <b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> b"_s;
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputStringLink1); testTextHandler.setData(testInputStringLink1);
@@ -458,9 +468,22 @@ void TextHandlerTest::receiveRichPlainUrl()
testTextHandler.setData(testInputStringMxId); testTextHandler.setData(testInputStringMxId);
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxId); QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxId);
}
testTextHandler.setData(testInputStringMxIdWithPrefix); // Test that user pill is add to an emote message.
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxIdWithPrefix); // N.B. The second message in the test timeline is marked as an emote.
void TextHandlerTest::receiveRichEmote()
{
auto event = room->messageEvents().at(1).get();
auto author = room->user(event->senderId());
const QString testInputString = QStringLiteral("This is an emote.");
const QString testOutputString = QStringLiteral("* <a href=\"https://matrix.to/#/@example:example.org\" style=\"color:")
+ Utils::getUserColor(author->hueF()).name() + QStringLiteral("\">@example:example.org</a> This is an emote.");
TextHandler testTextHandler;
testTextHandler.setData(testInputString);
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, event), testOutputString);
} }
void TextHandlerTest::receiveRichEdited_data() void TextHandlerTest::receiveRichEdited_data()
@@ -468,9 +491,12 @@ void TextHandlerTest::receiveRichEdited_data()
QTest::addColumn<QString>("testInputString"); QTest::addColumn<QString>("testInputString");
QTest::addColumn<QString>("testOutputString"); QTest::addColumn<QString>("testOutputString");
QTest::newRow("basic") << u"Edited"_s << u"Edited <span style=\"color:#000000\">(edited)</span>"_s; QTest::newRow("basic") << QStringLiteral("Edited") << QStringLiteral("Edited <span style=\"color:#000000\">(edited)</span>");
QTest::newRow("multiple paragraphs") << u"<p>Edited</p>\n<p>Edited</p>"_s QTest::newRow("multiple paragraphs") << QStringLiteral("<p>Edited</p>\n<p>Edited</p>")
<< u"<p>Edited</p>\n<p>Edited <span style=\"color:#000000\">(edited)</span></p>"_s; << QStringLiteral("<p>Edited</p>\n<p>Edited <span style=\"color:#000000\">(edited)</span></p>");
QTest::newRow("blockquote")
<< QStringLiteral("<blockquote>Edited</blockquote>")
<< QStringLiteral("<blockquote><table><tr><td>\u201CEdited\u201D</td></tr></table></blockquote><p> <span style=\"color:#000000\">(edited)</span></p>");
} }
void TextHandlerTest::receiveRichEdited() void TextHandlerTest::receiveRichEdited()
@@ -481,85 +507,24 @@ void TextHandlerTest::receiveRichEdited()
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(testInputString); testTextHandler.setData(testInputString);
const auto event = eventCast<const Quotient::RoomMessageEvent>(room->messageEvents().at(2).get()); QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(2).get()), testOutputString);
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, event, false, event->isReplaced()), testOutputString);
} }
void TextHandlerTest::receiveLineSeparator() void TextHandlerTest::receiveLineSeparator()
{ {
auto text = u"foo\u2028bar"_s; auto text = QStringLiteral("foo\u2028bar");
TextHandler textHandler; TextHandler textHandler;
textHandler.setData(text); textHandler.setData(text);
QCOMPARE(textHandler.handleRecievePlainText(Qt::PlainText, true), u"foo bar"_s); QCOMPARE(textHandler.handleRecievePlainText(Qt::PlainText, true), QStringLiteral("foo bar"));
} }
void TextHandlerTest::receiveRichCodeUrl() void TextHandlerTest::receiveRichCodeUrl()
{ {
auto input = u"<code>https://kde.org</code>"_s; auto input = QStringLiteral("<code>https://kde.org</code>");
TextHandler testTextHandler; TextHandler testTextHandler;
testTextHandler.setData(input); testTextHandler.setData(input);
QCOMPARE(testTextHandler.handleRecieveRichText(), input); QCOMPARE(testTextHandler.handleRecieveRichText(), input);
} }
void TextHandlerTest::receiveRichColor()
{
const QString testInputString =
u"<span data-mx-color=\"#ff00be\">¯</span><span data-mx-color=\"#ff3b1d\">\\</span><span data-mx-color=\"#ffa600\">_</span><span data-mx-color=\"#64d200\">(</span><span data-mx-color=\"#00e261\">ツ</span><span data-mx-color=\"#00e7ff\">)</span><span data-mx-color=\"#00e1ff\">_</span><span data-mx-color=\"#00bdff\">/</span><span data-mx-color=\"#ff60ff\">¯</span>"_s;
const QString testOutputString =
u"<span style=\"color: #ff00be;\">¯</span><span style=\"color: #ff3b1d;\">\\</span><span style=\"color: #ffa600;\">_</span><span style=\"color: #64d200;\">(</span><span style=\"color: #00e261;\">ツ</span><span style=\"color: #00e7ff;\">)</span><span style=\"color: #00e1ff;\">_</span><span style=\"color: #00bdff;\">/</span><span style=\"color: #ff60ff;\">¯</span>"_s;
TextHandler testTextHandler;
testTextHandler.setData(testInputString);
qInfo() << testTextHandler.handleRecieveRichText();
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
}
void TextHandlerTest::componentOutput_data()
{
QTest::addColumn<QString>("testInputString");
QTest::addColumn<QList<MessageComponent>>("testOutputComponents");
QTest::newRow("multiple paragraphs") << u"<p>Text</p>\n<p>Text</p>"_s
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
QTest::newRow("code") << u"<p>Text</p>\n<pre><code class=\"language-html\">Some code\n</code></pre>"_s
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
MessageComponent{MessageComponentType::Code, u"Some code"_s, QVariantMap{{u"class"_s, u"html"_s}}}};
QTest::newRow("quote") << u"<p>Text</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>"_s
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
MessageComponent{MessageComponentType::Quote, u"“blockquote”"_s, {}}};
QTest::newRow("no tag first paragraph") << u"Text\n<p>Text</p>"_s
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
QTest::newRow("no tag last paragraph") << u"<p>Text</p>\nText"_s
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
QTest::newRow("inline code") << u"<p><code>https://kde.org</code></p>\n<p>Text</p>"_s
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"<code>https://kde.org</code>"_s, {}},
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
QTest::newRow("inline code single block") << u"<code>https://kde.org</code>"_s
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"<code>https://kde.org</code>"_s, {}}};
QTest::newRow("long start tag")
<< u"Ah, you mean something like<br/><pre data-md=\"```\"><code class=\"language-qml\"># main.qml\nimport CustomQml\n...\nControls.TextField { id: someField }\nCustomQml {\n someTextProperty: someField.text\n}\n</code></pre>Sure you can, it's still local to the same file where you defined the id"_s
<< QList<MessageComponent>{
MessageComponent{MessageComponentType::Text, u"Ah, you mean something like<br/>"_s, {}},
MessageComponent{
MessageComponentType::Code,
u"# main.qml\nimport CustomQml\n...\nControls.TextField { id: someField }\nCustomQml {\n someTextProperty: someField.text\n}"_s,
QVariantMap{{u"class"_s, u"qml"_s}}},
MessageComponent{MessageComponentType::Text, u"Sure you can, it's still local to the same file where you defined the id"_s, {}}};
}
void TextHandlerTest::componentOutput()
{
QFETCH(QString, testInputString);
QFETCH(QList<MessageComponent>, testOutputComponents);
TextHandler testTextHandler;
QCOMPARE(testTextHandler.textComponents(testInputString), testOutputComponents);
}
QTEST_MAIN(TextHandlerTest) QTEST_MAIN(TextHandlerTest)
#include "texthandlertest.moc" #include "texthandlertest.moc"

View File

@@ -17,6 +17,7 @@ class WindowControllerTest : public QObject
private Q_SLOTS: private Q_SLOTS:
void nullWindow(); void nullWindow();
void geometry();
void showAndRaise(); void showAndRaise();
void toggle(); void toggle();
@@ -29,10 +30,32 @@ void WindowControllerTest::nullWindow()
auto &instance = WindowController::instance(); auto &instance = WindowController::instance();
QCOMPARE(instance.window(), nullptr); QCOMPARE(instance.window(), nullptr);
instance.restoreGeometry();
instance.saveGeometry();
instance.showAndRaiseWindow({}); instance.showAndRaiseWindow({});
instance.toggleWindow(); instance.toggleWindow();
} }
void WindowControllerTest::geometry()
{
auto &instance = WindowController::instance();
QWindow window;
window.setGeometry(0, 0, 200, 200);
instance.setWindow(&window);
QCOMPARE(instance.window(), &window);
instance.saveGeometry();
const auto stateConfig = KSharedConfig::openStateConfig();
KConfigGroup windowGroup = stateConfig->group(QStringLiteral("Window"));
QCOMPARE(KWindowConfig::hasSavedWindowSize(windowGroup), true);
window.setGeometry(0, 0, 400, 400);
QCOMPARE(window.geometry(), QRect(0, 0, 400, 400));
instance.restoreGeometry();
QCOMPARE(window.geometry(), QRect(0, 0, 200, 200));
}
void WindowControllerTest::showAndRaise() void WindowControllerTest::showAndRaise()
{ {
auto &instance = WindowController::instance(); auto &instance = WindowController::instance();

View File

@@ -1,34 +0,0 @@
# SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
# SPDX-License-Identifier: BSD-2-Clause
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}" )
qt_add_executable(timeline-memtest
main.cpp
)
target_link_libraries(timeline-memtest PRIVATE neochatplugin timelineplugin)
target_link_libraries(timeline-memtest PUBLIC
Qt::Core
Qt::Quick
Qt::Qml
Qt::Gui
Qt::QuickControls2
KF6::Kirigami
QuotientQt6
neochat
)
ecm_add_qml_module(timeline-memtest URI org.kde.neochat.timeline-memtest GENERATE_PLUGIN_SOURCE
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/timeline-memtest
QML_FILES
Main.qml
SOURCES
memtesttimelinemodel.cpp
memtesttimelinemodel.h
DEPENDENCIES
QtCore
QtQuick
IMPORTS
org.kde.neochat
)

View File

@@ -1,33 +0,0 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
import QtQuick
import QtQuick.Controls as QQC2
import org.kde.kirigami as Kirigami
import org.kde.neochat
QQC2.ApplicationWindow {
id: root
title: "Timeline Memory Test"
minimumWidth: Kirigami.Units.gridUnit * 30
minimumHeight: Kirigami.Units.gridUnit * 30
visible: true
QQC2.ScrollView {
width: root.width
height: root.height
contentItem: ListView {
model: messageFilterModel
delegate: EventDelegate {
room: memTestTimelineModel.room
}
}
}
}

View File

@@ -1,30 +0,0 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <KLocalizedString>
#include "memtesttimelinemodel.h"
#include "models/messagefiltermodel.h"
using namespace Qt::StringLiterals;
int main(int argc, char **argv)
{
QApplication app(argc, argv);
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
QQmlApplicationEngine engine;
engine.loadFromModule("org.kde.neochat.timeline-memtest", "Main");
MemTestTimelineModel *memTestTimelineModel = new MemTestTimelineModel;
MessageFilterModel *messageFilterModel = new MessageFilterModel(nullptr, memTestTimelineModel);
engine.rootContext()->setContextProperty(u"memTestTimelineModel"_s, memTestTimelineModel);
engine.rootContext()->setContextProperty(u"messageFilterModel"_s, messageFilterModel);
return app.exec();
}

View File

@@ -1,655 +0,0 @@
{
"ephemeral": {
"events": [
{
"content": {
"$1000000000000:example.org": {
"m.read": {
"@alice:example.org": {
"ts": 1000000000000
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1000000000000:example.org": {
"m.read": {
"@bob:example.org": {
"ts": 1000000000000
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1000000000003:example.org": {
"m.read": {
"@tim:example.org": {
"ts": 1000000000000
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1000000000003:example.org": {
"m.read": {
"@example:example.org": {
"ts": 1000000000000
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1000000000003:example.org": {
"m.read": {
"@jeff:example.org": {
"ts": 1000000000000
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1000000000003:example.org": {
"m.read": {
"@tina:example.org": {
"ts": 1000000000000
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1000000000003:example.org": {
"m.read": {
"@sally:example.org": {
"ts": 1000000000000
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1000000000003:example.org": {
"m.read": {
"@fred:example.org": {
"ts": 1000000000000
}
}
}
},
"type": "m.receipt"
}
]
},
"state": {
"events": [
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Example",
"membership": "join"
},
"event_id": "$143273582555PhrSn:example.org",
"origin_server_ts": 1000000000000,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "example:example.org",
"state_key": "@example:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice",
"membership": "join",
"reason": "Looking for support"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1000000000000,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "alice:example.org",
"state_key": "@alice:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Bob",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1000000000000,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "bob:example.org",
"state_key": "@bob:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Tim",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1000000000000,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "tim:example.org",
"state_key": "@tim:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Jeff",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1000000000000,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "jeff:example.org",
"state_key": "@jeff:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Tina",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1000000000000,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "tina:example.org",
"state_key": "@tina:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Sally",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1000000000000,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "sally:example.org",
"state_key": "@sally:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Fred",
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1000000000000,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "fred:example.org",
"state_key": "@fred:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
}
]
},
"timeline": {
"events": [
{
"content": {
"body": "This is an example text message",
"format": "org.matrix.custom.html",
"formatted_body": "This is an example<br>text message",
"msgtype": "m.text"
},
"event_id": "$1000000000000:example.org",
"origin_server_ts": 1000000000000,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "This is a highlight @bob:example.org",
"msgtype": "m.text"
},
"event_id": "$1000000000001:example.org",
"origin_server_ts": 1000000000001,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1233
}
},
{
"content": {
"m.relates_to": {
"event_id": "$1000000000001:example.org",
"key": "👍",
"rel_type": "m.annotation"
}
},
"origin_server_ts": 1000000000002,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@alice:example.org",
"type": "m.reaction",
"unsigned": {
"age": 390159120
},
"event_id": "$1000000000002:example.org",
"age": 390159120
},
{
"content": {
"body": "reply",
"format": "org.matrix.custom.html",
"formatted_body": "reply",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$1000000000000:example.org"
}
},
"msgtype": "m.text"
},
"origin_server_ts": 1000000000003,
"sender": "@alice:example.org",
"type": "m.room.message",
"unsigned": {
"age": 98
},
"event_id": "$1000000000003:example.org",
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
},
{
"age": 96845207,
"content": {
"body": "Lat: 51.7035, Lon: -1.14394",
"geo_uri": "geo:51.7035,-1.14394",
"msgtype": "m.location",
"org.matrix.msc1767.text": "Lat: 51.7035, Lon: -1.14394",
"org.matrix.msc3488.asset": {
"type": "m.pin"
},
"org.matrix.msc3488.location": {
"uri": "geo:51.7035,-1.14394"
}
},
"event_id": "$1000000000004:example.org",
"origin_server_ts": 1000000000004,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 96845207
}
},
{
"content": {
"body": "```cpp\nint main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral(\"neochat\"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule(\"org.kde.neochat.timeline-memtest\", \"Main\");\n\n return app.exec();\n}\n```",
"format": "org.matrix.custom.html",
"formatted_body": "<pre><code class=\"language-cpp\">int main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral(&quot;neochat&quot;));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule(&quot;org.kde.neochat.timeline-memtest&quot;, &quot;Main&quot;);\n\n return app.exec();\n}\n</code></pre>",
"msgtype": "m.text"
},
"event_id": "$1000000000005:example.org",
"origin_server_ts": 1000000000005,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@bob:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1233
}
},
{
"content": {
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
"msgtype": "m.text"
},
"event_id": "$1000000000006:example.org",
"origin_server_ts": 1000000000006,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
"format": "org.matrix.custom.html",
"formatted_body": "<blockquote>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat.</p>\n</blockquote>",
"msgtype": "m.text"
},
"event_id": "$1000000000007:example.org",
"origin_server_ts": 1000000000007,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "This is an example text message",
"format": "org.matrix.custom.html",
"formatted_body": "This is an example<br>text message",
"msgtype": "m.text"
},
"event_id": "$1000000000008:example.org",
"origin_server_ts": 1000000000008,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "This is a highlight @bob:example.org",
"msgtype": "m.text"
},
"event_id": "$1000000000009:example.org",
"origin_server_ts": 1000000000009,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1233
}
},
{
"content": {
"m.relates_to": {
"event_id": "$1000000000009:example.org",
"key": "👍",
"rel_type": "m.annotation"
}
},
"origin_server_ts": 1000000000010,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@alice:example.org",
"type": "m.reaction",
"unsigned": {
"age": 390159120
},
"event_id": "$1000000000010:example.org",
"age": 390159120
},
{
"content": {
"body": "reply",
"format": "org.matrix.custom.html",
"formatted_body": "reply",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$1000000000008:example.org"
}
},
"msgtype": "m.text"
},
"origin_server_ts": 1000000000011,
"sender": "@alice:example.org",
"type": "m.room.message",
"unsigned": {
"age": 98
},
"event_id": "$1000000000011:example.org",
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
},
{
"age": 96845207,
"content": {
"body": "Lat: 51.7035, Lon: -1.14394",
"geo_uri": "geo:51.7035,-1.14394",
"msgtype": "m.location",
"org.matrix.msc1767.text": "Lat: 51.7035, Lon: -1.14394",
"org.matrix.msc3488.asset": {
"type": "m.pin"
},
"org.matrix.msc3488.location": {
"uri": "geo:51.7035,-1.14394"
}
},
"event_id": "$1000000000012:example.org",
"origin_server_ts": 1000000000012,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 96845207
}
},
{
"content": {
"body": "```cpp\nint main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral(\"neochat\"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule(\"org.kde.neochat.timeline-memtest\", \"Main\");\n\n return app.exec();\n}\n```",
"format": "org.matrix.custom.html",
"formatted_body": "<pre><code class=\"language-cpp\">int main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral(&quot;neochat&quot;));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule(&quot;org.kde.neochat.timeline-memtest&quot;, &quot;Main&quot;);\n\n return app.exec();\n}\n</code></pre>",
"msgtype": "m.text"
},
"event_id": "$1000000000013:example.org",
"origin_server_ts": 1000000000013,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@bob:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1233
}
},
{
"content": {
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
"msgtype": "m.text"
},
"event_id": "$1000000000014:example.org",
"origin_server_ts": 1000000000014,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
"format": "org.matrix.custom.html",
"formatted_body": "<blockquote>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat.</p>\n</blockquote>",
"msgtype": "m.text"
},
"event_id": "$1000000000015:example.org",
"origin_server_ts": 1000000000015,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "This is an example text message",
"format": "org.matrix.custom.html",
"formatted_body": "This is an example<br>text message",
"msgtype": "m.text"
},
"event_id": "$1000000000016:example.org",
"origin_server_ts": 1000000000016,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "This is a highlight @bob:example.org",
"msgtype": "m.text"
},
"event_id": "$1000000000017:example.org",
"origin_server_ts": 1000000000017,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1233
}
},
{
"content": {
"m.relates_to": {
"event_id": "$1000000000017:example.org",
"key": "👍",
"rel_type": "m.annotation"
}
},
"origin_server_ts": 1000000000018,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@alice:example.org",
"type": "m.reaction",
"unsigned": {
"age": 390159120
},
"event_id": "$1000000000018:example.org",
"age": 390159120
},
{
"content": {
"body": "reply",
"format": "org.matrix.custom.html",
"formatted_body": "reply",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$1000000000016:example.org"
}
},
"msgtype": "m.text"
},
"origin_server_ts": 1000000000019,
"sender": "@alice:example.org",
"type": "m.room.message",
"unsigned": {
"age": 98
},
"event_id": "$1000000000019:example.org",
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
},
{
"age": 96845207,
"content": {
"body": "Lat: 51.7035, Lon: -1.14394",
"geo_uri": "geo:51.7035,-1.14394",
"msgtype": "m.location",
"org.matrix.msc1767.text": "Lat: 51.7035, Lon: -1.14394",
"org.matrix.msc3488.asset": {
"type": "m.pin"
},
"org.matrix.msc3488.location": {
"uri": "geo:51.7035,-1.14394"
}
},
"event_id": "$1000000000020:example.org",
"origin_server_ts": 1000000000020,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 96845207
}
},
{
"content": {
"body": "```cpp\nint main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral(\"neochat\"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule(\"org.kde.neochat.timeline-memtest\", \"Main\");\n\n return app.exec();\n}\n```",
"format": "org.matrix.custom.html",
"formatted_body": "<pre><code class=\"language-cpp\">int main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral(&quot;neochat&quot;));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule(&quot;org.kde.neochat.timeline-memtest&quot;, &quot;Main&quot;);\n\n return app.exec();\n}\n</code></pre>",
"msgtype": "m.text"
},
"event_id": "$1000000000021:example.org",
"origin_server_ts": 1000000000021,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@bob:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1233
}
},
{
"content": {
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
"msgtype": "m.text"
},
"event_id": "$1000000000022:example.org",
"origin_server_ts": 1000000000022,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
"format": "org.matrix.custom.html",
"formatted_body": "<blockquote>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat.</p>\n</blockquote>",
"msgtype": "m.text"
},
"event_id": "$1000000000023:example.org",
"origin_server_ts": 1000000000023,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
}
}

View File

@@ -1,36 +0,0 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include "memtesttimelinemodel.h"
#include <Quotient/events/eventcontent.h>
#include <Quotient/events/roommessageevent.h>
using namespace Quotient;
MemTestTimelineModel::MemTestTimelineModel(QObject *parent)
: MessageModel(parent)
{
beginResetModel();
m_connection = Connection::makeMockConnection(u"@bob:example.org"_s);
m_room = new MemTestRoom(m_connection, u"#memtestroom:example.org"_s, u"memtest-sync.json"_s);
for (const auto &eventIt : m_room->messageEvents()) {
Q_EMIT newEventAdded(eventIt.event());
}
endResetModel();
}
std::optional<std::reference_wrapper<const RoomEvent>> MemTestTimelineModel::getEventForIndex(QModelIndex index) const
{
return *m_room->messageEvents().at(index.row()).event();
}
int MemTestTimelineModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_room->messageEvents().size();
}
#include "moc_memtesttimelinemodel.cpp"

View File

@@ -1,75 +0,0 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <QAbstractListModel>
#include <QQmlEngine>
#include <Quotient/events/roomevent.h>
#include <Quotient/syncdata.h>
#include "models/messagemodel.h"
namespace Quotient
{
class Connection;
}
class NeoChatRoom;
class MemTestRoom : public NeoChatRoom
{
public:
MemTestRoom(Quotient::Connection *connection, const QString &roomName, const QString &syncFileName = {})
: NeoChatRoom(connection, roomName, Quotient::JoinState::Join)
{
syncNewEvents(syncFileName);
}
void update(Quotient::SyncRoomData &&data, bool fromCache = false)
{
Room::updateData(std::move(data), fromCache);
}
void syncNewEvents(const QString &syncFileName)
{
if (!syncFileName.isEmpty()) {
QFile testSyncFile;
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
testSyncFile.open(QIODevice::ReadOnly);
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll()).object();
Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson);
update(std::move(roomData));
}
}
};
/**
* @class MemTestTimelineModel
*
* This is a special version of the MessageModel design to load an unchanging set
* of events from a json file so that timeline memory optimisations can be measured.
*/
class MemTestTimelineModel : public MessageModel
{
Q_OBJECT
QML_ELEMENT
public:
explicit MemTestTimelineModel(QObject *parent = nullptr);
/**
* @brief Number of rows in the model.
*
* @sa QAbstractItemModel::rowCount
*/
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
private:
QPointer<Quotient::Connection> m_connection;
std::vector<Quotient::RoomEventPtr> m_events;
std::optional<std::reference_wrapper<const Quotient::RoomEvent>> getEventForIndex(QModelIndex index) const override;
};

View File

@@ -25,8 +25,6 @@
<name xml:lang="fi">NeoChat</name> <name xml:lang="fi">NeoChat</name>
<name xml:lang="fr">NeoChat</name> <name xml:lang="fr">NeoChat</name>
<name xml:lang="gl">NeoChat</name> <name xml:lang="gl">NeoChat</name>
<name xml:lang="he">NeoChat</name>
<name xml:lang="hi">नियोचैट</name>
<name xml:lang="hu">NeoChat</name> <name xml:lang="hu">NeoChat</name>
<name xml:lang="ia">Neochat</name> <name xml:lang="ia">Neochat</name>
<name xml:lang="id">NeoChat</name> <name xml:lang="id">NeoChat</name>
@@ -34,7 +32,6 @@
<name xml:lang="it">NeoChat</name> <name xml:lang="it">NeoChat</name>
<name xml:lang="ka">NeoChat</name> <name xml:lang="ka">NeoChat</name>
<name xml:lang="ko">NeoChat</name> <name xml:lang="ko">NeoChat</name>
<name xml:lang="lv">NeoChat</name>
<name xml:lang="nl">NeoChat</name> <name xml:lang="nl">NeoChat</name>
<name xml:lang="nn">NeoChat</name> <name xml:lang="nn">NeoChat</name>
<name xml:lang="pa">ਨਿਓ-ਚੈਟ</name> <name xml:lang="pa">ਨਿਓ-ਚੈਟ</name>
@@ -42,7 +39,6 @@
<name xml:lang="pt">NeoChat</name> <name xml:lang="pt">NeoChat</name>
<name xml:lang="pt-BR">NeoChat</name> <name xml:lang="pt-BR">NeoChat</name>
<name xml:lang="ru">NeoChat</name> <name xml:lang="ru">NeoChat</name>
<name xml:lang="sa">नवचैट्</name>
<name xml:lang="sk">NeoChat</name> <name xml:lang="sk">NeoChat</name>
<name xml:lang="sl">NeoChat</name> <name xml:lang="sl">NeoChat</name>
<name xml:lang="sv">NeoChat</name> <name xml:lang="sv">NeoChat</name>
@@ -52,95 +48,81 @@
<name xml:lang="x-test">xxNeoChatxx</name> <name xml:lang="x-test">xxNeoChatxx</name>
<name xml:lang="zh-CN">NeoChat</name> <name xml:lang="zh-CN">NeoChat</name>
<name xml:lang="zh-TW">NeoChat</name> <name xml:lang="zh-TW">NeoChat</name>
<summary>Chat on Matrix</summary> <summary>Chat with your friends on matrix</summary>
<summary xml:lang="ar">دردش على ماتركس</summary> <summary xml:lang="ar">دردش مع أصدقائك على ماتركس</summary>
<summary xml:lang="ca">Xat a Matrix</summary> <summary xml:lang="ca">Xategeu amb els vostres amics a Matrix</summary>
<summary xml:lang="ca-valencia">Xat a Matrix</summary> <summary xml:lang="ca-valencia">Xategeu amb els vostres amics a Matrix</summary>
<summary xml:lang="de">Über Matrix unterhalten</summary> <summary xml:lang="cs">Mluvte se svými přáteli na Matrixu</summary>
<summary xml:lang="en-GB">Chat on Matrix</summary> <summary xml:lang="eo">Babilu kun viaj amikoj sur matrix</summary>
<summary xml:lang="eo">Babilo en Matrix</summary> <summary xml:lang="es">Charle con sus amigos en matrix</summary>
<summary xml:lang="es">Charle en Matrix</summary> <summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary>
<summary xml:lang="eu">Berriketa Matrix-en</summary> <summary xml:lang="fi">Keskustelu ystäviesi kanssa Matrixissa</summary>
<summary xml:lang="fi">Keskustelu Matrixissä</summary> <summary xml:lang="fr">Discuter avec vos ami(e)s sur le réseau Matrix</summary>
<summary xml:lang="fr">Discuter sur Matrix</summary> <summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary>
<summary xml:lang="gl">Charlar en Matrix</summary> <summary xml:lang="hu">Csevegjen barátaival a matrixon</summary>
<summary xml:lang="he">התכתבות דרך Matrix</summary> <summary xml:lang="ia">Starta Conversation con tu amicos sur matrix</summary>
<summary xml:lang="hi">मैट्रिक्स पर चैट करें</summary> <summary xml:lang="it">Conversa con i tuoi contatti su matrix</summary>
<summary xml:lang="hu">Csevegés Matrixon</summary> <summary xml:lang="ka">ესაუბრეთ მეგობრებს Matrix-ზე</summary>
<summary xml:lang="ia">Conversation en ditecto sur Matrix</summary> <summary xml:lang="ko">Matrix를 사용하여 친구들과 대화하기</summary>
<summary xml:lang="it">Chat su Matrix</summary> <summary xml:lang="nl">Met uw vrienden chatten op matrix</summary>
<summary xml:lang="ka">ისაუბრეთ Matrix-ზე</summary> <summary xml:lang="nn">Prat med vennar på Matrix</summary>
<summary xml:lang="lv">Tērzējiet „Matrix“ tīklā</summary> <summary xml:lang="pl">Rozmawiaj ze swoimi znajomymi w Matriksie</summary>
<summary xml:lang="nl">Chat op Matrix</summary> <summary xml:lang="sl">Klepet z vašimi prijatelji na matrixu</summary>
<summary xml:lang="nn">Prat med via Matrix</summary> <summary xml:lang="sv">Chatta med dina vänner på Matrix</summary>
<summary xml:lang="pl">Rozmawiaj na Matriksie</summary> <summary xml:lang="ta">மேட்ரிக்ஸு மூலம் உங்கள் நண்பர்களிடம் பேசலாம்</summary>
<summary xml:lang="sa">Matrix इत्यत्र गपशपं कुर्वन्तु</summary> <summary xml:lang="tr">Matrixte arkadaşlarınızla sohbet edin</summary>
<summary xml:lang="sl">Klepet na Matrixu</summary> <summary xml:lang="uk">Спілкуйтеся з вашими друзями у matrix</summary>
<summary xml:lang="sv">Chatta på Matrix</summary> <summary xml:lang="x-test">xxChat with your friends on matrixxx</summary>
<summary xml:lang="ta">மேட்ரிக்ஸுக்கான உரையாடல் செயலி</summary> <summary xml:lang="zh-CN">在 Matrix 上与朋友聊天</summary>
<summary xml:lang="tr">Matrix Üzerinde Sohbet</summary> <summary xml:lang="zh-TW">Matrix 上與您的朋友聊天</summary>
<summary xml:lang="uk">Спілкування у Matrix</summary>
<summary xml:lang="x-test">xxChat on Matrixxx</summary>
<summary xml:lang="zh-TW">在 Matrix 上聊天</summary>
<description> <description>
<p>NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p> <p>NeoChat is a client for Matrix, the decentralized communication protocol for instant messaging. It allows you to send text messages, videos and audio files to your family, colleagues and friends. It uses KDE frameworks and most notably Kirigami
<p xml:lang="ar">نيوتشات هو تطبيق دردشة يتيح لك الاستفادة الكاملة من شبكة Matrix. فهو يوفر لك طريقة آمنة لإرسال الرسائل النصية ومقاطع الفيديو والملفات الصوتية إلى عائلتك وزملائك وأصدقائك.</p> to provide a convergent experience across multiple platforms.</p>
<p xml:lang="ca">El NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p> <p xml:lang="ar">نيوتشات هو عميل ماتركس Matrix، (ميفاق الاتصال اللامركزي للمراسلة الفورية). يتيح لك نيوتشات إرسال رسائل نصية ومقاطع فيديو وملفات صوتية إلى عائلتك وزملائك وأصدقائك. يستخدم أطر عمل كيدي وأبرزها Kirigami لتوفير تجربة متقاربة عبر منصات متعددة.</p>
<p xml:lang="ca-valencia">NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p> <p xml:lang="ca">El NeoChat és un client de Matrix, el protocol descentralitzat de comunicacions de missatgeria instantània. Permet enviar missatges de text, fitxers de vídeo i d'àudio a la família, col·legues i amics. Fa servir els Frameworks de KDE i, sobretot, el Kirigami per a proporcionar una experiència convergent a través de diverses plataformes.</p>
<p xml:lang="de">NeoChat ist eine Anwendung für Unterhaltungen mit allen Vorteilen des Matrix-Netzwerkes. Sie bietet eine sichere Möglichkeit zum Versenden von Nachrichten, Videos und Audiodateien and die Familienmitglieder.</p> <p xml:lang="ca-valencia">NeoChat és un client de Matrix, el protocol descentralitzat de comunicacions de missatgeria instantània. Permet enviar missatges de text, fitxers de vídeo i d'àudio a la família, col·legues i amics. Utilitza els Frameworks de KDE i, sobretot, Kirigami per a proporcionar una experiència convergent a través de diverses plataformes.</p>
<p xml:lang="el">Το NeoChat είναι μια εφαρμογή συνομιλίας που σας επιτρέπει να εκμεταλλευτείτε πλήρως το δίκτυο Matrix. Σας παρέχει έναν ασφαλή τρόπο να στέλνετε μηνύματα κειμένου, βίντεο και αρχεία ήχου στην οικογένεια, τους συναδέλφους και τους φίλους σας.</p> <p xml:lang="en-GB">NeoChat is a client for Matrix, the decentralised communication protocol for instant messaging. It allows you to send text messages, videos and audio files to your family, colleagues and friends. It uses KDE frameworks and most notably Kirigami to provide a convergent experience across multiple platforms.</p>
<p xml:lang="en-GB">NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p> <p xml:lang="eo">NeoChat estas kliento por Matrix, la malcentra komunikoprotokolo por tuja mesaĝado. Ĝi ebligas al vi sendi tekstmesaĝojn, filmetojn kaj sondosierojn al via familio, kolegoj kaj amikoj. Ĝi uzas KDE-framojn kaj precipe Kirigami por disponigi konverĝan sperton tra pluraj platformoj.</p>
<p xml:lang="eo">NeoChat estas babilej-apo, kiu ebligas al vi plene profiti de la Matrix-reto. Ĝi provizas al vi sekuran manieron sendi tekstmesaĝojn, filmetojn kaj sondosierojn al via familio, kolegoj kaj amikoj.</p> <p xml:lang="es">NeoChat es un cliente para Matrix, el protocolo de comunicaciones descentralizado para mensajería instantánea. Le permite enviar mensajes de texto, vídeos y archivos de sonido a su familia, compañeros de trabajo y amigos. Usa la infraestructura de KDE y, en particular, Kirigami para proporcionar una experiencia convergente en muchas plataformas.</p>
<p xml:lang="es">NeoChat es una aplicación de chat que le permite aprovechar al máximo la red Matrix. Le proporciona un modo seguro de enviar mensajes de texto, vídeos y archivos de sonido a su familia, colegas y amigos.</p> <p xml:lang="eu">NeoChat «Matrix»erako, bat-bateko mezularitzarako komunikazio deszentralizatuko protokolorako, bezero bat da. Zure sendiari, kide eta lagunei testu mezuak, bideo eta audio fitxategiak bidaltzeko aukera ematen dizu. «KDE Frameworks» eta bereziki «Kirigami» erabiltzen ditu plataforma anitzen artean esperientzia konbergente bat eskaintzeko.</p>
<p xml:lang="eu">NeoChat, Matrix sarearen abantaila guztiei probetsua ateratzeko aukera ematen dizun berriketa aplikaizo bat da. Zure familiari, kideei eta lagunei testu mezuak, bideoak eta audio fitxategiak era seguruan bidaltzeko aukera ematen dizu.</p> <p xml:lang="fi">NeoChat on asiakassovellus Matrixille, hajautetulle pikaviestinyhteyskäytännölle. Sillä voi lähettää teksti-, video- ja ääniviestejä perheelle, tutuille ja ystäville. Se käyttää KDE-kehystä ja erityisesti Kirigamia tuottaakseen mukautuvan monialustaisen käyttökokemuksen.</p>
<p xml:lang="fi">NeoChat on keskustelusovellus, jolla Matrix-verkosta saa täyden hyödyn. Se tarjoaa salatun kanavan lähettää perheelle, työkavereille ja ystäville tekstiviestejä sekä video- ja äänitiedostoja.</p> <p xml:lang="fr">NeoChat est un client pour le protocole Matrix, un protocole décentralisé de communications pour messagerie instantané. Il vous permet d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos amis. Il utilise les environnements de développement et plus précisément Kirigami pour fournir une expérience convergente sur plusieurs plate-formes. </p>
<p xml:lang="fr">NeoChat est une application de discussions vous permettant de profiter pleinement du réseau Matrix. Elle vous offre un moyen sécurisé d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos ami(e)s.</p> <p xml:lang="gl">NeoChat é un cliente para Matrix, o protocolo de comunicación descentralizada para mensaxaría instantánea. Podes enviar mensaxes de texto, vídeos e ficheiros de son á túa familia, colegas e amizades. Usas infraestruturas de KDE e principalmente Kirigami para proporcionar unha experiencia de uso converxente para varias plataformas.</p>
<p xml:lang="gl">NeoChat é unha aplicación de conversa que lle permite usar todas as funcionalidades da rede Matrix. Fornece unha forma segura de enviar mensaxes de texto e ficheiros de vídeo e son a familiares, amizades ou no traballo.</p> <p xml:lang="hu">A NeoChat egy kliens a Matrixhoz, az azonnali üzenetküldés decentralizált komunikációs protokolljához. Szöveges üzeneteket, videókat és hangfájlokat küldhet családjának, kollégáinak és barátainak. A KDE keretrendszert használja, a Kirigaminak köszönhetően konvergens élményt nyújt több platformon is.</p>
<p xml:lang="he">NeoChat הוא יישום התכתבות שמאפשר לך לנצל את רשת Matrix במלואה. הוא מספק דרך מאובטחת לשליחת הודעות כתובות, סרטונים וקובצי שמע למשפחה, לעמיתים לעבודה ולחברים.</p> <p xml:lang="ia">NeoChat es un cliente per Matrix, le protocollo de communication decentralisate per messager instantanee. Illo te permitte inviar messager de texto, files de video e audio a tu familia, collegas e amicos usante. Illo usa KDE frameworks e super toto Kirigamii forni un experientia convergente trans platteforme multiple.</p>
<p xml:lang="hi">नियोचैट एक चैट ऐप है जो आपको मैट्रिक्स नेटवर्क का पूरा लाभ उठाने देता है। यह आपको अपने परिवार, सहकर्मियों और दोस्तों को टेक्स्ट संदेश, वीडियो और ऑडियो फ़ाइलें भेजने का एक सुरक्षित तरीका प्रदान करता है।</p> <p xml:lang="it">NeoChat è un client per Matrix, il protocollo di comunicazione decentralizzato per la messaggistica istantanea. Ti consente di inviare messaggi di testo, video e file audio a familiari, colleghi e amici. Utilizza i framework KDE e in particolare Kirigami per fornire un'esperienza convergente su più piattaforme.</p>
<p xml:lang="hu">A NeoChat egy olyan csevegőalkalmazás, amellyel teljes mértékben kihasználhatja a Matrix hálózatot. Biztonságos módot biztosít szöveges üzenetek, videók és hangfájlok küldéséhez családtagjainak, kollégáinak és barátainak.</p> <p xml:lang="ka">NeoChat არის Matrix კლიენტი. ის საშუალებას გაძლევთ გაგზავნოთ ტექსტური შეტყობინებები, ვიდეოები და აუდიო ფაილები თქვენს ოჯახს, კოლეგებსა და მეგობრებს მატრიქსის პროტოკოლის გამოყენებით.</p>
<p xml:lang="ia">NeoChat es un app de conversation que te permitte prender avantage plen del rete Matrix. Il te forni un modo secur de inviar messages de texto, videos e files audio a tui familia, collegas e amicos.</p> <p xml:lang="ko">NeoChat은 분산형 인스턴트 메시징 통신 프로토콜인 Matrix 클라이언트입니다. 가족, 동료, 친구에게 텍스트 메시지, 동영상, 오디오 파일을 전송할 수 있습니다. KDE 프레임워크와 Kirigami를 사용하여 다양한 플랫폼에서 일관적인 사용자 경험을 제공합니다.</p>
<p xml:lang="it">NeoChat è un'applicazione di chat che ti consente di sfruttare appieno la rete Matrix. Ti fornisce un modo sicuro per inviare messaggi di testo, video e file audio a familiari, colleghi e amici.</p> <p xml:lang="nl">NeoChat is een client voor Matrix, het gedecentraliseerde communicatieprotocol voor instant messages. Het biedt u het verzenden van tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden. Het gebruik KDE frameworks en het meest opmerkelijk Kirigami om een convergente ervaring te leveren op meerdere platforms.</p>
<p xml:lang="ka">NeoChat ჩატის აპია, რომელიც საშუალება გაძლევთ, Matrix-ის ქსელის საშუალებები ბოლომდე გამოიყენოთ. ის გაძლევთ უსაფრთხო გზას, გააგზავნოთ ტექსტური შეტყობინებები, ვიდეოებ და აუდიოფაილები თქვენს ოჯახთან, კოლეგებთან და მეგობრებთან.</p> <p xml:lang="nn">NeoChat er ein klient for Matrix, ein protokoll for desentralisert kommunikasjon. Du kan utveksla tekst, lyd og videoar med kollegaar, vennar og familie. Programmet brukar KDE Frameworks og Kirigami for å gje ei brukarflate tilpassa ulike plattformer.</p>
<p xml:lang="lv">NeoChat“ ir tērzēšanas programma, kas ļauj pilnvērtīgi izmantot „Matrix“ tīklu. Tā sniedz drošu veidu teksta ziņu, video un audio sūtīšanai ģimenes locekļiem, kolēģiem un draugiem.</p> <p xml:lang="pl">NeoChat jest programem do Matriksa, protokołu rozproszonego porozumiewania się w czasie rzeczywistym. Umożliwia wysyłanie wiadomości tekstowych, filmów oraz dźwięku do twojej rodziny, znajomych oraz przyjaciół. Używa szkieletów KDE i głównie Kirigami, aby zapewnić spójne wrażenia na wielu platformach</p>
<p xml:lang="nl">NeoChat is een chat-toepassing die u het volledige voordeel van het Matrix-netwerk laat genieten. Het levert u op een veilige manier tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden te verzenden.</p> <p xml:lang="pt">O NeoChat é um cliente do Matrix. O mesmo permite-lhe enviar mensagens de texto, ficheiros de vídeo e áudio para a sua família, colegas e amigos com o protocolo Matrix. Usa as plataformas do KDE, e principalmente o Kirigami, para oferecer uma experiência convergente entre várias plataformas.</p>
<p xml:lang="nn">NeoChat er ein prateapp som lèt deg bruka all funksjonalitet i Matrix-nettverket. Du kan utveksla tekst, lyd og videoar med vennar, familie og kollegaar på ein trygg måte.</p> <p xml:lang="sl">Neochat je odjemalec za Matrix, decentralizirani komunikacijski protokol za takojšnje sporočanje. Omogoča vam pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek svoji družini, sodelavcem in prijateljem. Uporablja okvire ogrodje KDE frameworks in predvsem Kirigami za zagotavljanje konvergentne izkušnje na več platformah.</p>
<p xml:lang="pl">NoeChat to aplikacja do rozmów, która umożliwia wykorzystanie wszystkich możliwości Matriksa. Umożliwia wysyłanie wiadomości tekstowych, filmów i dźwięków w bezpieczny sposób do twojej rodziny, kolegów i przyjaciół.</p> <p xml:lang="sv">NeoChat är en klient för Matrix, det decentraliserade kommunikationsprotokollet för direktmeddelanden. Den låter dig skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner. Den använder KDE Ramverk, i synnerhet Kirigami, för att tillhandahålla en konvergent upplevelse på flera plattformar.</p>
<p xml:lang="ru">NeoChat — приложение для общения, предоставляющее все преимущества сети Matrix. С его помощью можно безопасно отправлять текстовые сообщения, видеозаписи и звуковые файлы родственникам, коллегам и друзьям.</p> <p xml:lang="tr">NeoChat, anlık iletileşme için merkezi olmayan iletişim protokolü olan Matrix için bir istemcidir. Ailenize, iş arkadaşlarınıza ve arkadaşlarınıza metin iletiler, videolar ve ses dosyaları göndermenize olanak tanır. Birden çok platformda yakınsak bir deneyim sağlamak için KDE Frameworks ve en önemlilerinden Kirigami'yi kullanır.</p>
<p xml:lang="sa">NeoChat इति एकं गपशप-अनुप्रयोगं यत् भवान् Matrix-जालस्य पूर्णं लाभं ग्रहीतुं शक्नोति । एतत् भवन्तं भवतः परिवाराय, सहकारिभ्यः, मित्रेभ्यः च पाठसन्देशान्, भिडियो, श्रव्यसञ्चिकाः च प्रेषयितुं सुरक्षितं मार्गं प्रदाति ।</p> <p xml:lang="uk">NeoChat — клієнт Matrix, децентралізованого протоколу спілкування для миттєвого обміну повідомленнями. За його допомогою ви можете надсилати текстові повідомлення, відео та звукові файли вашій родин, колегами та друзям. У програмі використано бібліотеки KDE, зокрема Kirigami, для надання однорідного середовища на декількох програмних та апаратних платформах.</p>
<p xml:lang="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p> <p xml:lang="x-test">xxNeoChat is a client for Matrix, the decentralized communication protocol for instant messaging. It allows you to send text messages, videos and audio files to your family, colleagues and friends. It uses KDE frameworks and most notably Kirigami to provide a convergent experience across multiple platforms.xx</p>
<p xml:lang="sv">NeoChat är ett chattprogram som låter dig dra full nytta av Matrix-nätverket. Det ger dig ett säkert sätt att skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner.</p> <p xml:lang="zh-TW">NeoChat 是去中心化即時通訊協定 Matrix 的一個用戶端。它讓您可以傳送文字訊息、影片、音訊檔案給您的家人、同事或朋友。NeoChat 使用 KDE frameworks尤其是 Kirigami來提供跨平台的響應式體驗。</p>
<p xml:lang="tr">NeoChat, Matrix ağının tüm özelliklerini kullanan bir sohbet uygulamasıdır. Ailenize, arkadaşlarınıza ve iş arkadaşlarınıza metin iletileri, ses ve video dosyaları göndermenin kolay bir yolunu sunar.</p>
<p xml:lang="uk">NeoChat є програмою для спілкування, за допомогою якої ви можете скористатися усіма перевагами мережі Matrix. За її допомогою ви можете безпечно надсилати текстові повідомлення, відео та звукові файли вашим родичам, колегам та друзям.</p>
<p xml:lang="x-test">xxNeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.xx</p>
<p xml:lang="zh-TW">NeoChat 是一個讓您能夠完全利用 Matrix 網路的聊天應用程式。它讓您安全地傳送文字訊息、影片或音訊檔給家人、同事或朋友等等。</p>
<p>NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p> <p>NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p>
<p xml:lang="ar">يهدف نيوتشات إلى أن يكون تطبيقًا كامل الميزات لمواصفات ماتركس. على هذا النحو يتم دعم كل شيء في المواصفات المستقرة الحالية مع الاستثناءات الملحوظة لـ VoIP والخيوط وبعض جوانب التشفير من طرف إلى طرف. هناك عدد قليل من الإغفالات الصغيرة الأخرى بسبب حقيقة أن مواصفات ماتركس تتطور باستمرار ، ولكن يبقى الهدف توفير الدعم النهائي للمواصفات بأكملها.</p> <p xml:lang="ar">يهدف نيوتشات إلى أن يكون تطبيقًا كامل الميزات لمواصفات ماتركس. على هذا النحو يتم دعم كل شيء في المواصفات المستقرة الحالية مع الاستثناءات الملحوظة لـ VoIP والخيوط وبعض جوانب التشفير من طرف إلى طرف. هناك عدد قليل من الإغفالات الصغيرة الأخرى بسبب حقيقة أن مواصفات ماتركس تتطور باستمرار ، ولكن يبقى الهدف توفير الدعم النهائي للمواصفات بأكملها.</p>
<p xml:lang="ca">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptatge d'extrem a extrem. Hi ha algunes altres omissions més petites a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu segueix sent proporcionar suport eventual per a tota l'especificació.</p> <p xml:lang="ca">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptatge d'extrem a extrem. Hi ha algunes altres omissions més petites a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu segueix sent proporcionar suport eventual per a tota l'especificació.</p>
<p xml:lang="ca-valencia">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptació d'extrem a extrem. Hi ha algunes altres omissions més xicotetes a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu seguix sent proporcionar suport eventual per a tota l'especificació.</p> <p xml:lang="ca-valencia">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptació d'extrem a extrem. Hi ha algunes altres omissions més xicotetes a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu seguix sent proporcionar suport eventual per a tota l'especificació.</p>
<p xml:lang="de">NeoChat versucht eine vollumfängliche Anwendung für die Spezifikation von Matrix zu sein. Damit wird alles der aktuellen stabilen Spezifikation mit den erwähnenswerten Ausnahmen von VoIP, Diskussionsfäden und ein paar Teilen der Ende-zu-Ende-Verschlüsselung unterstützt. Zudem sind andere kleinere Auslassungen vorhanden, da sich die Matrixspezifikation ständig weiterentwickelt. Nichtsdestotrotz soll letztendlich die gesamte Spezifikation unterstützt werden.</p>
<p xml:lang="el">Το NeoChat στοχεύει να είναι μια πλήρως εξοπλισμένη εφαρμογή για τις προδιαγραφές Matrix. Ως εκ τούτου, υποστηρίζονται όλα τα στοιχεία της τρέχουσας σταθερής προδιαγραφής με τις αξιοσημείωτες εξαιρέσεις του VoIP, των νημάτων και ορισμένων πτυχών της κρυπτογράφησης στα άκρα. Υπάρχουν μερικές άλλες μικρότερες παραλείψεις που οφείλονται στο γεγονός ότι η προδιαγραφή Matrix εξελίσσεται συνεχώς, αλλά ο στόχος παραμένει να παρέχεται τελικά υποστήριξη για ολόκληρη την προδιαγραφή.</p>
<p xml:lang="en-GB">NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p> <p xml:lang="en-GB">NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p>
<p xml:lang="eo">NeoChat celas esti plene kapabla aplikaĵo por la Matrix-specifo. Kiel tia, ĉio en la nuna stabila specifo kun la rimarkindaj esceptoj de VoIP, fadenoj kaj kelkaj aspektoj de Fin-al-Fina Ĉifrado estas subtenataj. Estas kelkaj aliaj pli malgrandaj preterlasoj pro la fakto, ke la Matrix-speco konstante evoluas, sed la celo restas provizi finfine subtenon por la tuta specifaĵo.</p> <p xml:lang="eo">NeoChat celas esti plene kapabla aplikaĵo por la Matrix-specifo. Kiel tia, ĉio en la nuna stabila specifo kun la rimarkindaj esceptoj de VoIP, fadenoj kaj kelkaj aspektoj de Fin-al-Fina Ĉifrado estas subtenataj. Estas kelkaj aliaj pli malgrandaj preterlasoj pro la fakto, ke la Matrix-speco konstante evoluas, sed la celo restas provizi finfine subtenon por la tuta specifaĵo.</p>
<p xml:lang="es">NeoChat pretende ser una aplicación con todas las funciones para la especificación de Matrix. Como tal, admite todo en la especificación estable actual, con las notables excepciones de VoIP, subprocesos y algunas funciones de cifrado de extremo a extremo. Existen algunas omisiones menos importantes debido al hecho de que la especificación de Matrix está en constante evolución, pero el objetivo sigue siendo brindar compatibilidad final con toda la especificación.</p> <p xml:lang="es">NeoChat pretende ser una aplicación con todas las funciones para la especificación de Matrix. Como tal, admite todo en la especificación estable actual, con las notables excepciones de VoIP, subprocesos y algunas funciones de cifrado de extremo a extremo. Existen algunas omisiones menos importantes debido al hecho de que la especificación de Matrix está en constante evolución, pero el objetivo sigue siendo brindar compatibilidad final con toda la especificación.</p>
<p xml:lang="eu">«NeoChat»ek «Matrix» zehaztapenaren ezaugarri guztiak eskaintzen dituen aplikazio bat izan nahi du. Beraz, egungo zehaztapen egonkorrean dagoen guztiaren euskarria du, VoIP, hariak eta muturren artean zifratzeko salbuespen nabarmenekin. Badira beste ez-betetze txikiago batzuk, «Matrix»en zehaztapena etengabe eboluzioan dagoelako, baina azken helburua zehaztapen osoaren euskarria ematea izaten jarraitzen du.</p> <p xml:lang="eu">«NeoChat»ek «Matrix» zehaztapenaren ezaugarri guztiak eskaintzen dituen aplikazio bat izan nahi du. Beraz, egungo zehaztapen egonkorrean dagoen guztiaren euskarria du, VoIP, hariak eta muturren artean zifratzeko salbuespen nabarmenekin. Badira beste ez-betetze txikiago batzuk, «Matrix»en zehaztapena etengabe eboluzioan dagoelako, baina azken helburua zehaztapen osoaren euskarria ematea izaten jarraitzen du.</p>
<p xml:lang="fi">NeoChat pyrkii olemaan Matrix-määritelmän täysominaisuuksinen sovellus, joten se tukee kaikkea nykyisessä vakaassa määritelmässä muutamaa huomattavaa poikkeusta lukuun ottamatta (VoIP, säikeet ja jotkin piirteet päästä päähän -salauksessa). Joitakin pienempiäkin puutteita on Matrix-määritelmän jatkuvan kehityksen vuoksi, mutta lopputavoitteena on tarjota määritelmän täysi tuki.</p> <p xml:lang="fi">NeoChat pyrkii olemaan Matrix-määritelmän täysominaisuuksinen sovellus, joten se tukee kaikkea nykyisessä vakaassa määritelmässä muutamaa huomattavaa poikkeusta lukuun ottamatta (VoIP, säikeet ja jotkin piirteet päästä päähän -salauksessa). Joitakin pienempiäkin puutteita on Matrix-määritelmän jatkuvan kehityksen vuoksi, mutta lopputavoitteena on tarjota määritelmän täysi tuki.</p>
<p xml:lang="fr">L'objectif de NeoChat est d'être une application complète pour le protocole Matrix. En tant que tel, tout dans la spécification stable actuelle avec les exceptions notables de VoIP, les processus et certains aspects du chiffrement de bout en bout sont pris en charge. Il y a quelques autres petites omissions en raison du fait que la spécification du protocole Matrix est en constante évolution. Cependant, l'objectif reste de fournir un soutien éventuel pour l'ensemble de la spécification.</p> <p xml:lang="fr">L'objectif de NeoChat est d'être une application complète pour le protocole Matrix. En tant que tel, tout dans la spécification stable actuelle avec les exceptions notables de VoIP, les processus et certains aspects du chiffrement de bout en bout sont pris en charge. Il y a quelques autres petites omissions en raison du fait que la spécification du protocole Matrix est en constante évolution. Cependant, l'objectif reste de fournir un soutien éventuel pour l'ensemble de la spécification.</p>
<p xml:lang="gl">NeoChat pretende ser unha aplicación completa para a especificación de Matrix. Coas excepcións de VoIP, conversas fiadas e algúns aspectos da cifraxe de extremo a extremo, a versión estábel segue as especificacións. Existen algunhas outras pequenas omisións debido ao feito de que Matrix está en continua evolución pero a intención é fornecer compatibilidade coa especificación completa.</p> <p xml:lang="gl">NeoChat pretende ser unha aplicación completa para a especificación de Matrix. Coas excepcións de VoIP, conversas fiadas e algúns aspectos da cifraxe de extremo a extremo, a versión estábel segue as especificacións. Existen algunhas outras pequenas omisións debido ao feito de que Matrix está en continua evolución pero a intención é implementar a especificación completa.</p>
<p xml:lang="he">NeoChat מתיימר להיות יישום עתיר יכולות לפי מפרט Matrix. כיוון שזה ייעודו, כל מה שבמפרט היציב עם חריגות משמעותיות כגון VoIP, שרשורים ועוד מגוון היבטים של הצפנה מקצה לקצה נתמכים גם הם. יש מספר השמטות קטן עקב העובדה שהמפרט של Matrix ממשיך להתפתח אך המטרה היא להמשיך לספק תמיכה בסופו של דבר לכל המפרט.</p>
<p xml:lang="hi">नियोचैट का लक्ष्य मैट्रिक्स विनिर्देश के लिए एक पूर्ण विशेषताओं वाला अनुप्रयोग बनना है। इस प्रकार वर्तमान स्थिर विनिर्देश में वीओआईपी, थ्रेड्स और एंड-टू-एंड एन्क्रिप्शन के कुछ पहलुओं के उल्लेखनीय अपवादों के साथ सब कुछ समर्थित है। मैट्रिक्स विनिर्देश लगातार विकसित हो रहा है, इस तथ्य के कारण कुछ अन्य छोटी चूकें हैं, लेकिन उद्देश्य पूरे विनिर्देश के लिए अंतिम समर्थन प्रदान करना है।</p>
<p xml:lang="hu">A NeoChat célja, hogy a Matrix specifikációnak megfelelő teljes funkcionalitású alkalmazás legyen. Mint ilyen, a jelenlegi stabil specifikáció támogatott a VoIP, a szálak és a végpontok közötti titkosítás egyes elemeinek kivételével. Van még néhány kisebb hiányosság annak köszönhetően, hogy a Matrix specifikáció folyamatosan fejlődik, de végső cél a teljes specifikáció megvalósítása.</p> <p xml:lang="hu">A NeoChat célja, hogy a Matrix specifikációnak megfelelő teljes funkcionalitású alkalmazás legyen. Mint ilyen, a jelenlegi stabil specifikáció támogatott a VoIP, a szálak és a végpontok közötti titkosítás egyes elemeinek kivételével. Van még néhány kisebb hiányosság annak köszönhetően, hogy a Matrix specifikáció folyamatosan fejlődik, de végső cél a teljes specifikáció megvalósítása.</p>
<p xml:lang="ia">NeoChat aspira a esser un application plenmente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p> <p xml:lang="ia">NeoChat aspira a esser un application plenemente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p>
<p xml:lang="it">NeoChat mira ad essere un'applicazione completa per le specifiche Matrix. Pertanto, sono supportati tutti gli elementi dell'attuale specifica stabile con le notevoli eccezioni di VoIP, conversazioni e alcuni aspetti della cifratura end-to-end. Ci sono alcune altre piccole omissioni dovute al fatto che le specifiche Matrix sono in continua evoluzione, ma l'obiettivo rimane quello di fornire un eventuale supporto per l'intera specifica.</p> <p xml:lang="it">NeoChat mira ad essere un'applicazione completa per le specifiche Matrix. Pertanto, sono supportati tutti gli elementi dell'attuale specifica stabile con le notevoli eccezioni di VoIP, conversazioni e alcuni aspetti della cifratura end-to-end. Ci sono alcune altre piccole omissioni dovute al fatto che le specifiche Matrix sono in continua evoluzione, ma l'obiettivo rimane quello di fornire un eventuale supporto per l'intera specifica.</p>
<p xml:lang="ka">NeoChat მიზნად ისახავს Matrix სპეციფიკაციის სრული განხორციელება ჰქონდეს. როგორც ასეთი, ყველაფერი მიმდინარე სპეციფიკაციიდან, VoIP-ის, ძაფებისა და გამჭოლი დაშიფვრის ზოგიერთი ასპექტის გარდა, მხარდაჭერილია. შეძლება ასევე იყოს მცირე ლაფსუსებიც იმის გამო, რომ Matrix-ის სპეციფიკაცია მუდმივად ვითარდება, მაგრამ ჩვენი მიზანი მისი სრული მხარდაჭერაა.</p> <p xml:lang="ka">NeoChat-ი მიზნად ისახავს Matrix სპეციფიკაციის სრული განხორციელება ჰქონდეს. როგორც ასეთი, ყველაფერი მიმდინარე სპეციფიკაციიდან, VoIP-ის, ძაფებისა და გამჭოლი დაშიფვრის ზოგიერთი ასპექტის გარდა, მხარდაჭერილია. შეძლება ასევე იყოს მცირე ლაფსუსებიც იმის გამო, რომ Matrix-ის სპეციფიკაცია მუდმივად ვითარდება, მაგრამ ჩვენი მიზანი მისი სრული მხარდაჭერაა.</p>
<p xml:lang="ko">NeoChat은 Matrix 표준을 따르는 프로그램을 목표로 합니다. 현재 안정 버전의 표준에서 제공하는 기능의 대부분을 지원하며, VoIP, 스레드, 일부 종단간 암호화와 같은 기능은 아직 지원하지 않습니다. Matrix 표준은 계속하여 진화 중이기 때문에 일부 기능이 빠져 있을 수도 있지만 장기적으로는 전체 표준을 지원하는 것이 목표입니다.</p> <p xml:lang="ko">NeoChat은 Matrix 표준을 따르는 프로그램을 목표로 합니다. 현재 안정 버전의 표준에서 제공하는 기능의 대부분을 지원하며, VoIP, 스레드, 일부 종단간 암호화와 같은 기능은 아직 지원하지 않습니다. Matrix 표준은 계속하여 진화 중이기 때문에 일부 기능이 빠져 있을 수도 있지만 장기적으로는 전체 표준을 지원하는 것이 목표입니다.</p>
<p xml:lang="lv">„NeoChat“ mērķis ir piedāvāt plašas iespējas atbilstoši „Matrix“ specifikācijai. Līdz ar to programma atbalsta visu pašreizējā stabilajā specifikācijā, izņemot VoIP, pavedienus un dažos aspektos galšifrēšanu. Pastāv citas atsevišķas sīkas neieviestas daļas, jo „Matrix“ specifikācija nepārtraukti attīstās, tomēr mērķis ir ar laiku nodrošināt atbalstu pilnai specifikācijai.</p>
<p xml:lang="nl">NeoChat richt zich op het volledig bieden van alle mogelijkheden van de Matrix-specificatie. Alles in de huidige stabiele specificatie met merkbare uitzondering van VoIP, gekoppelde discussies en sommige aspecten van eind-tot-eind versleuteling worden ondersteund. Er zijn een paar andere kleinere omissies vanwege het feit dat de Matrix specificatie constant evolueert maar het doel blijft het eventueel bieden van ondersteuning van de gehele specificatie.</p> <p xml:lang="nl">NeoChat richt zich op het volledig bieden van alle mogelijkheden van de Matrix-specificatie. Alles in de huidige stabiele specificatie met merkbare uitzondering van VoIP, gekoppelde discussies en sommige aspecten van eind-tot-eind versleuteling worden ondersteund. Er zijn een paar andere kleinere omissies vanwege het feit dat de Matrix specificatie constant evolueert maar het doel blijft het eventueel bieden van ondersteuning van de gehele specificatie.</p>
<p xml:lang="nn">NeoChat har som mål å støtta all funksjonalitet i Matrix-spesifikasjonen. Førebels er alt i den gjeldande stabile spesifikasjonen støtta, med unntak av VoIP, trådar og nokre delar av ende-til-kryptering. Det finst òg andre småting som ikkje er støtta, sidan Matrix-spesifikasjon er i stadig endring, men målet er altså støtte for alt.</p> <p xml:lang="nn">NeoChat har som mål å støtta all funksjonalitet i Matrix-spesifikasjonen. Førebels er alt i den gjeldande stabile spesifikasjonen støtta, med unntak av VoIP, trådar og nokre delar av ende-til-kryptering. Det finst òg andre småting som ikkje er støtta, sidan Matrix-spesifikasjon er i stadig endring, men målet er altså støtte for alt.</p>
<p xml:lang="pl">NeoChat w zamyśle ma być pełnowartościową aplikacją wg wytycznych Matriksa. Z tego powodu, wszystko, co jest obecnie w stabilnych wytycznych z pominięciem VoIP, wątków i niektórych części szyfrowania Użytkownik-do-Użytkownika są obecnie obsługiwane. Pominięto też kilka mniejszych rzeczy ze względu na ciągły rozwój wytycznych Matriksa, lecz celem nadal jest zapewnienie obsługi wszystkich wytycznych.</p> <p xml:lang="pl">NeoChat w zamyśle ma być pełnowartościową aplikacją wg wytycznych Matriksa. Z tego powodu, wszystko, co jest obecnie w stabilnych wytycznych z pominięciem VoIP, wątków i niektórych części szyfrowania Użytkownik-do-Użytkownika są obecnie obsługiwane. Pominięto też kilka mniejszych rzeczy ze względu na ciągły rozwój wytycznych Matriksa, lecz celem nadal jest zapewnienie obsługi wszystkich wytycznych.</p>
<p xml:lang="pt">O NeoChat pretende ser uma aplicação completa para a especificação do Matrix. Como tal, tudo o que existe na especificação estável actual, com as notáveis excepções do VoIP, tópicos e alguns aspectos da Encriptação Ponto-a-Ponto, são suportados. Existem mais algumas omissões, devido ao facto que a norma do Matrix está em constante evolução, mas o objectivo continua a ser oferecer o suporte eventual para a norma por inteiro.</p> <p xml:lang="pt">O NeoChat pretende ser uma aplicação completa para a especificação do Matrix. Como tal, tudo o que existe na especificação estável actual, com as notáveis excepções do VoIP, tópicos e alguns aspectos da Encriptação Ponto-a-Ponto, são suportados. Existem mais algumas omissões, devido ao facto que a norma do Matrix está em constante evolução, mas o objectivo continua a ser oferecer o suporte eventual para a norma por inteiro.</p>
<p xml:lang="ru">Целью создания NeoChat является полноценная реализация программы для спецификации Matrix. Как следствие, реализовано всё в текущей стабильной спецификации (за исключением голосовой интернет-связи, потоков и некоторых аспектов сквозного шифрования). Есть также несколько других незначительных пробелов, обусловленных постоянными изменениями спецификации Matrix. Тем не менее, стоит задача в итоге предоставить полную поддержку спецификации.</p>
<p xml:lang="sa">NeoChat इत्यस्य उद्देश्यं Matrix विनिर्देशस्य कृते पूर्णतया विशेषतायुक्तः अनुप्रयोगः भवितुम् अस्ति । यथा तथा वर्तमानस्थिरविनिर्देशे सर्वं VoIP इत्यस्य उल्लेखनीयअपवादैः सह, थ्रेड्स तथा च End-to-End Encryption इत्यस्य केचन पक्षाः समर्थिताः सन्ति । अन्ये कतिचन लघु लोपाः सन्ति यतोहि Matrix spec निरन्तरं विकसितः अस्ति परन्तु उद्देश्यं सम्पूर्ण spec कृते अन्ततः समर्थनं प्रदातुं अवशिष्टम् अस्ति</p>
<p xml:lang="sl">Neochat cilja, da bi bila popolna aplikacija po specifikaciji Matrixa. Kot takšna vsebuje vse v trenutni stabilni specifikaciji z pomembnimi izjemami pri VoIP, nitih in nekaterih vidikov šifriranja od konca do konca. Obstaja nekaj drugih manjših opustitev zaradi dejstva, da se specifikacija Matrix nenehno razvija, vendar cilj ostaja zagotoviti morebitno podporo celotni specifikaciji.</p> <p xml:lang="sl">Neochat cilja, da bi bila popolna aplikacija po specifikaciji Matrixa. Kot takšna vsebuje vse v trenutni stabilni specifikaciji z pomembnimi izjemami pri VoIP, nitih in nekaterih vidikov šifriranja od konca do konca. Obstaja nekaj drugih manjših opustitev zaradi dejstva, da se specifikacija Matrix nenehno razvija, vendar cilj ostaja zagotoviti morebitno podporo celotni specifikaciji.</p>
<p xml:lang="sv">NeoChat har som mål att vara ett fullständigt program enligt Matrix-specifikationen. Som sådant stöds allt i den nuvarande stabila specifikationen, med de nämnvärda undantagen VoIP, trådar och några aspekter av kryptering hela vägen. Det finns några ytterligare utelämnanden på grund av att Matrix-specifikationen hela tiden utvecklas, men målet förblir att till slut erbjuda stöd för hela specifikationen.</p> <p xml:lang="sv">NeoChat har som mål att vara ett fullständigt program enligt Matrix-specifikationen. Som sådant stöds allt i den nuvarande stabila specifikationen, med de nämnvärda undantagen VoIP, trådar och några aspekter av kryptering hela vägen. Det finns några ytterligare utelämnanden på grund av att Matrix-specifikationen hela tiden utvecklas, men målet förblir att till slut erbjuda stöd för hela specifikationen.</p>
<p xml:lang="tr">NeoChat, Matrix belirtimi için tam özellikli bir uygulama olmayı hedefler. Bu nedenle; VoIP, ileti zincirleri ve Uçtan Uca Şifrelemenin bazı yönleri gibi dikkate değer istisnalar dışında var olan kararlı belirtimdeki her şey desteklenir. Matrix belirtiminin sürekli gelişmesi nedeniyle birkaç küçük eksiklik daha var; ancak amaç tüm belirtim için nihai destek sağlamak olmayı sürdürüyor.</p> <p xml:lang="tr">NeoChat, Matrix belirtimi için tam özellikli bir uygulama olmayı hedefler. Bu nedenle; VoIP, ileti zincirleri ve Uçtan Uca Şifrelemenin bazı yönleri gibi dikkate değer istisnalar dışında var olan kararlı belirtimdeki her şey desteklenir. Matrix belirtiminin sürekli gelişmesi nedeniyle birkaç küçük eksiklik daha var; ancak amaç tüm belirtim için nihai destek sağlamak olmayı sürdürüyor.</p>
@@ -151,8 +133,6 @@
<p xml:lang="ar">نظرًا لطبيعة تطوير مواصفات ماتركس، يدعم نيوتشات أيضًا العديد من الميزات غير المستقرة وهي:</p> <p xml:lang="ar">نظرًا لطبيعة تطوير مواصفات ماتركس، يدعم نيوتشات أيضًا العديد من الميزات غير المستقرة وهي:</p>
<p xml:lang="ca">A causa de la naturalesa del desenvolupament de l'especificació de Matrix, el NeoChat també implementa nombroses característiques inestables. Actualment són:</p> <p xml:lang="ca">A causa de la naturalesa del desenvolupament de l'especificació de Matrix, el NeoChat també implementa nombroses característiques inestables. Actualment són:</p>
<p xml:lang="ca-valencia">A causa de la naturalea del desenvolupament de l'especificació de Matrix, NeoChat també implementa nombroses característiques inestables. Actualment són:</p> <p xml:lang="ca-valencia">A causa de la naturalea del desenvolupament de l'especificació de Matrix, NeoChat també implementa nombroses característiques inestables. Actualment són:</p>
<p xml:lang="de">Durch die Weiterentwicklung der Matrix-Spezifikation unterstützt auch NeoChat einige als noch instabil gekennzeichnete Funktionen. Derzeit sind das:</p>
<p xml:lang="el">Λόγω της φύσης της ανάπτυξης των προδιαγραφών Matrix, το NeoChat υποστηρίζει επίσης πολλά ασταθή χαρακτηριστικά. Επί του παρόντος, αυτά είναι:</p>
<p xml:lang="en-GB">Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:</p> <p xml:lang="en-GB">Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:</p>
<p xml:lang="eo">Pro la naturo de la Matrix-specifevoluo NeoChat ankaŭ subtenas multajn malstabilajn funkciojn. Nuntempe ĉi tiuj estas:</p> <p xml:lang="eo">Pro la naturo de la Matrix-specifevoluo NeoChat ankaŭ subtenas multajn malstabilajn funkciojn. Nuntempe ĉi tiuj estas:</p>
<p xml:lang="es">Debido a la naturaleza del desarrollo de la especificación de Matrix, NeoChat también permite numerosas funciones no estables, como:</p> <p xml:lang="es">Debido a la naturaleza del desarrollo de la especificación de Matrix, NeoChat también permite numerosas funciones no estables, como:</p>
@@ -160,20 +140,15 @@
<p xml:lang="fi">Matrix-määritelmän kehittyessä NeoChat tukee myös monia epävakaita ominaisuuksia. Tällä hetkellä näitä ovat:</p> <p xml:lang="fi">Matrix-määritelmän kehittyessä NeoChat tukee myös monia epävakaita ominaisuuksia. Tällä hetkellä näitä ovat:</p>
<p xml:lang="fr">En raison de la nature du développement des spécifications du protocole Matrix, NeoChat prend également en charge de nombreuses fonctionnalités instables. Actuellement, ce sont :</p> <p xml:lang="fr">En raison de la nature du développement des spécifications du protocole Matrix, NeoChat prend également en charge de nombreuses fonctionnalités instables. Actuellement, ce sont :</p>
<p xml:lang="gl">Debido á natureza do desenvolvemento da especificación de Matrix, NeoChat tamén inclúe varias funcionalidades non estábeis:</p> <p xml:lang="gl">Debido á natureza do desenvolvemento da especificación de Matrix, NeoChat tamén inclúe varias funcionalidades non estábeis:</p>
<p xml:lang="he">מטבע הדברים, הפיתוח של NeoChat תומך במגוון יכולות מפוקפקות כתלות בהתפתחות המפרט הטכני של Matrix. היכולות האלה הן:</p>
<p xml:lang="hi">मैट्रिक्स विनिर्देश विकास की प्रकृति के कारण नियोचैट कई अस्थिर सुविधाओं का भी समर्थन करता है। वर्तमान में ये हैं:</p>
<p xml:lang="hu">A Matrix specifikáció fejlesztésének jellegéből adódóan a NeoChat számos instabil funkciót is támogat. Jelenleg a következőket:</p> <p xml:lang="hu">A Matrix specifikáció fejlesztésének jellegéből adódóan a NeoChat számos instabil funkciót is támogat. Jelenleg a következőket:</p>
<p xml:lang="ia">Debite al natura del disveloppamento de specification de Matrix NeoChat tamben supporta numerose characteristicas instabile. Currentemente istes es:</p> <p xml:lang="ia">Debite al natura del disveloppamento de specification de Matrix NeoChat tamben supporta numerose characteristicas instabile. Currentemente istes es:</p>
<p xml:lang="it">A causa della natura dello sviluppo delle specifiche Matrix, NeoChat supporta anche numerose funzionalità instabili. Attualmente queste sono:</p> <p xml:lang="it">A causa della natura dello sviluppo delle specifiche Matrix, NeoChat supporta anche numerose funzionalità instabili. Attualmente queste sono:</p>
<p xml:lang="ka">Matrix-ის სპეციფიკაციის განვითარების ბუნების გამო NeoChat-ს ასევე აქვს უამრავი არასტაბილური ფუნქციაც. ახლა ისინია:</p> <p xml:lang="ka">Matrix-ის სპეციფიკაციის განვითარების ბუნების გამო NeoChat-ს ასევე აქვს უამრავი არასტაბილური ფუნქციაც. ახლა ისინია:</p>
<p xml:lang="ko">Matrix 표준 개발의 특징으로 인하여 NeoChat은 일부 실험적인 기능을 지원합니다. 현재 지원하는 기능은 다음과 같습니다.</p> <p xml:lang="ko">Matrix 표준 개발의 특징으로 인하여 NeoChat은 일부 실험적인 기능을 지원합니다. 현재 지원하는 기능은 다음과 같습니다.</p>
<p xml:lang="lv">„Matrix“ specifikācijas veida dēļ „NeoChat“ attīstība atbalsta arī vairākas nestabilas iespējas, šobrīd šādas ir:</p>
<p xml:lang="nl">Vanwege de aard van de ontwikkeling van de Matrix specificatie ondersteunt NeoChat ook talloze onstabiele mogelijkheden. Dit zijn nu:</p> <p xml:lang="nl">Vanwege de aard van de ontwikkeling van de Matrix specificatie ondersteunt NeoChat ook talloze onstabiele mogelijkheden. Dit zijn nu:</p>
<p xml:lang="nn">På grunn av måten Matrix-spesifikasjonen vert utvikla på, støttar NeoChat òg nokre uferdige funksjonar:</p> <p xml:lang="nn">På grunn av måten Matrix-spesifikasjonen vert utvikla på, støttar NeoChat òg nokre uferdige funksjonar:</p>
<p xml:lang="pl">Ze względu na sposób rozwoju Matriksa, NeoChat obsługuje także kilka niestabilnych możliwości. Obecnie są to:</p> <p xml:lang="pl">Ze względu na sposób rozwoju Matriksa, NeoChat obsługuje także kilka niestabilnych możliwości. Obecnie są to:</p>
<p xml:lang="pt">Devido à natureza do desenvolvimento da especificação do Matrix, o NeoChat também suporta diversas funcionalidades instáveis. De momento são:</p> <p xml:lang="pt">Devido à natureza do desenvolvimento da especificação do Matrix, o NeoChat também suporta diversas funcionalidades instáveis. De momento são:</p>
<p xml:lang="ru">В силу природы разработки спецификации Matrix в NeoChat тоже предусмотрена поддержка многочисленных нестабильных возможностей. В текущей версии это следующие возможности:</p>
<p xml:lang="sa">Matrix विनिर्देशविकासस्य प्रकृतेः कारणात् NeoChat अपि अनेकानाम् अस्थिरविशेषतानां समर्थनं करोति । सम्प्रति एते सन्ति :</p>
<p xml:lang="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p> <p xml:lang="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p>
<p xml:lang="sv">På grund av sättet Matrix-specifikationens utvecklas, stöder NeoChat också ett stor antal instabila funktioner. För närvarande är de:</p> <p xml:lang="sv">På grund av sättet Matrix-specifikationens utvecklas, stöder NeoChat också ett stor antal instabila funktioner. För närvarande är de:</p>
<p xml:lang="ta">மேட்ரிக்ஸு நெறிமுறை வரையறுக்கப்படும் வித‍த்தின் காரணமாக, பல நிலையற்ற அம்சங்களையும் நியோச்சாட் ஆதரிக்கிறது. தற்போது ஆதரிக்கப்படுபவை:</p> <p xml:lang="ta">மேட்ரிக்ஸு நெறிமுறை வரையறுக்கப்படும் வித‍த்தின் காரணமாக, பல நிலையற்ற அம்சங்களையும் நியோச்சாட் ஆதரிக்கிறது. தற்போது ஆதரிக்கப்படுபவை:</p>
@@ -186,7 +161,6 @@
<li xml:lang="ar">التصويت - MSC3381</li> <li xml:lang="ar">التصويت - MSC3381</li>
<li xml:lang="ca">Enquestes - MSC3381</li> <li xml:lang="ca">Enquestes - MSC3381</li>
<li xml:lang="ca-valencia">Enquestes - MSC3381</li> <li xml:lang="ca-valencia">Enquestes - MSC3381</li>
<li xml:lang="el">Δημοσκοπήσεις - MSC3381</li>
<li xml:lang="en-GB">Polls - MSC3381</li> <li xml:lang="en-GB">Polls - MSC3381</li>
<li xml:lang="eo">Enketoj - MSC3381</li> <li xml:lang="eo">Enketoj - MSC3381</li>
<li xml:lang="es">Encuestas - MSC3381</li> <li xml:lang="es">Encuestas - MSC3381</li>
@@ -194,20 +168,15 @@
<li xml:lang="fi">Kyselyt MSC3381</li> <li xml:lang="fi">Kyselyt MSC3381</li>
<li xml:lang="fr">Sondages - MSC3381</li> <li xml:lang="fr">Sondages - MSC3381</li>
<li xml:lang="gl">Enquisas — MSC3381</li> <li xml:lang="gl">Enquisas — MSC3381</li>
<li xml:lang="he">סקרים - MSC3381</li>
<li xml:lang="hi">पोल - MSC3381</li>
<li xml:lang="hu">Szavazások - MSC3381</li> <li xml:lang="hu">Szavazások - MSC3381</li>
<li xml:lang="ia">Inquestas - MSC3381</li> <li xml:lang="ia">Inquestas - MSC3381</li>
<li xml:lang="it">Sondaggi - MSC3381</li> <li xml:lang="it">Sondaggi - MSC3381</li>
<li xml:lang="ka">Polls - MSC3381</li> <li xml:lang="ka">Polls - MSC3381</li>
<li xml:lang="ko">투표 - MSC3381</li> <li xml:lang="ko">투표 - MSC3381</li>
<li xml:lang="lv">Aptaujas — MSC3381</li>
<li xml:lang="nl">Polls - MSC3381</li> <li xml:lang="nl">Polls - MSC3381</li>
<li xml:lang="nn">Avstemmingar  MSC3381</li> <li xml:lang="nn">Avstemmingar  MSC3381</li>
<li xml:lang="pl">Ankiety - MSC3381</li> <li xml:lang="pl">Ankiety - MSC3381</li>
<li xml:lang="pt">Inquéritos - MSC3381</li> <li xml:lang="pt">Inquéritos - MSC3381</li>
<li xml:lang="ru">Голосования — MSC3381</li>
<li xml:lang="sa">मतदान - MSC3381</li>
<li xml:lang="sl">Polls - MSC3381</li> <li xml:lang="sl">Polls - MSC3381</li>
<li xml:lang="sv">Polls - MSC3381</li> <li xml:lang="sv">Polls - MSC3381</li>
<li xml:lang="ta">வாக்கெடுப்புகள் - MSC3381</li> <li xml:lang="ta">வாக்கெடுப்புகள் - MSC3381</li>
@@ -219,7 +188,6 @@
<li xml:lang="ar">حزم الملصقات - MSC2545</li> <li xml:lang="ar">حزم الملصقات - MSC2545</li>
<li xml:lang="ca">Paquets d'adhesius - MSC2545</li> <li xml:lang="ca">Paquets d'adhesius - MSC2545</li>
<li xml:lang="ca-valencia">Paquets d'adhesius - MSC2545</li> <li xml:lang="ca-valencia">Paquets d'adhesius - MSC2545</li>
<li xml:lang="el">Πακέτα αυτοκόλλητων - MSC2545</li>
<li xml:lang="en-GB">Sticker Packs - MSC2545</li> <li xml:lang="en-GB">Sticker Packs - MSC2545</li>
<li xml:lang="eo">Glumark-Pakoj - MSC2545</li> <li xml:lang="eo">Glumark-Pakoj - MSC2545</li>
<li xml:lang="es">Paquetes de pegatinas - MSC2545</li> <li xml:lang="es">Paquetes de pegatinas - MSC2545</li>
@@ -227,24 +195,19 @@
<li xml:lang="fi">Tarrapakkaukset MSC2545</li> <li xml:lang="fi">Tarrapakkaukset MSC2545</li>
<li xml:lang="fr">Paquets d'auto-collants - MSC2545</li> <li xml:lang="fr">Paquets d'auto-collants - MSC2545</li>
<li xml:lang="gl">Paquetes de adhesivos — MSC2545</li> <li xml:lang="gl">Paquetes de adhesivos — MSC2545</li>
<li xml:lang="he">חבילות מדבקות - MSC2545</li>
<li xml:lang="hi">स्टिकर पैक - MSC2545</li>
<li xml:lang="hu">Matricacsomagok - MSC2545</li> <li xml:lang="hu">Matricacsomagok - MSC2545</li>
<li xml:lang="ia">Etiquetta gummate (sticker) -MSC2545</li> <li xml:lang="ia">Etiquetta gummate (sticker) -MSC2545</li>
<li xml:lang="it">Pacchetti di adesivi - MSC2545</li> <li xml:lang="it">Pacchetti di adesivi - MSC2545</li>
<li xml:lang="ka">სტიკერების პაკეტები - MSC2545</li> <li xml:lang="ka">სტიკერების პაკეტები - MSC2545</li>
<li xml:lang="ko">스티커 팩 - MSC2545</li> <li xml:lang="ko">스티커 팩 - MSC2545</li>
<li xml:lang="lv">Uzlīmju pakas — MSC2545</li>
<li xml:lang="nl">Sticker Packs - MSC2545</li> <li xml:lang="nl">Sticker Packs - MSC2545</li>
<li xml:lang="nn">Klistremerke-pakkar  MSC2545</li> <li xml:lang="nn">Klistremerke-pakkar  MSC2545</li>
<li xml:lang="pl">Paczki naklejek - MSC2545</li> <li xml:lang="pl">Paczki naklejek - MSC2545</li>
<li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li> <li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li>
<li xml:lang="ru">Наборы стикеров — MSC2545</li>
<li xml:lang="sa">स्टिकर पैक - MSC2545</li>
<li xml:lang="sl">Sticker Packs - MSC2545</li> <li xml:lang="sl">Sticker Packs - MSC2545</li>
<li xml:lang="sv">Sticker Packs - MSC2545</li> <li xml:lang="sv">Sticker Packs - MSC2545</li>
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li> <li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
<li xml:lang="tr">Çıkartma Paketleri — MSC2545</li> <li xml:lang="tr">Yapışkan Paketleri — MSC2545</li>
<li xml:lang="uk">Пакунки наліпок - MSC2545</li> <li xml:lang="uk">Пакунки наліпок - MSC2545</li>
<li xml:lang="x-test">xxSticker Packs - MSC2545xx</li> <li xml:lang="x-test">xxSticker Packs - MSC2545xx</li>
<li xml:lang="zh-TW">貼圖包 - MSC2545</li> <li xml:lang="zh-TW">貼圖包 - MSC2545</li>
@@ -252,7 +215,6 @@
<li xml:lang="ar">موقع الأحداث - MSC3488</li> <li xml:lang="ar">موقع الأحداث - MSC3488</li>
<li xml:lang="ca">Esdeveniments d'ubicació - MSC3488</li> <li xml:lang="ca">Esdeveniments d'ubicació - MSC3488</li>
<li xml:lang="ca-valencia">Esdeveniments d'ubicació - MSC3488</li> <li xml:lang="ca-valencia">Esdeveniments d'ubicació - MSC3488</li>
<li xml:lang="el">Τοποθεσία γεγονότα - MSC3488</li>
<li xml:lang="en-GB">Location Events - MSC3488</li> <li xml:lang="en-GB">Location Events - MSC3488</li>
<li xml:lang="eo">Lokaj Eventoj - MSC3488</li> <li xml:lang="eo">Lokaj Eventoj - MSC3488</li>
<li xml:lang="es">Eventos de ubicación - MSC3488</li> <li xml:lang="es">Eventos de ubicación - MSC3488</li>
@@ -260,20 +222,15 @@
<li xml:lang="fi">Sijaintitapahtumat MSC3488</li> <li xml:lang="fi">Sijaintitapahtumat MSC3488</li>
<li xml:lang="fr">Événements de lieu - MSC3488</li> <li xml:lang="fr">Événements de lieu - MSC3488</li>
<li xml:lang="gl">Localización de eventos — MSC3488</li> <li xml:lang="gl">Localización de eventos — MSC3488</li>
<li xml:lang="he">אירועי מקום - MSC3488</li>
<li xml:lang="hi">स्थान घटनाएँ - MSC3488</li>
<li xml:lang="hu">Események helyadatai - MSC3488</li> <li xml:lang="hu">Események helyadatai - MSC3488</li>
<li xml:lang="ia">Eventos de Location - MSC3488</li> <li xml:lang="ia">Eventos de Location - MSC3488</li>
<li xml:lang="it">Località eventi - MSC3488</li> <li xml:lang="it">Località eventi - MSC3488</li>
<li xml:lang="ka">მდებარეობის მოვლენები - MSC3488</li> <li xml:lang="ka">მდებარეობის მოვლენები - MSC3488</li>
<li xml:lang="ko">위치 이벤트 - MSC3488</li> <li xml:lang="ko">위치 이벤트 - MSC3488</li>
<li xml:lang="lv">Atrašanās vietas notikumi — MSC3488</li>
<li xml:lang="nl">Locatie gebeurtenissen - MSC3488</li> <li xml:lang="nl">Locatie gebeurtenissen - MSC3488</li>
<li xml:lang="nn">Posisjonshendingar  MSC3488</li> <li xml:lang="nn">Posisjonshendingar  MSC3488</li>
<li xml:lang="pl">Wydarzenia w miejscach - MSC3488</li> <li xml:lang="pl">Wydarzenia w miejscach - MSC3488</li>
<li xml:lang="pt">Eventos com Localizações - MSC3488</li> <li xml:lang="pt">Eventos com Localizações - MSC3488</li>
<li xml:lang="ru">События местоположения — MSC3488</li>
<li xml:lang="sa">स्थान घटनाएँ - MSC3488</li>
<li xml:lang="sl">Location Events - MSC3488</li> <li xml:lang="sl">Location Events - MSC3488</li>
<li xml:lang="sv">Location Events - MSC3488</li> <li xml:lang="sv">Location Events - MSC3488</li>
<li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li> <li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li>
@@ -285,21 +242,47 @@
</description> </description>
<url type="homepage">https://apps.kde.org/neochat</url> <url type="homepage">https://apps.kde.org/neochat</url>
<url type="bugtracker">https://bugs.kde.org/enter_bug.cgi?product=NeoChat</url> <url type="bugtracker">https://bugs.kde.org/enter_bug.cgi?product=NeoChat</url>
<url type="vcs-browser">https://invent.kde.org/network/neochat</url>
<url type="contact">https://go.kde.org/matrix/#/#neochat:kde.org</url>
<url type="donation">https://kde.org/community/donations/?app=neochat</url>
<url type="contribute">https://community.kde.org/Get_Involved/</url>
<categories> <categories>
<category>Network</category> <category>Network</category>
</categories> </categories>
<keywords> <developer_name>The KDE Community</developer_name>
<keyword>Matrix</keyword> <developer_name xml:lang="ar">مجتمع كِيدِي</developer_name>
<keyword>Kirigami</keyword> <developer_name xml:lang="az">KDE Cəmiyyəti</developer_name>
</keywords> <developer_name xml:lang="ca">La comunitat KDE</developer_name>
<developer id="kde.org"> <developer_name xml:lang="ca-valencia">La comunitat KDE</developer_name>
<name>The KDE Community</name> <developer_name xml:lang="cs">Komunita KDE</developer_name>
<url>https://kde.org</url> <developer_name xml:lang="de">Die KDE-Gemeinschaft</developer_name>
</developer> <developer_name xml:lang="el">Η Κοινότητα του KDE</developer_name>
<developer_name xml:lang="en-GB">The KDE Community</developer_name>
<developer_name xml:lang="eo">La KDE-Komunumo</developer_name>
<developer_name xml:lang="es">La comunidad KDE</developer_name>
<developer_name xml:lang="eu">KDE komunitatea</developer_name>
<developer_name xml:lang="fi">KDE-yhteisö</developer_name>
<developer_name xml:lang="fr">La communauté de KDE</developer_name>
<developer_name xml:lang="gl">A comunidade KDE</developer_name>
<developer_name xml:lang="hu">A KDE Közösség</developer_name>
<developer_name xml:lang="ia">Le communitate de KDE</developer_name>
<developer_name xml:lang="id">Komunitas KDE</developer_name>
<developer_name xml:lang="ie">Li comunité de KDE</developer_name>
<developer_name xml:lang="it">La comunità KDE</developer_name>
<developer_name xml:lang="ka">KDE-ის საზოგადოება</developer_name>
<developer_name xml:lang="ko">KDE 커뮤니티</developer_name>
<developer_name xml:lang="nl">De KDE gemeenschap</developer_name>
<developer_name xml:lang="nn">KDE-fellesskapet</developer_name>
<developer_name xml:lang="pa">ਕੇਡੀਈ ਕਮਿਊਨਟੀ</developer_name>
<developer_name xml:lang="pl">Społeczność KDE</developer_name>
<developer_name xml:lang="pt">A Comunidade do KDE</developer_name>
<developer_name xml:lang="pt-BR">A comunidade KDE</developer_name>
<developer_name xml:lang="ru">Сообщество KDE</developer_name>
<developer_name xml:lang="sk">KDE Komunita</developer_name>
<developer_name xml:lang="sl">Skupnost KDE</developer_name>
<developer_name xml:lang="sv">KDE-gemenskapen</developer_name>
<developer_name xml:lang="ta">கே.டீ.யீ. சமூகம்</developer_name>
<developer_name xml:lang="tr">KDE Topluluğu</developer_name>
<developer_name xml:lang="uk">Спільнота KDE</developer_name>
<developer_name xml:lang="x-test">xxThe KDE Communityxx</developer_name>
<developer_name xml:lang="zh-CN">KDE 社区</developer_name>
<developer_name xml:lang="zh-TW">KDE 社群</developer_name>
<metadata_license>CC0-1.0</metadata_license> <metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0</project_license> <project_license>GPL-3.0</project_license>
<custom> <custom>
@@ -310,118 +293,36 @@
<value key="KDE::windows_store::StoreLogoSquare">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/storelogo-1080x1080.png</value> <value key="KDE::windows_store::StoreLogoSquare">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/storelogo-1080x1080.png</value>
<value key="KDE::windows_store::Icon">https://invent.kde.org/network/neochat/-/raw/master/icons/300-apps-neochat.png</value> <value key="KDE::windows_store::Icon">https://invent.kde.org/network/neochat/-/raw/master/icons/300-apps-neochat.png</value>
<value key="KDE::windows_store::PromotionalArt16x9">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/promoimage-1920x1080.png</value> <value key="KDE::windows_store::PromotionalArt16x9">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/promoimage-1920x1080.png</value>
<value key="KDE::supporters">Tanguy Fardet;[dabe](https://freeradical.zone/@dabe);[lengau](https://mastodon.world/@lengau);Joshua Strobl;Stuart Turton</value>
</custom> </custom>
<launchable type="desktop-id">org.kde.neochat.desktop</launchable> <launchable type="desktop-id">org.kde.neochat.desktop</launchable>
<screenshots> <screenshots>
<screenshot type="default"> <screenshot type="default">
<image>https://cdn.kde.org/screenshots/neochat/application.png</image> <image>https://cdn.kde.org/screenshots/neochat/application-mobile.png</image>
<caption>Main view with room list, chat, and room information</caption>
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="de">Hauptansicht mit Raumliste, Unterhaltung und Raum-Informationen</caption>
<caption xml:lang="el">Κύρια προβολή με λίστα δωματίων, συνομιλία και πληροφορίες δωματίων</caption>
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
<caption xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</caption>
<caption xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</caption>
<caption xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</caption>
<caption xml:lang="he">תצוגה ראשית עם רשימת חדרים, צ׳אט ופרטי חדר</caption>
<caption xml:lang="hi">कमरे की सूची, चैट और कमरे की जानकारी के साथ मुख्य दृश्य</caption>
<caption xml:lang="hu">A fő nézet a szobalistával, csevegéssel és szobainformációkkal</caption>
<caption xml:lang="ia">Vista principal con lista de sala, chat e information de sala</caption>
<caption xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</caption>
<caption xml:lang="ka">მთავარი ხედი სურათების სიით, ჩატით და ოთახის ინფორმაციით</caption>
<caption xml:lang="ko">대화방 목록, 채팅, 대화방 정보가 표시된 주 보기</caption>
<caption xml:lang="lv">Pamata skats ar istabu sarakstu, tērzēšanu un istabas informāciju</caption>
<caption xml:lang="nl">Hoofdweergave met lijst met rooms, chat en roominformatie</caption>
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
<caption xml:lang="sa">कक्षसूची, गपशपः, कक्षसूचना च सह मुख्यदृश्यम्</caption>
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
<caption xml:lang="tr">Oda listesini, sohbet penceresini ve oda bilgisini gösteren ana görünüm</caption>
<caption xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</caption>
<caption xml:lang="x-test">xxMain view with room list, chat, and room informationxx</caption>
<caption xml:lang="zh-TW">主頁面,包含聊天室列表、聊天內容,與聊天室資訊</caption>
</screenshot> </screenshot>
<screenshot type="default"> <screenshot type="default">
<image>https://cdn.kde.org/screenshots/neochat/spaces.png</image> <image>https://cdn.kde.org/screenshots/neochat/application.png</image>
<caption>Discover new communities with Matrix Spaces</caption>
<caption xml:lang="ar">اكتشف مجتمعات جديدة مع فضاءات ماتركس</caption>
<caption xml:lang="ca">Descobriu comunitats noves amb els espais de Matrix</caption>
<caption xml:lang="ca-valencia">Descobriu comunitats noves amb els espais de Matrix</caption>
<caption xml:lang="de">Neue Gemeinschaften mit den Umgebungen von Matrix erkunden</caption>
<caption xml:lang="el">Ανακαλύψτε νέες κοινότητες με το Matrix Spaces</caption>
<caption xml:lang="en-GB">Discover new communities with Matrix Spaces</caption>
<caption xml:lang="eo">Malkovru novajn komunumojn per Matrix Spaces</caption>
<caption xml:lang="es">Descubra nuevas comunidades con los espacios de Matrix</caption>
<caption xml:lang="eu">Ezagutu komunitate berriak Matrixeko Tokiak erabiliz</caption>
<caption xml:lang="fi">Löydä uusia yhteisöjä Matrix Spacesillä</caption>
<caption xml:lang="fr">Découvrez de nouvelles communautés avec les espaces sous Matrix</caption>
<caption xml:lang="gl">Descubra novas comunidades dos espazos de Matrix.</caption>
<caption xml:lang="he">אפשר להיחשף לקהילות חדשות דרך Matrix Spaces</caption>
<caption xml:lang="hi">मैट्रिक्स स्पेस के साथ नए समुदायों की खोज करें</caption>
<caption xml:lang="hu">Fedezzen fel új közösségeket a Matrix Terek segítségével</caption>
<caption xml:lang="ia">Discoperi nove communitate con Matrix Spaces (Spatios de Matrix)</caption>
<caption xml:lang="it">Scopri nuove comunità con Matrix Spaces</caption>
<caption xml:lang="ka">აღმოაჩინეთ ახალი საზოგადოებები Matrix Spaces-თან ერთად</caption>
<caption xml:lang="lv">Atklājiet jaunas kopienas ar „Matrix“ telpām</caption>
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption>
<caption xml:lang="nn">Oppdag nye fellesskap med Matrix Spaces</caption>
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
<caption xml:lang="ru">Поиск новых сообществ с помощью Matrix Spaces</caption>
<caption xml:lang="sa">Matrix Spaces इत्यनेन सह नूतनानां समुदायानाम् अन्वेषणं कुर्वन्तु</caption>
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
<caption xml:lang="sv">Upptäck nya gemenskaper med Matrix Spaces</caption>
<caption xml:lang="ta">மேட்ரிக்ஸு இடங்களின் மூலம் புதிய சமூகங்களைக் கண்டுபிடிக்கலாம்</caption>
<caption xml:lang="tr">Matrix Alanlar ile yeni topluluklar keşfedin</caption>
<caption xml:lang="uk">Пошук нових спільнот за допомогою Matrix Spaces</caption>
<caption xml:lang="x-test">xxDiscover new communities with Matrix Spacesxx</caption>
<caption xml:lang="zh-TW">利用 Matrix 聊天空間發現新的社群</caption>
</screenshot> </screenshot>
<!--
Currently invalid. See https://github.com/ximion/appstream/issues/611
<screenshot type="default" environment="plasma-mobile">
<image>https://cdn.kde.org/screenshots/neochat/neochat-1.png</image>
<caption>List of chats on mobile</caption>
</screenshot>
-->
<screenshot environment="windows"> <screenshot environment="windows">
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</image> <image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</image>
<caption>Main view with room list, chat, and room information</caption> <caption>Main view with room list, chat, and room information</caption>
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption> <caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption> <caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption> <caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
<caption xml:lang="de">Hauptansicht mit Raumliste, Unterhaltung und Raum-Informationen</caption>
<caption xml:lang="el">Κύρια προβολή με λίστα δωματίων, συνομιλία και πληροφορίες δωματίων</caption>
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption> <caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption> <caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption> <caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
<caption xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</caption> <caption xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</caption>
<caption xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</caption> <caption xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</caption>
<caption xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</caption> <caption xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</caption>
<caption xml:lang="he">תצוגה ראשית עם רשימת חדרים, צ׳אט ופרטי חדר</caption>
<caption xml:lang="hi">कमरे की सूची, चैट और कमरे की जानकारी के साथ मुख्य दृश्य</caption>
<caption xml:lang="hu">A fő nézet a szobalistával, csevegéssel és szobainformációkkal</caption> <caption xml:lang="hu">A fő nézet a szobalistával, csevegéssel és szobainformációkkal</caption>
<caption xml:lang="ia">Vista principal con lista de sala, chat e information de sala</caption> <caption xml:lang="ia">Vista principal con lista de sala, chat e information de sala</caption>
<caption xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</caption> <caption xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</caption>
<caption xml:lang="ka">მთავარი ხედი სურათების სიით, ჩატით და ოთახის ინფორმაციით</caption> <caption xml:lang="ka">მთავარი ხედი სურათების სიით, ჩატით და ოთახის ინფორმაციით</caption>
<caption xml:lang="ko">대화방 목록, 채팅, 대화방 정보가 표시된 주 보기</caption> <caption xml:lang="ko">대화방 목록, 채팅, 대화방 정보가 표시된 주 보기</caption>
<caption xml:lang="lv">Pamata skats ar istabu sarakstu, tērzēšanu un istabas informāciju</caption>
<caption xml:lang="nl">Hoofdweergave met lijst met rooms, chat en roominformatie</caption> <caption xml:lang="nl">Hoofdweergave met lijst met rooms, chat en roominformatie</caption>
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption> <caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption> <caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption> <caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
<caption xml:lang="sa">कक्षसूची, गपशपः, कक्षसूचना च सह मुख्यदृश्यम्</caption>
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption> <caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption> <caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption> <caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
@@ -437,29 +338,21 @@
<caption xml:lang="ca">Pantalla d'inici de sessió</caption> <caption xml:lang="ca">Pantalla d'inici de sessió</caption>
<caption xml:lang="ca-valencia">Pantalla d'inici de sessió</caption> <caption xml:lang="ca-valencia">Pantalla d'inici de sessió</caption>
<caption xml:lang="cs">Přihlašovací obrazovka</caption> <caption xml:lang="cs">Přihlašovací obrazovka</caption>
<caption xml:lang="de">Anmeldebildschirm</caption>
<caption xml:lang="el">Οθόνη εισόδου</caption>
<caption xml:lang="en-GB">Login screen</caption>
<caption xml:lang="eo">Ensaluta ekrano</caption> <caption xml:lang="eo">Ensaluta ekrano</caption>
<caption xml:lang="es">Pantalla de inicio de sesión</caption> <caption xml:lang="es">Pantalla de inicio de sesión</caption>
<caption xml:lang="eu">Saio-hasteko pantaila</caption> <caption xml:lang="eu">Saio-hasteko pantaila</caption>
<caption xml:lang="fi">Kirjautumisnäkymä</caption> <caption xml:lang="fi">Kirjautumisnäkymä</caption>
<caption xml:lang="fr">Écran de connexion</caption> <caption xml:lang="fr">Écran de connexion</caption>
<caption xml:lang="gl">Pantalla de identificación.</caption> <caption xml:lang="gl">Pantalla de identificación.</caption>
<caption xml:lang="he">מסך כניסה</caption>
<caption xml:lang="hi">लॉगिन स्क्रीन</caption>
<caption xml:lang="hu">Bejelentkező képernyő</caption> <caption xml:lang="hu">Bejelentkező képernyő</caption>
<caption xml:lang="ia">Schermo de accesso</caption> <caption xml:lang="ia">Schermo de accesso</caption>
<caption xml:lang="it">Schermata di accesso</caption> <caption xml:lang="it">Schermata di accesso</caption>
<caption xml:lang="ka">შესვლის ეკრანი</caption> <caption xml:lang="ka">შესვლის ეკრანი</caption>
<caption xml:lang="ko">로그인 화면</caption> <caption xml:lang="ko">로그인 화면</caption>
<caption xml:lang="lv">Ierakstīšanās logs</caption>
<caption xml:lang="nl">Aanmeldscherm</caption> <caption xml:lang="nl">Aanmeldscherm</caption>
<caption xml:lang="nn">Innloggingsbilete</caption> <caption xml:lang="nn">Innloggingsbilete</caption>
<caption xml:lang="pl">Ekran logowania</caption> <caption xml:lang="pl">Ekran logowania</caption>
<caption xml:lang="pt">Ecrã de autenticação</caption> <caption xml:lang="pt">Ecrã de autenticação</caption>
<caption xml:lang="ru">Окно входа</caption>
<caption xml:lang="sa">लॉगिन् स्क्रीन</caption>
<caption xml:lang="sl">Prijavni zaslon</caption> <caption xml:lang="sl">Prijavni zaslon</caption>
<caption xml:lang="sv">Inloggningsfönster</caption> <caption xml:lang="sv">Inloggningsfönster</caption>
<caption xml:lang="ta">நுழைவுத் திரை</caption> <caption xml:lang="ta">நுழைவுத் திரை</caption>
@@ -473,17 +366,6 @@
<content_attribute id="social-chat">intense</content_attribute> <content_attribute id="social-chat">intense</content_attribute>
</content_rating> </content_rating>
<releases> <releases>
<release version="24.12.3" date="2025-03-06"/>
<release version="24.12.2" date="2025-02-06"/>
<release version="24.12.1" date="2025-01-09"/>
<release version="24.12.0" date="2024-12-12"/>
<release version="24.08.3" date="2024-11-07"/>
<release version="24.08.2" date="2024-10-10"/>
<release version="24.08.1" date="2024-09-12"/>
<release version="24.08.0" date="2024-08-22"/>
<release version="24.05.2" date="2024-07-04"/>
<release version="24.05.1" date="2024-06-13"/>
<release version="24.05.0" date="2024-05-23"/>
<release version="24.02.2" date="2024-04-11"/> <release version="24.02.2" date="2024-04-11"/>
<release version="24.02.1" date="2024-03-21"/> <release version="24.02.1" date="2024-03-21"/>
<release version="24.02.0" date="2024-02-28"> <release version="24.02.0" date="2024-02-28">
@@ -651,11 +533,4 @@
<url>https://carlschwan.eu/2020/12/23/announcing-neochat-1.0-the-kde-matrix-client/</url> <url>https://carlschwan.eu/2020/12/23/announcing-neochat-1.0-the-kde-matrix-client/</url>
</release> </release>
</releases> </releases>
<requires>
<display_length compare="ge">360</display_length>
</requires>
<branding>
<color type="primary" scheme_preference="light">#a6e4f3</color>
<color type="primary" scheme_preference="dark">#235670</color>
</branding>
</component> </component>

View File

@@ -18,8 +18,6 @@ Name[eu]=NeoChat
Name[fi]=NeoChat Name[fi]=NeoChat
Name[fr]=NeoChat Name[fr]=NeoChat
Name[gl]=NeoChat Name[gl]=NeoChat
Name[he]=NeoChat
Name[hi]=नियोचैट
Name[hu]=NeoChat Name[hu]=NeoChat
Name[ia]=Neochat Name[ia]=Neochat
Name[id]=NeoChat Name[id]=NeoChat
@@ -28,7 +26,6 @@ Name[it]=NeoChat
Name[ka]=NeoChat Name[ka]=NeoChat
Name[ko]=NeoChat Name[ko]=NeoChat
Name[lt]=NeoChat Name[lt]=NeoChat
Name[lv]=NeoChat
Name[nl]=NeoChat Name[nl]=NeoChat
Name[nn]=NeoChat Name[nn]=NeoChat
Name[pa]=ਨਿਓ-ਚੈਟ Name[pa]=ਨਿਓ-ਚੈਟ
@@ -37,7 +34,6 @@ Name[pt]=NeoChat
Name[pt_BR]=NeoChat Name[pt_BR]=NeoChat
Name[ro]=NeoChat Name[ro]=NeoChat
Name[ru]=NeoChat Name[ru]=NeoChat
Name[sa]=नवचैट्
Name[sk]=NeoChat Name[sk]=NeoChat
Name[sl]=NeoChat Name[sl]=NeoChat
Name[sv]=NeoChat Name[sv]=NeoChat
@@ -62,8 +58,6 @@ GenericName[eu]=Matrix bezeroa
GenericName[fi]=Matrix-asiakas GenericName[fi]=Matrix-asiakas
GenericName[fr]=Client « Matrix » GenericName[fr]=Client « Matrix »
GenericName[gl]=Cliente de Matrix GenericName[gl]=Cliente de Matrix
GenericName[he]=לקוח Matrix
GenericName[hi]=मैट्रिक्स क्लाइंट
GenericName[hu]=Matrix kliens GenericName[hu]=Matrix kliens
GenericName[ia]=Cliente de Matrice GenericName[ia]=Cliente de Matrice
GenericName[id]=Klien Matrix GenericName[id]=Klien Matrix
@@ -71,8 +65,7 @@ GenericName[ie]=Cliente de Matrix
GenericName[it]=Client Matrix GenericName[it]=Client Matrix
GenericName[ka]=Matrix -ის კლიენტი GenericName[ka]=Matrix -ის კლიენტი
GenericName[ko]=Matrix 클라이언트 GenericName[ko]=Matrix 클라이언트
GenericName[lt]=Matrix kliento programa GenericName[lt]=Matrix kliento programą
GenericName[lv]=„Matrix“ klients
GenericName[nl]=Matrix-client GenericName[nl]=Matrix-client
GenericName[nn]=Matrix-klient GenericName[nn]=Matrix-klient
GenericName[pa]=ਮੈਟਰਿਕਸ ਕਲਾਈਂਟ GenericName[pa]=ਮੈਟਰਿਕਸ ਕਲਾਈਂਟ
@@ -81,7 +74,6 @@ GenericName[pt]=Cliente de Matrix
GenericName[pt_BR]=Cliente Matrix GenericName[pt_BR]=Cliente Matrix
GenericName[ro]=Client Matrix GenericName[ro]=Client Matrix
GenericName[ru]=Клиент Matrix GenericName[ru]=Клиент Matrix
GenericName[sa]=मैट्रिक्स क्लाइंट
GenericName[sk]=Matrix Client GenericName[sk]=Matrix Client
GenericName[sl]=Odjemalec Matrix GenericName[sl]=Odjemalec Matrix
GenericName[sv]=Matrix-klient GenericName[sv]=Matrix-klient
@@ -91,37 +83,45 @@ GenericName[uk]=Клієнт Matrix
GenericName[x-test]=xxMatrix Clientxx GenericName[x-test]=xxMatrix Clientxx
GenericName[zh_CN]=Matrix 客户端 GenericName[zh_CN]=Matrix 客户端
GenericName[zh_TW]=Matrix 用戶端 GenericName[zh_TW]=Matrix 用戶端
Comment=Chat on Matrix Comment=Client for the Matrix protocol
Comment[ar]=دردش على ماتركس Comment[ar]=عميل لميفاق ماتركس
Comment[ca]=Xat a Matrix Comment[az]=Matrix protokolu üçün müştəri
Comment[ca@valencia]=Xat a Matrix Comment[ca]=Client per al protocol Matrix
Comment[de]=Über Matrix unterhalten Comment[ca@valencia]=Client per al protocol Matrix
Comment[en_GB]=Chat on Matrix Comment[de]=Programm für das Matrix-Protokoll
Comment[eo]=Babilo en Matrix Comment[el]=Πελάτης για το πρωτόκολλο Matrix
Comment[es]=Chat en Matrix Comment[en_GB]=Client for the Matrix protocol
Comment[eu]=Berriketa Matrix-en Comment[eo]=Kliento por la Matrix-protokolo
Comment[fi]=Keskustele Matrixissä Comment[es]=Cliente para el protocolo Matrix
Comment[fr]=Clavarder sur Matrix Comment[eu]=Matrix protokolorako bezeroa
Comment[gl]=Charle en Matrix Comment[fi]=Asiakas Matrix-yhteyskäytännölle
Comment[he]=התכתבות דרך Matrix Comment[fr]=Client pour le protocole « Matrix »
Comment[hi]=मैट्रिक्स पर चैट करें Comment[gl]=Cliente para o protocolo Matrix.
Comment[hu]=Csevegés Matrixon Comment[hu]=Kliens a Matrix protokollhoz
Comment[ia]=Conversation en ditecto sur Matrix Comment[ia]=Cliente per le protocollo de Matrix
Comment[it]= su Matrix Comment[id]=Klien untuk protokol Matrix
Comment[ka]=ჩატი Matrix-ზე Comment[ie]=Un cliente del protocol Matrix
Comment[lv]=Tērzējiet „Matrix“ tīklā Comment[it]=Client per il protocollo Matrix
Comment[nl]=Chat op Matrix Comment[ka]=კლიენტი Matrix-ის პროტოკოლისთვის
Comment[pl]=Rozmawiaj na Matriksie Comment[ko]=Matrix 프로토콜용 클라이언트
Comment[pt_BR]=Bate papo na Matrix Comment[lt]=Matrix protokolo kliento programa
Comment[sa]=Matrix इत्यत्र गपशपं कुर्वन्तु Comment[nl]=Client voor het Matrix-protocol
Comment[sl]=Klepet na Matrixu Comment[nn]=Klient for Matrix-protokollen
Comment[sv]=Chatta på Matrix Comment[pa]=ਮੈਟਰਿਕਸ ਪਰੋਟੋਕਾਲ ਲਈ ਕਲਾਈਂਟ ਹੈ
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும் Comment[pl]=Program obsługi protokołu Matriksa
Comment[tr]=Matrix üzerinde sohbet edin Comment[pt]=Cliente para o protocolo Matrix
Comment[uk]=Спілкування у Matrix Comment[pt_BR]=Cliente para o protocolo Matrix
Comment[x-test]=xxChat on Matrixxx Comment[ro]=Client pentru protocolul Matrix
Comment[zh_CN]= Matrix 上聊天 Comment[ru]=Клиент для протокола Matrix
Comment[zh_TW]= Matrix 上聊天 Comment[sk]=Klient protokolu Matrix
Comment[sl]=Odjemalec za protokol Matrix
Comment[sv]=Klient för protokollet Matrix
Comment[ta]=Matrix நெறிமுறைக்கான வாங்கி
Comment[tr]=Matrix protokolü için istemci
Comment[uk]=Клієнт протоколу Matrix
Comment[x-test]=xxClient for the Matrix protocolxx
Comment[zh_CN]=为 Matrix 协议打造的客户端
Comment[zh_TW]=Matrix 通訊協定的用戶端
MimeType=x-scheme-handler/matrix; MimeType=x-scheme-handler/matrix;
Exec=neochat %u Exec=neochat %u
Terminal=false Terminal=false

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -77,7 +77,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
></term> ></term>
<listitem> <listitem>
<para <para
>L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:example.org o matrix:r/root:example.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para> >L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:exemple.org o matrix:r/root:exemple.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,122 +0,0 @@
<?xml version="1.0" ?>
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
<!ENTITY % Slovenian "INCLUDE">
]>
<!--
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
SPDX-License-Identifier: CC-BY-SA-4.0
-->
<refentry lang="&language;">
<refentryinfo>
<title
>Uporabniški priročnik za NeoChat</title>
<author
><firstname
>Carl</firstname
><surname
>Schwan</surname
> <contrib
>Stran z navodili za NeoChat.</contrib
> <email
>carl@carlschwan.eu</email
></author>
<date
>01.11.2022</date>
<releaseinfo
>22,09</releaseinfo>
<productname
>NeoChat</productname>
</refentryinfo>
<refmeta>
<refentrytitle>
<command
>neochat</command>
</refentrytitle>
<manvolnum
>1</manvolnum>
</refmeta>
<refnamediv>
<refname
>neochat</refname>
<refpurpose
>Odjemalec za interakcijo s protokolom za matrično sporočanje</refpurpose>
</refnamediv>
<!-- body begins here -->
<refsynopsisdiv id='synopsis'>
<cmdsynopsis
><command
>neochat</command
> <arg choice="opt"
><replaceable
>URI</replaceable
></arg
> </cmdsynopsis>
</refsynopsisdiv>
<refsect1 id="description">
<title
>Opis</title>
<para
><command
>neochat</command
> je aplikacija za klepet za matrični protokol, ki deluje na namizju in mobilni napravi. </para>
</refsect1>
<refsect1 id="options"
><title
>Možnosti</title>
<variablelist>
<varlistentry>
<term
><option
>URI</option
></term>
<listitem>
<para
>Uri matrike za uporabnika ali sobo. npr. matrix:u/user:example.org in matrix:r/root:example.org. Tako bo NeoChat poskušal odpreti dano sobo ali pogovor. </para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="bug">
<title
>Poročanje o napakah</title>
<para
>Napake in zahteve po funkcijah lahko prijavite na <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&amp;component=General"
>https://bugs.kde.org/enter_bug.cgi? product=NeoChat&amp;component=General</ulink
></para>
</refsect1>
<refsect1>
<title
>Poglej tudi</title>
<simplelist>
<member
>Seznam pogostih vprašanj o Matrix <ulink url="https://matrix.org/faq/"
>https://matrix.org/faq/</ulink
> </member>
<member
>kf5options(7)</member>
<member
>qt5options(7)</member>
</simplelist>
</refsect1>
<refsect1 id="copyright"
><title
>Avtorske pravice</title>
<para
>Avtorske pravice &copy; 2020-2022 Tobias Fella </para>
<para
>Avtorske pravice &copy; 2020-2022 Carl Schwan </para>
<para
>Licenca: GNU General Public različica 3 ali novejša &lt;<ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
>https://www.gnu.org/licenses/gpl-3.0 .html</ulink
>&gt;</para>
</refsect1>
</refentry>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
# SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
#
# SPDX-License-Identifier: GPL-3.0-or-later
kdoctools_create_manpage(man-neochat.1.docbook 1 INSTALL_DESTINATION ${MAN_INSTALL_DIR})

View File

@@ -77,7 +77,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
></term> ></term>
<listitem> <listitem>
<para <para
>Bir kullanıcı veya oda için matrix URIsi; örneğin, matrix:u/kullanıcı:örnek.org ve matrix:r/kök:örnek.org. Bu, NeoChatin verilen odayı veya konuşmayı açmayı denemesini sağlar. </para> >Bir kullanıcı veya oda için matrix URI'si; örneğin, matrix:u/kullanıcı:örnek.org ve matrix:r/kök:örnek.org. Bu, NeoChat'in verilen odayı veya konuşmayı açmayı denemesini sağlar. </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,184 +0,0 @@
# SPDX-FileCopyrightText: 2024 Scarlett Moore <sgmoore@kde.org>
#
# SPDX-License-Identifier: CC0-1.0
---
name: neochat
base: core24
adopt-info: neochat
grade: stable
confinement: strict
apps:
neochat:
extensions:
- kde-neon-6
command: usr/bin/neochat
common-id: org.kde.neochat
desktop: usr/share/applications/org.kde.neochat.desktop
plugs:
- home
- removable-media
- audio-playback
- unity7
- network
- network-bind
- network-manager-observe
- password-manager-service
- accounts-service
compression: lzo
package-repositories:
- type: apt
ppa: ubuntu-toolchain-r/test
slots:
session-dbus-interface:
interface: dbus
name: org.kde.neochat
bus: session
parts:
olm:
source: https://gitlab.matrix.org/matrix-org/olm.git
source-depth: 1
source-tag: '3.2.12'
plugin: cmake
cmake-parameters:
- -DCMAKE_BUILD_TYPE=Release
- -DCMAKE_INSTALL_PREFIX=/usr
prime:
- -usr/include
- -usr/lib/*/pkgconfig
- -usr/lib/*/cmake
libsecret:
source: https://gitlab.gnome.org/GNOME/libsecret.git
source-tag: '0.21.4'
source-depth: 1
plugin: meson
meson-parameters:
- --prefix=/usr
- -Doptimization=3
- -Ddebug=true
- -Dmanpage=false
- -Dvapi=false
- -Dintrospection=false
- -Dcrypto=disabled
- -Dgtk_doc=false
build-packages:
- meson
- libglib2.0-dev
- libgcrypt20-dev
prime:
- -usr/include
- -usr/lib/*/pkgconfig
qtkeychain:
after: [libsecret]
source: https://github.com/frankosterfeld/qtkeychain.git
source-tag: 0.14.3
source-depth: 1
plugin: cmake
build-environment:
- PATH: /snap/bin:${PATH}
- PKG_CONFIG_PATH: "$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET\
/pkgconfig:$PKG_CONFIG_PATH"
cmake-parameters:
- -DCMAKE_INSTALL_PREFIX=/usr
- -DCMAKE_BUILD_TYPE=Release
- -DBUILD_TRANSLATIONS=NO
- -DBUILD_WITH_QT6=ON
prime:
- -usr/include
- -usr/lib/*/pkgconfig
- -usr/lib/*/cmake
libquotient:
after:
- olm
- qtkeychain
source: https://github.com/quotient-im/libQuotient.git
source-tag: 0.9.1
source-depth: 1
plugin: cmake
build-environment:
- PATH: /snap/bin:${PATH}
build-snaps:
- cmake
build-packages:
- libssl-dev
cmake-parameters:
- -DCMAKE_INSTALL_PREFIX=/usr
- -DCMAKE_BUILD_TYPE=Release
- -DBUILD_TESTING=OFF
- -DQuotient_ENABLE_E2EE=ON
- -DBUILD_WITH_QT6=ON
prime:
- -usr/include
- -usr/lib/*/pkgconfig
- -usr/lib/*/cmake
kquickimageeditor:
source: https://invent.kde.org/libraries/kquickimageeditor.git
source-tag: 'v0.3.0'
source-depth: 1
plugin: cmake
build-environment:
- PATH: /snap/bin:${PATH}
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
cmake-parameters:
- -DCMAKE_INSTALL_PREFIX=/usr
- -DCMAKE_BUILD_TYPE=Release
- -DBUILD_WITH_QT6=ON
- -DBUILD_TESTING=OFF
prime:
- -usr/include
- -usr/lib/*/pkgconfig
- -usr/lib/*/cmake
neochat:
after:
- qtkeychain
- libquotient
- kquickimageeditor
parse-info:
- usr/share/metainfo/org.kde.neochat.appdata.xml
source: .
plugin: cmake
build-environment:
- PATH: /snap/bin:${PATH}
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
build-packages:
- cmark
- libcmark-dev
- libsqlite3-dev
- libvulkan-dev
- libxkbcommon-dev
- libicu-dev
- libpulse0
cmake-parameters:
- -DCMAKE_INSTALL_PREFIX=/usr
- -DCMAKE_BUILD_TYPE=Release
- -DBUILD_TESTING=OFF
prime:
- -usr/share/man
deps:
after: [neochat]
plugin: nil
stage-packages:
- libcmark0.30.2
prime:
- usr/lib/*/libcmark.so*
gpu-2404:
after: [neochat]
source: https://github.com/canonical/gpu-snap.git
plugin: dump
override-prime: |
craftctl default
${CRAFT_PART_SRC}/bin/gpu-2404-cleanup mesa-2404
prime:
- bin/gpu-2404-wrapper

View File

@@ -3,13 +3,11 @@
# SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org> # SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
# SPDX-License-Identifier: BSD-2-Clause # SPDX-License-Identifier: BSD-2-Clause
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE)
add_subdirectory(purpose)
endif()
add_library(neochat STATIC add_library(neochat STATIC
controller.cpp controller.cpp
controller.h controller.h
actionshandler.cpp
actionshandler.h
models/emojimodel.cpp models/emojimodel.cpp
models/emojimodel.h models/emojimodel.h
emojitones.cpp emojitones.cpp
@@ -18,8 +16,10 @@ add_library(neochat STATIC
models/customemojimodel.h models/customemojimodel.h
clipboard.cpp clipboard.cpp
clipboard.h clipboard.h
models/timelinemessagemodel.cpp matriximageprovider.cpp
models/timelinemessagemodel.h matriximageprovider.h
models/messageeventmodel.cpp
models/messageeventmodel.h
models/messagefiltermodel.cpp models/messagefiltermodel.cpp
models/messagefiltermodel.h models/messagefiltermodel.h
models/roomlistmodel.cpp models/roomlistmodel.cpp
@@ -56,8 +56,6 @@ add_library(neochat STATIC
notificationsmanager.h notificationsmanager.h
models/sortfilterroomlistmodel.cpp models/sortfilterroomlistmodel.cpp
models/sortfilterroomlistmodel.h models/sortfilterroomlistmodel.h
models/roomtreemodel.cpp
models/roomtreemodel.h
chatdocumenthandler.cpp chatdocumenthandler.cpp
chatdocumenthandler.h chatdocumenthandler.h
models/devicesmodel.cpp models/devicesmodel.cpp
@@ -107,6 +105,8 @@ add_library(neochat STATIC
models/imagepacksmodel.h models/imagepacksmodel.h
events/imagepackevent.cpp events/imagepackevent.cpp
events/imagepackevent.h events/imagepackevent.h
events/joinrulesevent.cpp
events/joinrulesevent.h
models/reactionmodel.cpp models/reactionmodel.cpp
models/reactionmodel.h models/reactionmodel.h
delegatesizehelper.cpp delegatesizehelper.cpp
@@ -120,12 +120,15 @@ add_library(neochat STATIC
events/pollevent.cpp events/pollevent.cpp
pollhandler.cpp pollhandler.cpp
utils.h utils.h
utils.cpp
registration.cpp registration.cpp
neochatconnection.cpp neochatconnection.cpp
neochatconnection.h neochatconnection.h
jobs/neochatgetcommonroomsjob.cpp jobs/neochatdeactivateaccountjob.cpp
jobs/neochatgetcommonroomsjob.h jobs/neochatdeactivateaccountjob.h
jobs/neochatdeletedevicejob.cpp
jobs/neochatdeletedevicejob.h
jobs/neochatchangepasswordjob.cpp
jobs/neochatchangepasswordjob.h
mediasizehelper.cpp mediasizehelper.cpp
mediasizehelper.h mediasizehelper.h
eventhandler.cpp eventhandler.cpp
@@ -141,81 +144,15 @@ add_library(neochat STATIC
models/timelinemodel.cpp models/timelinemodel.cpp
models/timelinemodel.h models/timelinemodel.h
enums/pushrule.h enums/pushrule.h
models/itinerarymodel.cpp
models/itinerarymodel.h
proxycontroller.cpp
proxycontroller.h
models/linemodel.cpp
models/linemodel.h
events/locationbeaconevent.h
events/widgetevent.h
enums/messagecomponenttype.h
models/messagecontentmodel.cpp
models/messagecontentmodel.h
enums/neochatroomtype.h
models/sortfilterroomtreemodel.cpp
models/sortfilterroomtreemodel.h
mediamanager.cpp
mediamanager.h
models/statekeysmodel.cpp
models/statekeysmodel.h
sharehandler.cpp
sharehandler.h
models/roomtreeitem.cpp
models/roomtreeitem.h
foreigntypes.h
models/threepidmodel.cpp
models/threepidmodel.h
threepidaddhelper.cpp
threepidaddhelper.h
identityserverhelper.cpp
identityserverhelper.h
enums/powerlevel.cpp
enums/powerlevel.h
models/permissionsmodel.cpp
models/permissionsmodel.h
threepidbindhelper.cpp
threepidbindhelper.h
models/readmarkermodel.cpp
models/readmarkermodel.h
neochatroommember.cpp
neochatroommember.h
models/threadmodel.cpp
models/threadmodel.h
enums/messagetype.h
messagecomponent.h
enums/roomsortparameter.cpp
enums/roomsortparameter.h
models/roomsortparametermodel.cpp
models/roomsortparametermodel.h
models/messagemodel.cpp
models/messagemodel.h
models/messagecontentfiltermodel.cpp
models/messagecontentfiltermodel.h
models/pinnedmessagemodel.cpp
models/pinnedmessagemodel.h
models/commonroomsmodel.cpp
models/commonroomsmodel.h
) )
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
QT_QML_SINGLETON_TYPE TRUE
)
if(ANDROID OR WIN32)
set_source_files_properties(qml/ShareActionStub.qml PROPERTIES
QT_QML_SOURCE_TYPENAME ShareAction
)
endif()
ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
QML_FILES QML_FILES
qml/Main.qml qml/main.qml
qml/AccountMenu.qml qml/AccountMenu.qml
qml/ExploreComponent.qml qml/ExploreComponent.qml
qml/ExploreComponentMobile.qml qml/ExploreComponentMobile.qml
qml/RoomContextMenu.qml qml/ContextMenu.qml
qml/CollapsedRoomDelegate.qml qml/CollapsedRoomDelegate.qml
qml/RoomDelegate.qml qml/RoomDelegate.qml
qml/RoomListPage.qml qml/RoomListPage.qml
@@ -223,19 +160,71 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/UserInfo.qml qml/UserInfo.qml
qml/UserInfoDesktop.qml qml/UserInfoDesktop.qml
qml/RoomPage.qml qml/RoomPage.qml
qml/ExploreRoomsPage.qml qml/RoomWindow.qml
qml/JoinRoomPage.qml
qml/ManualRoomDialog.qml qml/ManualRoomDialog.qml
qml/ExplorerDelegate.qml qml/ExplorerDelegate.qml
qml/InviteUserPage.qml qml/InviteUserPage.qml
qml/StartChatPage.qml
qml/ImageEditorPage.qml qml/ImageEditorPage.qml
qml/WelcomePage.qml
qml/General.qml
qml/RoomSecurity.qml
qml/PushNotification.qml
qml/Categories.qml
qml/Permissions.qml
qml/NeochatMaximizeComponent.qml qml/NeochatMaximizeComponent.qml
qml/FancyEffectsContainer.qml
qml/TypingPane.qml qml/TypingPane.qml
qml/QuickSwitcher.qml qml/QuickSwitcher.qml
qml/HoverActions.qml qml/HoverActions.qml
qml/ChatBar.qml
qml/AttachmentPane.qml qml/AttachmentPane.qml
qml/ReplyPane.qml
qml/CompletionMenu.qml
qml/PieProgressBar.qml
qml/QuickFormatBar.qml qml/QuickFormatBar.qml
qml/RoomData.qml
qml/ServerData.qml
qml/EmojiPicker.qml
qml/TimelineDelegate.qml
qml/ReplyComponent.qml
qml/StateDelegate.qml
qml/RichLabel.qml
qml/MessageDelegate.qml
qml/Bubble.qml
qml/SectionDelegate.qml
qml/VideoDelegate.qml
qml/ReactionDelegate.qml
qml/LinkPreviewDelegate.qml
qml/AudioDelegate.qml
qml/FileDelegate.qml
qml/ImageDelegate.qml
qml/EncryptedDelegate.qml
qml/EventDelegate.qml
qml/TextDelegate.qml
qml/ReadMarkerDelegate.qml
qml/PollDelegate.qml
qml/MimeComponent.qml
qml/StateComponent.qml
qml/MessageEditComponent.qml
qml/AvatarFlow.qml
qml/LoginStep.qml
qml/Login.qml
qml/Homeserver.qml
qml/Username.qml
qml/RegisterPassword.qml
qml/Captcha.qml
qml/Terms.qml
qml/Email.qml
qml/Password.qml
qml/LoginRegister.qml
qml/Loading.qml
qml/LoginMethod.qml
qml/Sso.qml
qml/UserDetailDialog.qml qml/UserDetailDialog.qml
qml/CreateRoomDialog.qml qml/CreateRoomDialog.qml
qml/EmojiDialog.qml
qml/OpenFileDialog.qml qml/OpenFileDialog.qml
qml/KeyVerificationDialog.qml qml/KeyVerificationDialog.qml
qml/ConfirmLogoutDialog.qml qml/ConfirmLogoutDialog.qml
@@ -246,18 +235,47 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/EmojiSas.qml qml/EmojiSas.qml
qml/ConfirmDeactivateAccountDialog.qml qml/ConfirmDeactivateAccountDialog.qml
qml/VerificationCanceled.qml qml/VerificationCanceled.qml
qml/GlobalMenu.qml
qml/EditMenu.qml
qml/MessageDelegateContextMenu.qml qml/MessageDelegateContextMenu.qml
qml/FileDelegateContextMenu.qml qml/FileDelegateContextMenu.qml
qml/MessageSourceSheet.qml qml/MessageSourceSheet.qml
qml/ReportSheet.qml
qml/SettingsPage.qml
qml/ThemeRadioButton.qml
qml/ColorScheme.qml
qml/GeneralSettingsPage.qml
qml/EmoticonsPage.qml
qml/EmoticonEditorPage.qml
qml/EmoticonFormCard.qml
qml/GlobalNotificationsPage.qml
qml/NotificationRuleItem.qml
qml/AppearanceSettingsPage.qml
qml/AccountsPage.qml
qml/AccountEditorPage.qml
qml/DevicesPage.qml
qml/DeviceDelegate.qml
qml/DevicesCard.qml
qml/About.qml
qml/AboutKDE.qml
qml/SonnetConfigPage.qml
qml/NetworkProxyPage.qml
qml/DevtoolsPage.qml
qml/ConfirmEncryptionDialog.qml qml/ConfirmEncryptionDialog.qml
qml/RoomSearchPage.qml qml/RemoveSheet.qml
qml/RoomPinnedMessagesPage.qml qml/BanSheet.qml
qml/EmojiTonesPicker.qml
qml/EmojiDelegate.qml
qml/EmojiGrid.qml
qml/SearchPage.qml
qml/LocationDelegate.qml
qml/LocationChooser.qml qml/LocationChooser.qml
qml/TimelineView.qml qml/TimelineView.qml
qml/InvitationView.qml qml/InvitationView.qml
qml/AvatarTabButton.qml qml/AvatarTabButton.qml
qml/SpaceDrawer.qml qml/SpaceDrawer.qml
qml/OsmLocationPlugin.qml qml/OsmLocationPlugin.qml
qml/LiveLocationDelegate.qml
qml/FullScreenMap.qml qml/FullScreenMap.qml
qml/LocationsPage.qml qml/LocationsPage.qml
qml/LocationMapItem.qml qml/LocationMapItem.qml
@@ -268,81 +286,32 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/RoomInformation.qml qml/RoomInformation.qml
qml/RoomMedia.qml qml/RoomMedia.qml
qml/ChooseRoomDialog.qml qml/ChooseRoomDialog.qml
qml/ShareAction.qml
qml/SpaceHomePage.qml qml/SpaceHomePage.qml
qml/SpaceHierarchyDelegate.qml qml/SpaceHierarchyDelegate.qml
qml/RemoveChildDialog.qml qml/RemoveChildDialog.qml
qml/SelectParentDialog.qml qml/SelectParentDialog.qml
qml/Security.qml
qml/QrCodeMaximizeComponent.qml qml/QrCodeMaximizeComponent.qml
qml/SelectSpacesDialog.qml qml/SelectSpacesDialog.qml
qml/AttachDialog.qml
qml/NotificationsView.qml qml/NotificationsView.qml
qml/SearchPage.qml qml/LoadingDelegate.qml
qml/ServerComboBox.qml qml/TimelineEndDelegate.qml
qml/UserSearchPage.qml RESOURCES
qml/ManualUserDialog.qml qml/confetti.png
qml/RecommendedSpaceDialog.qml qml/glowdot.png
qml/RoomTreeSection.qml
qml/DelegateContextMenu.qml
qml/ShareDialog.qml
qml/UnlockSSSSDialog.qml
qml/QrScannerPage.qml
qml/JoinRoomDialog.qml
qml/ConfirmUrlDialog.qml
qml/AccountSwitchDialog.qml
qml/ConfirmLeaveDialog.qml
qml/CodeMaximizeComponent.qml
qml/EditStateDialog.qml
qml/ConsentDialog.qml
qml/AskDirectChatConfirmation.qml
qml/HoverLinkIndicator.qml
qml/AvatarNotification.qml
qml/ReasonDialog.qml
DEPENDENCIES
QtCore
QtQuick
IMPORTS
org.kde.neochat.timeline
org.kde.neochat.settings
org.kde.neochat.devtools
org.kde.neochat.login
org.kde.neochat.chatbar
) )
add_subdirectory(settings)
add_subdirectory(timeline)
add_subdirectory(devtools)
add_subdirectory(login)
add_subdirectory(chatbar)
if(NOT ANDROID AND NOT WIN32)
qt_target_qml_sources(neochat QML_FILES
qml/ShareAction.qml
qml/GlobalMenu.qml
qml/EditMenu.qml
)
else()
qt_target_qml_sources(neochat QML_FILES qml/ShareActionStub.qml)
endif()
configure_file(config-neochat.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-neochat.h)
if(WIN32) if(WIN32)
set_target_properties(neochat PROPERTIES OUTPUT_NAME "neochatlib") set_target_properties(neochat PROPERTIES OUTPUT_NAME "neochatlib")
endif() endif()
ecm_qt_declare_logging_category(neochat ecm_qt_declare_logging_category(neochat
HEADER "messagemodel_logging.h" HEADER "messageeventmodel_logging.h"
IDENTIFIER "Message" IDENTIFIER "MessageEvent"
CATEGORY_NAME "org.kde.neochat.messagemodel" CATEGORY_NAME "org.kde.neochat.messageeventmodel"
DESCRIPTION "Neochat: messagemodel" DESCRIPTION "Neochat: messageeventmodel"
DEFAULT_SEVERITY Info
EXPORT NEOCHAT
)
ecm_qt_declare_logging_category(neochat
HEADER "publicroomlist_logging.h"
IDENTIFIER "PublicRoomList"
CATEGORY_NAME "org.kde.neochat.publicroomlistmodel"
DESCRIPTION "Neochat: publicroomlistmodel"
DEFAULT_SEVERITY Info DEFAULT_SEVERITY Info
EXPORT NEOCHAT EXPORT NEOCHAT
) )
@@ -392,20 +361,17 @@ if(NOT ANDROID)
target_compile_definitions(neochat PUBLIC -DHAVE_ICU) target_compile_definitions(neochat PUBLIC -DHAVE_ICU)
endif() endif()
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU) if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
target_compile_definitions(neochat PUBLIC -DHAVE_RUNNER) target_compile_definitions(neochat PUBLIC -DHAVE_RUNNER)
target_compile_definitions(neochat PUBLIC -DHAVE_X11=1) target_compile_definitions(neochat PUBLIC -DHAVE_X11)
target_sources(neochat PRIVATE runner.cpp) target_sources(neochat PRIVATE runner.cpp)
if (TARGET KUnifiedPush) if (TARGET KUnifiedPush)
target_sources(neochat PRIVATE fakerunner.cpp) target_sources(neochat PRIVATE fakerunner.cpp)
endif() endif()
else()
target_compile_definitions(neochat PUBLIC -DHAVE_X11=0)
endif() endif()
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums) target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
target_link_libraries(neochat PRIVATE settingsplugin timelineplugin devtoolsplugin loginplugin chatbarplugin)
target_link_libraries(neochat PUBLIC target_link_libraries(neochat PUBLIC
Qt::Core Qt::Core
Qt::Quick Qt::Quick
@@ -421,7 +387,6 @@ target_link_libraries(neochat PUBLIC
KF6::ConfigGui KF6::ConfigGui
KF6::CoreAddons KF6::CoreAddons
KF6::SonnetCore KF6::SonnetCore
KF6::IconThemes
KF6::ColorScheme KF6::ColorScheme
KF6::ItemModels KF6::ItemModels
QuotientQt6 QuotientQt6
@@ -430,11 +395,7 @@ target_link_libraries(neochat PUBLIC
QCoro::Network QCoro::Network
) )
if (TARGET KF6::Crash) kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
target_link_libraries(neochat PUBLIC KF6::Crash)
endif()
kconfig_target_kcfg_file(neochat FILE neochatconfig.kcfg CLASS_NAME NeoChatConfig MUTATORS GENERATE_PROPERTIES DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR SINGLETON GENERATE_MOC QML_REGISTRATION)
if(NEOCHAT_FLATPAK) if(NEOCHAT_FLATPAK)
target_compile_definitions(neochat PUBLIC NEOCHAT_FLATPAK) target_compile_definitions(neochat PUBLIC NEOCHAT_FLATPAK)
@@ -449,11 +410,8 @@ if(ANDROID)
target_sources(neochat-app PRIVATE notifyrc.qrc) target_sources(neochat-app PRIVATE notifyrc.qrc)
target_link_libraries(neochat PUBLIC Qt::Svg OpenSSL::SSL) target_link_libraries(neochat PUBLIC Qt::Svg OpenSSL::SSL)
kirigami_package_breeze_icons(ICONS kirigami_package_breeze_icons(ICONS
"arrow-down-symbolic" "arrow-down"
"arrow-up-symbolic" "arrow-up"
"arrow-up-double-symbolic"
"arrow-left-symbolic"
"arrow-right-symbolic"
"checkmark" "checkmark"
"help-about" "help-about"
"im-user" "im-user"
@@ -462,7 +420,6 @@ if(ANDROID)
"mail-attachment" "mail-attachment"
"dialog-cancel" "dialog-cancel"
"preferences-desktop-emoticons" "preferences-desktop-emoticons"
"preferences-security"
"document-open" "document-open"
"document-save" "document-save"
"document-send" "document-send"
@@ -495,7 +452,6 @@ if(ANDROID)
"network-connect" "network-connect"
"list-remove-user" "list-remove-user"
"org.kde.neochat" "org.kde.neochat"
"org.kde.neochat.tray"
"preferences-system-users" "preferences-system-users"
"preferences-desktop-theme-global" "preferences-desktop-theme-global"
"notifications" "notifications"
@@ -533,20 +489,15 @@ if(ANDROID)
"object-rotate-left" "object-rotate-left"
"object-rotate-right" "object-rotate-right"
"add-subtitle" "add-subtitle"
"security-high"
"security-low" "security-low"
"security-low-symbolic" "security-low-symbolic"
"kde" "kde"
"list-remove-symbolic" "list-remove-symbolic"
"edit-delete" "edit-delete"
"user-home-symbolic"
"pin-symbolic"
"kt-restore-defaults-symbolic"
"user-symbolic"
) )
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android) ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
else() else()
target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets KF6::SyntaxHighlighting) target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets)
install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR}) install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
endif() endif()

Some files were not shown because too many files have changed in this diff Show More