Compare commits
448 Commits
release/24
...
work/nvrwh
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45c46ddcbb | ||
|
|
31d83ac0e3 | ||
|
|
909eec30d2 | ||
|
|
dbed3e99c2 | ||
|
|
4d0db0b5c2 | ||
|
|
6e49aaf17b | ||
|
|
1092d75f2e | ||
|
|
8059c3797d | ||
|
|
1302d62ad9 | ||
|
|
8eaae4034d | ||
|
|
354e3414a1 | ||
|
|
fc24beae6d | ||
|
|
923cc67b55 | ||
|
|
30e24069bc | ||
|
|
f7533a454c | ||
|
|
ab4e1a86dc | ||
|
|
d28c2ed113 | ||
|
|
3a467328f5 | ||
|
|
979d83cb01 | ||
|
|
d165cd955d | ||
|
|
6eb770343e | ||
|
|
54be52b855 | ||
|
|
d201333409 | ||
|
|
3db8b4cd17 | ||
|
|
0e246a00bc | ||
|
|
e638fa8929 | ||
|
|
cdc982ad91 | ||
|
|
bff69e21ad | ||
|
|
e117cc0cfb | ||
|
|
3af1a88e05 | ||
|
|
aa116a35f5 | ||
|
|
ac232d7f55 | ||
|
|
928911e33c | ||
|
|
e3c30f5bb3 | ||
|
|
4b51855528 | ||
|
|
79c27db0a9 | ||
|
|
78e42ab352 | ||
|
|
93909c45ee | ||
|
|
eda0bf4b23 | ||
|
|
4f4b10e0b6 | ||
|
|
2b374a8bec | ||
|
|
7821de4a8d | ||
|
|
86b88c851f | ||
|
|
1157882f1b | ||
|
|
594d1373c9 | ||
|
|
1e6948bbc7 | ||
|
|
41845b97d5 | ||
|
|
bb56f74622 | ||
|
|
a98f6ac331 | ||
|
|
15d6287995 | ||
|
|
0242ab72e8 | ||
|
|
4b7cbf37d5 | ||
|
|
0ccfe7d991 | ||
|
|
ab5585cd06 | ||
|
|
b25a0a7a4e | ||
|
|
f574c12adc | ||
|
|
05a2f03c18 | ||
|
|
cbc2e65856 | ||
|
|
1df80a7d2a | ||
|
|
050a014df7 | ||
|
|
4775ae09b0 | ||
|
|
8d4c3bb4fc | ||
|
|
439260ff03 | ||
|
|
5b04ad6805 | ||
|
|
6d77ed1e0e | ||
|
|
cc7f783b50 | ||
|
|
1d7ed1983b | ||
|
|
c0151353c5 | ||
|
|
72994248fa | ||
|
|
af0d3d5ee1 | ||
|
|
07dd1d2e91 | ||
|
|
185a88a16e | ||
|
|
e3059e636a | ||
|
|
aeb566746a | ||
|
|
8da567d9fa | ||
|
|
d99f69cc24 | ||
|
|
8240962400 | ||
|
|
bd1d4289c0 | ||
|
|
5d2139471a | ||
|
|
d49a64ac1e | ||
|
|
cd867ea581 | ||
|
|
32fd62c484 | ||
|
|
f2c561bd15 | ||
|
|
80734944d3 | ||
|
|
b3afa9f595 | ||
|
|
656558850c | ||
|
|
e41cca9be0 | ||
|
|
46916b34d4 | ||
|
|
4f9ca3e74d | ||
|
|
2bcdd0f52b | ||
|
|
56d790dda9 | ||
|
|
149013d2ff | ||
|
|
776807580a | ||
|
|
75e9eee3a9 | ||
|
|
183615fa7b | ||
|
|
7405fbaa16 | ||
|
|
22743b6d8b | ||
|
|
b5864f02cb | ||
|
|
373431fb1a | ||
|
|
29167fbdf2 | ||
|
|
699ac3a8e6 | ||
|
|
d7b572faaf | ||
|
|
a09b4e7f2c | ||
|
|
a794420d3e | ||
|
|
8b606266c5 | ||
|
|
11e4329d5e | ||
|
|
68dfc6ca81 | ||
|
|
e0c8945431 | ||
|
|
fe60ee00fb | ||
|
|
5990e00577 | ||
|
|
358a699290 | ||
|
|
da6e4378d9 | ||
|
|
5edb0629b3 | ||
|
|
5170854a2c | ||
|
|
37d6033df4 | ||
|
|
ea2f891533 | ||
|
|
42cec7d5ba | ||
|
|
2df2e39d43 | ||
|
|
b34525a4d8 | ||
|
|
0a7bd64b0d | ||
|
|
11fd4f88ec | ||
|
|
4d9452b862 | ||
|
|
060e30e612 | ||
|
|
ade7270add | ||
|
|
338428b0c0 | ||
|
|
54574e4450 | ||
|
|
ae564451b8 | ||
|
|
9a4504ce61 | ||
|
|
80785a2ff3 | ||
|
|
cb8ed02e82 | ||
|
|
a64c1b8eab | ||
|
|
d43aa169c3 | ||
|
|
8ae7141851 | ||
|
|
d3908db2c9 | ||
|
|
55de838a55 | ||
|
|
4cdfc38b87 | ||
|
|
51197d7c1a | ||
|
|
2a2a2e0c05 | ||
|
|
07fee30cc0 | ||
|
|
83c6ce0ace | ||
|
|
fb7303efa0 | ||
|
|
ef5585d312 | ||
|
|
11475259a1 | ||
|
|
9df4cd6f13 | ||
|
|
c9583964c8 | ||
|
|
5022ed1a63 | ||
|
|
799ffa18c4 | ||
|
|
6323e27040 | ||
|
|
03acb26109 | ||
|
|
34fc1f6a6b | ||
|
|
042032ec46 | ||
|
|
73de99f661 | ||
|
|
cc068f9ebb | ||
|
|
2bfc2b1944 | ||
|
|
029936112f | ||
|
|
d5e400e8a4 | ||
|
|
9dbb9c3f3b | ||
|
|
a101e6b0a7 | ||
|
|
c525ea55ce | ||
|
|
8ca45f298f | ||
|
|
cb4c6cb677 | ||
|
|
d574a97a35 | ||
|
|
20f9a86ad9 | ||
|
|
a4a411cf1f | ||
|
|
029bda5734 | ||
|
|
0fd578e6aa | ||
|
|
95e1bee5e6 | ||
|
|
c8dc10f311 | ||
|
|
a00f4e393b | ||
|
|
5a7dea8857 | ||
|
|
27e8970fff | ||
|
|
7848274ba1 | ||
|
|
145bf0298b | ||
|
|
0392a33b54 | ||
|
|
b211f46e3e | ||
|
|
709711c3ca | ||
|
|
841607406f | ||
|
|
70b726b04d | ||
|
|
2799248106 | ||
|
|
2321299084 | ||
|
|
aa00773a3b | ||
|
|
733de1d0e1 | ||
|
|
c16e4ad412 | ||
|
|
d1cf7a07f1 | ||
|
|
8751f6fea7 | ||
|
|
ea1b577ec7 | ||
|
|
a41afa70eb | ||
|
|
e11c97cdc0 | ||
|
|
d76e44512e | ||
|
|
fd1931377d | ||
|
|
68ce6c4ed7 | ||
|
|
a2ee330307 | ||
|
|
c3a17f951e | ||
|
|
443c0f34d7 | ||
|
|
8725600368 | ||
|
|
3b83b7f190 | ||
|
|
e0c3a1c143 | ||
|
|
bec1ad7bee | ||
|
|
9e6c00f78c | ||
|
|
abbbd9d705 | ||
|
|
4a5c012f05 | ||
|
|
319862b3d4 | ||
|
|
1fcf58024d | ||
|
|
9db162d0fc | ||
|
|
13b15390c3 | ||
|
|
799b62e9d2 | ||
|
|
d91ed535ad | ||
|
|
c48b9874bf | ||
|
|
6a788f6c32 | ||
|
|
53519a604e | ||
|
|
2818b87f02 | ||
|
|
50e10133b9 | ||
|
|
068161719e | ||
|
|
c8d5d095e0 | ||
|
|
52d07320ef | ||
|
|
158b9ea2ca | ||
|
|
6a100bfbab | ||
|
|
b3bd6ee176 | ||
|
|
04696b27eb | ||
|
|
332937dbc1 | ||
|
|
92d932ce5c | ||
|
|
af3c4f536a | ||
|
|
b98ca5af52 | ||
|
|
a15a11f44b | ||
|
|
1460132772 | ||
|
|
76d68bb3e4 | ||
|
|
08df0ebbea | ||
|
|
e918db2cc1 | ||
|
|
2e0dc8db94 | ||
|
|
b78a9f2a9c | ||
|
|
832e6b9de0 | ||
|
|
feec7ca408 | ||
|
|
408f0a12e2 | ||
|
|
35ab4e6e09 | ||
|
|
430bafafe7 | ||
|
|
58d727350d | ||
|
|
c6a4057659 | ||
|
|
60ac806690 | ||
|
|
e9263fc596 | ||
|
|
3dd28a0382 | ||
|
|
066cb8184e | ||
|
|
373e22b999 | ||
|
|
fd8725f649 | ||
|
|
3d433762b1 | ||
|
|
ea4cb5bf62 | ||
|
|
a6ca3b8203 | ||
|
|
bc4ceb6d52 | ||
|
|
24480229cd | ||
|
|
8b10573197 | ||
|
|
cbc81e8285 | ||
|
|
0b9a978061 | ||
|
|
e974e5d13b | ||
|
|
5a42e86bf6 | ||
|
|
889946e186 | ||
|
|
5c47e8044e | ||
|
|
1a974ac305 | ||
|
|
db1bf61805 | ||
|
|
5456b4a7ff | ||
|
|
a08ffaae77 | ||
|
|
18445f55f0 | ||
|
|
2daf3b5c4b | ||
|
|
923b844212 | ||
|
|
0aec9f8472 | ||
|
|
23b0c8a143 | ||
|
|
3c2c2e2bd8 | ||
|
|
c1465a7368 | ||
|
|
be1dadab74 | ||
|
|
1cba39eae9 | ||
|
|
a0c8bdf021 | ||
|
|
6fdb22a5b5 | ||
|
|
19c370a273 | ||
|
|
861336ea97 | ||
|
|
24219bcb03 | ||
|
|
77ed762e2c | ||
|
|
d45b6cb03d | ||
|
|
9a921b2e0d | ||
|
|
c17e213e11 | ||
|
|
6275d7afaa | ||
|
|
364eda6400 | ||
|
|
ccf34cfe20 | ||
|
|
7daae6a2d9 | ||
|
|
277a4ad124 | ||
|
|
b11d46e34a | ||
|
|
e8ad0a055d | ||
|
|
8a8c745d77 | ||
|
|
a523fe7674 | ||
|
|
dc9a150929 | ||
|
|
be66ffef0f | ||
|
|
f278cc0c86 | ||
|
|
7f72808a9a | ||
|
|
1d5297c0f0 | ||
|
|
e40528ba45 | ||
|
|
29972b5867 | ||
|
|
91109ca845 | ||
|
|
8e5ccb5461 | ||
|
|
8a75967953 | ||
|
|
3f4965b182 | ||
|
|
2ac266029c | ||
|
|
3261231d07 | ||
|
|
95ce6385b0 | ||
|
|
64c5894602 | ||
|
|
8c4839c300 | ||
|
|
80c2bc1a52 | ||
|
|
bcd417e039 | ||
|
|
ac216f697f | ||
|
|
9893fae27c | ||
|
|
cb183efa66 | ||
|
|
87d707bc21 | ||
|
|
227ebd610a | ||
|
|
ab4af48e52 | ||
|
|
78a8227219 | ||
|
|
ec73a53101 | ||
|
|
3fb1d086b7 | ||
|
|
5d4a12c127 | ||
|
|
d2a79214b5 | ||
|
|
db57111188 | ||
|
|
b22276bcd5 | ||
|
|
6e2d85f2d2 | ||
|
|
efb72652ce | ||
|
|
3615c3e8e5 | ||
|
|
8186ee0e3f | ||
|
|
74aa14c011 | ||
|
|
aa68369f95 | ||
|
|
7837364b86 | ||
|
|
31f0e39617 | ||
|
|
a48151920d | ||
|
|
8199653ddd | ||
|
|
9d650519c7 | ||
|
|
a545eaca97 | ||
|
|
9da9de2d2d | ||
|
|
c9ddd9d513 | ||
|
|
415cfd57e7 | ||
|
|
b1ede93cdb | ||
|
|
32df465c8a | ||
|
|
2f1c5df11d | ||
|
|
f85f6a7fdc | ||
|
|
93cc80a4b3 | ||
|
|
0f3e401d42 | ||
|
|
a9f2c33053 | ||
|
|
c5ef8c3fec | ||
|
|
ad696bd60b | ||
|
|
9da7462f3e | ||
|
|
0ecdf354c6 | ||
|
|
67f10632fb | ||
|
|
044b910357 | ||
|
|
3de943e50f | ||
|
|
1a2272249d | ||
|
|
0dfeec6cae | ||
|
|
8d193021ab | ||
|
|
f45226a680 | ||
|
|
40d55805ff | ||
|
|
7d6d0b012b | ||
|
|
d7d2c6bf01 | ||
|
|
ce1c6096d3 | ||
|
|
8c4ea6180a | ||
|
|
95649ba758 | ||
|
|
2b61f2a9e8 | ||
|
|
47242aa66c | ||
|
|
31a8abe615 | ||
|
|
4dae3c34b4 | ||
|
|
65aa8919b9 | ||
|
|
acf8eac0d4 | ||
|
|
e8aa29d3c2 | ||
|
|
a36194afe2 | ||
|
|
8554898e45 | ||
|
|
55b29f645b | ||
|
|
52cc91ba3e | ||
|
|
c9e3a9f8fe | ||
|
|
c3de788956 | ||
|
|
53e3c36f7e | ||
|
|
20908107a0 | ||
|
|
cbe1a0d6f8 | ||
|
|
7d8c79ec57 | ||
|
|
9bb89c728f | ||
|
|
be2e28cc53 | ||
|
|
57be57971d | ||
|
|
64eed47f04 | ||
|
|
7659105fda | ||
|
|
18c9376992 | ||
|
|
3a4aca7fbd | ||
|
|
85ff8cdd4a | ||
|
|
b1048cb84a | ||
|
|
ff9cf9abf6 | ||
|
|
157c84663d | ||
|
|
908e4fb5a4 | ||
|
|
fdca7d58e5 | ||
|
|
2eb26d512b | ||
|
|
b7fdf7d60f | ||
|
|
2a1e66468d | ||
|
|
cd7faf751e | ||
|
|
d79d806cda | ||
|
|
cae389c04c | ||
|
|
4e6850a60c | ||
|
|
a71f8cf358 | ||
|
|
fe6ff9b2b6 | ||
|
|
5a0f3e474d | ||
|
|
cd9c4239b1 | ||
|
|
0cf1d87b12 | ||
|
|
99d91c1e07 | ||
|
|
457f80bc9b | ||
|
|
968e3fc23b | ||
|
|
b1e338579d | ||
|
|
7e4361bb5e | ||
|
|
dd35fa3d91 | ||
|
|
affb911d97 | ||
|
|
785f9cd1b6 | ||
|
|
419056f098 | ||
|
|
396db18de2 | ||
|
|
f124721cd9 | ||
|
|
52e49b49fb | ||
|
|
10e03777e9 | ||
|
|
27538b72e9 | ||
|
|
19ace37a75 | ||
|
|
90c5377ef0 | ||
|
|
f0e3d3e474 | ||
|
|
26064ebf8c | ||
|
|
1d92b74131 | ||
|
|
5f83c137d2 | ||
|
|
fa57db8e83 | ||
|
|
9d3c2e19f5 | ||
|
|
46a9600d55 | ||
|
|
de40701cf6 | ||
|
|
307536c6b6 | ||
|
|
203be8bd35 | ||
|
|
1e644587b3 | ||
|
|
66a60f09e3 | ||
|
|
69b6f16ec1 | ||
|
|
10b4274a3d | ||
|
|
28c9d94457 | ||
|
|
d74fd1a560 | ||
|
|
624b1b06c5 | ||
|
|
95376c2ccc | ||
|
|
1eb622165b | ||
|
|
9d6ba324fb | ||
|
|
d462852ab9 | ||
|
|
eeec81898b | ||
|
|
ab0c8b8170 | ||
|
|
91d295e0bb | ||
|
|
125974dd7a | ||
|
|
92895a7d00 | ||
|
|
d9308440e6 | ||
|
|
5340142c06 | ||
|
|
012d30ee9f | ||
|
|
031d69d996 | ||
|
|
8b63c18f65 | ||
|
|
dc2f11eb2b | ||
|
|
13e64a9487 | ||
|
|
6a3c88ae5b |
@@ -2,5 +2,6 @@
|
|||||||
; SPDX-License-Identifier: CC0-1.0
|
; SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
[BlueprintSettings]
|
[BlueprintSettings]
|
||||||
|
kde/applications/neochat.packageAppx=True
|
||||||
kde/frameworks/extra-cmake-modules.version=master
|
kde/frameworks/extra-cmake-modules.version=master
|
||||||
libs/qt.qtMajorVersion=6
|
libs/qt.qtMajorVersion=6
|
||||||
|
|||||||
@@ -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.6",
|
"runtime-version": "6.7",
|
||||||
"sdk": "org.kde.Sdk",
|
"sdk": "org.kde.Sdk",
|
||||||
"command": "neochat",
|
"command": "neochat",
|
||||||
"tags": [
|
"tags": [
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ include:
|
|||||||
- /gitlab-templates/android-qt6.yml
|
- /gitlab-templates/android-qt6.yml
|
||||||
- /gitlab-templates/linux-qt6.yml
|
- /gitlab-templates/linux-qt6.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/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
|
||||||
@@ -8,13 +8,13 @@ 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 "24")
|
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||||
set(RELEASE_SERVICE_VERSION_MINOR "05")
|
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
||||||
set(RELEASE_SERVICE_VERSION_MICRO "2")
|
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||||
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.0")
|
set(KF_MIN_VERSION "6.5")
|
||||||
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)
|
||||||
@@ -38,6 +38,7 @@ include(KDEGitCommitHooks)
|
|||||||
include(ECMCheckOutboundLicense)
|
include(ECMCheckOutboundLicense)
|
||||||
include(ECMQtDeclareLoggingCategory)
|
include(ECMQtDeclareLoggingCategory)
|
||||||
include(ECMAddAndroidApk)
|
include(ECMAddAndroidApk)
|
||||||
|
include(ECMQmlModule)
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
include(KDEClangFormat)
|
include(KDEClangFormat)
|
||||||
endif()
|
endif()
|
||||||
@@ -59,7 +60,9 @@ set_package_properties(Qt6 PROPERTIES
|
|||||||
PURPOSE "Basic application components"
|
PURPOSE "Basic application components"
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_policy(SET QTP0001 NEW)
|
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 ColorScheme)
|
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
|
||||||
set_package_properties(KF6 PROPERTIES
|
set_package_properties(KF6 PROPERTIES
|
||||||
@@ -102,7 +105,7 @@ 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.7)
|
find_package(QuotientQt6 0.8.2)
|
||||||
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"
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ 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/).
|
Nightly builds for Linux and Windows can be downloaded from [cdn.kde.org](https://cdn.kde.org/ci-builds/network/neochat/).
|
||||||
Nightly builds for android are available from [KDE's nightly F-Droid repository](https://community.kde.org/Android/F-Droid).
|
Nightly builds for Android are available from [KDE's nightly F-Droid repository](https://community.kde.org/Android/F-Droid).
|
||||||
Nightly Flatpaks are available from [KDE's nightly Flatpak repository](https://userbase.kde.org/Tutorials/Flatpak).
|
Nightly Flatpaks are available from [KDE's nightly Flatpak repository](https://userbase.kde.org/Tutorials/Flatpak).
|
||||||
|
|
||||||
## Building NeoChat
|
## Building NeoChat
|
||||||
|
|||||||
56
appiumtests/createroomtest.py
Executable file
56
appiumtests/createroomtest.py
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
#!/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()
|
||||||
78
appiumtests/data/sync_response_new_room.json
Normal file
78
appiumtests/data/sync_response_new_room.json
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ 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():
|
||||||
@@ -42,8 +44,13 @@ 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 = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
|
result = dict()
|
||||||
|
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")
|
||||||
@@ -65,6 +72,18 @@ 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(ssl_context='adhoc', port=1234)
|
app.run(ssl_context='adhoc', port=1234)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#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>
|
||||||
|
|
||||||
@@ -50,7 +51,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->relationUser(), room->getUser(nullptr));
|
QCOMPARE(chatBarCache->relationUser(), room->member(QString()));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||||
}
|
}
|
||||||
@@ -64,7 +65,7 @@ void ChatBarCacheTest::noRoom()
|
|||||||
// 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->relationUser(), QVariantMap());
|
QCOMPARE(chatBarCache->relationUser(), Quotient::RoomMember());
|
||||||
|
|
||||||
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());
|
||||||
@@ -80,7 +81,7 @@ void ChatBarCacheTest::badParent()
|
|||||||
// 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->relationUser(), QVariantMap());
|
QCOMPARE(chatBarCache->relationUser(), Quotient::RoomMember());
|
||||||
|
|
||||||
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());
|
||||||
@@ -98,7 +99,7 @@ void ChatBarCacheTest::reply()
|
|||||||
QCOMPARE(chatBarCache->replyId(), QLatin1String("$153456789:example.org"));
|
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->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
|
QCOMPARE(chatBarCache->relationUser(), room->member(QLatin1String("@example:example.org")));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||||
}
|
}
|
||||||
@@ -106,8 +107,13 @@ void ChatBarCacheTest::reply()
|
|||||||
void ChatBarCacheTest::edit()
|
void ChatBarCacheTest::edit()
|
||||||
{
|
{
|
||||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||||
|
|
||||||
chatBarCache->setText(QLatin1String("some text"));
|
chatBarCache->setText(QLatin1String("some text"));
|
||||||
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
|
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
|
||||||
|
connect(chatBarCache.get(), &ChatBarCache::relationIdChanged, this, [](const QString &oldEventId, const QString &newEventId) {
|
||||||
|
QCOMPARE(oldEventId, QString());
|
||||||
|
QCOMPARE(newEventId, QString(QLatin1String("$153456789:example.org")));
|
||||||
|
});
|
||||||
chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
|
chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
|
||||||
|
|
||||||
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
|
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
|
||||||
@@ -115,7 +121,7 @@ void ChatBarCacheTest::edit()
|
|||||||
QCOMPARE(chatBarCache->replyId(), QString());
|
QCOMPARE(chatBarCache->replyId(), QString());
|
||||||
QCOMPARE(chatBarCache->isEditing(), true);
|
QCOMPARE(chatBarCache->isEditing(), true);
|
||||||
QCOMPARE(chatBarCache->editId(), QLatin1String("$153456789:example.org"));
|
QCOMPARE(chatBarCache->editId(), QLatin1String("$153456789:example.org"));
|
||||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
|
QCOMPARE(chatBarCache->relationUser(), room->member(QLatin1String("@example:example.org")));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||||
}
|
}
|
||||||
@@ -132,7 +138,7 @@ void ChatBarCacheTest::attachment()
|
|||||||
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->relationUser(), room->getUser(nullptr));
|
QCOMPARE(chatBarCache->relationUser(), room->member(QString()));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
|
QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"user_ids": [
|
"user_ids": [
|
||||||
"@alice:matrix.org",
|
"@alice:matrix.org",
|
||||||
"@bob:example.com"
|
"@bob:kde.org"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"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:matrix.org": {
|
"@alice:example.org": {
|
||||||
"ts": 1436451550453
|
"ts": 1436451550453
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"$1532735824654:example.org": {
|
"$1532735824654:example.org": {
|
||||||
"m.read": {
|
"m.read": {
|
||||||
"@bob:example.com": {
|
"@bob:kde.org": {
|
||||||
"ts": 1436451550453
|
"ts": 1436451550453
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,6 +67,18 @@
|
|||||||
},
|
},
|
||||||
"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": {
|
||||||
@@ -136,6 +148,22 @@
|
|||||||
"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",
|
||||||
@@ -156,7 +184,7 @@
|
|||||||
"summary": {
|
"summary": {
|
||||||
"m.heroes": [
|
"m.heroes": [
|
||||||
"@alice:example.com",
|
"@alice:example.com",
|
||||||
"@bob:example.com"
|
"@bob:kde.org"
|
||||||
],
|
],
|
||||||
"m.invited_member_count": 0,
|
"m.invited_member_count": 0,
|
||||||
"m.joined_member_count": 2
|
"m.joined_member_count": 2
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -37,16 +37,14 @@
|
|||||||
"events": [
|
"events": [
|
||||||
{
|
{
|
||||||
"content": {
|
"content": {
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
"displayname": "Example",
|
||||||
"displayname": "Alice Margatroid",
|
"membership": "join"
|
||||||
"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": "@alice:example.org",
|
"state_key": "@example:example.org",
|
||||||
"type": "m.room.member",
|
"type": "m.room.member",
|
||||||
"unsigned": {
|
"unsigned": {
|
||||||
"age": 1234
|
"age": 1234
|
||||||
|
|||||||
@@ -130,7 +130,23 @@
|
|||||||
"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:example.org",
|
"state_key": "@alice:matrix.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
|
||||||
|
|||||||
@@ -51,6 +51,21 @@
|
|||||||
"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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,15 +29,11 @@ private:
|
|||||||
Connection *connection = nullptr;
|
Connection *connection = nullptr;
|
||||||
TestUtils::TestRoom *room = nullptr;
|
TestUtils::TestRoom *room = nullptr;
|
||||||
|
|
||||||
EventHandler emptyHandler = EventHandler(nullptr, nullptr);
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
|
|
||||||
void eventId();
|
void eventId();
|
||||||
void nullEventId();
|
void nullEventId();
|
||||||
void author();
|
|
||||||
void nullAuthor();
|
|
||||||
void authorDisplayName();
|
void authorDisplayName();
|
||||||
void nullAuthorDisplayName();
|
void nullAuthorDisplayName();
|
||||||
void singleLineSidplayName();
|
void singleLineSidplayName();
|
||||||
@@ -45,7 +41,6 @@ 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();
|
||||||
@@ -56,6 +51,7 @@ 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();
|
||||||
@@ -66,16 +62,10 @@ private Q_SLOTS:
|
|||||||
void nullReplyId();
|
void nullReplyId();
|
||||||
void replyAuthor();
|
void replyAuthor();
|
||||||
void nullReplyAuthor();
|
void nullReplyAuthor();
|
||||||
void replyBody();
|
|
||||||
void nullReplyBody();
|
|
||||||
void replyMediaInfo();
|
|
||||||
void nullReplyMediaInfo();
|
|
||||||
void thread();
|
void thread();
|
||||||
void nullThread();
|
void nullThread();
|
||||||
void location();
|
void location();
|
||||||
void nullLocation();
|
void nullLocation();
|
||||||
void readMarkers();
|
|
||||||
void nullReadMarkers();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void EventHandlerTest::initTestCase()
|
void EventHandlerTest::initTestCase()
|
||||||
@@ -86,183 +76,136 @@ void EventHandlerTest::initTestCase()
|
|||||||
|
|
||||||
void EventHandlerTest::eventId()
|
void EventHandlerTest::eventId()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
QCOMPARE(EventHandler::id(room->messageEvents().at(0).get()), QStringLiteral("$153456789:example.org"));
|
||||||
QCOMPARE(eventHandler.getId(), QStringLiteral("$153456789:example.org"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullEventId()
|
void EventHandlerTest::nullEventId()
|
||||||
{
|
{
|
||||||
EventHandler noEventHandler(room, nullptr);
|
QTest::ignoreMessage(QtWarningMsg, "id called with event set to nullptr.");
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getId called with m_event set to nullptr.");
|
QCOMPARE(EventHandler::id(nullptr), QString());
|
||||||
QCOMPARE(noEventHandler.getId(), QString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void EventHandlerTest::author()
|
|
||||||
{
|
|
||||||
auto event = room->messageEvents().at(0).get();
|
|
||||||
auto author = room->user(event->senderId());
|
|
||||||
EventHandler eventHandler(room, 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());
|
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
|
||||||
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()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(1).get());
|
QCOMPARE(EventHandler::authorDisplayName(room, room->messageEvents().at(1).get()), QStringLiteral("before"));
|
||||||
QCOMPARE(eventHandler.getAuthorDisplayName(), QStringLiteral("before"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullAuthorDisplayName()
|
void EventHandlerTest::nullAuthorDisplayName()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "authorDisplayName called with room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getAuthorDisplayName(), QString());
|
QCOMPARE(EventHandler::authorDisplayName(nullptr, nullptr), QString());
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
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()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(11).get());
|
QCOMPARE(EventHandler::singleLineAuthorDisplayname(room, room->messageEvents().at(11).get()),
|
||||||
QCOMPARE(eventHandler.singleLineAuthorDisplayname(), QStringLiteral("Look at me I put newlines in my display name"));
|
QStringLiteral("Look at me I put newlines in my display name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullSingleLineDisplayName()
|
void EventHandlerTest::nullSingleLineDisplayName()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "singleLineAuthorDisplayname called with room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.singleLineAuthorDisplayname(), QString());
|
QCOMPARE(EventHandler::singleLineAuthorDisplayname(nullptr, nullptr), QString());
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
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()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
const auto event = room->messageEvents().at(0).get();
|
||||||
|
|
||||||
QCOMPARE(eventHandler.getTime(), QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC));
|
QCOMPARE(EventHandler::time(event), QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC));
|
||||||
QCOMPARE(eventHandler.getTime(true, QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC)), QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC));
|
QCOMPARE(EventHandler::time(event, true, QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC)), QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullTime()
|
void EventHandlerTest::nullTime()
|
||||||
{
|
{
|
||||||
EventHandler noEventHandler(room, nullptr);
|
QTest::ignoreMessage(QtWarningMsg, "time called with event set to nullptr.");
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getTime called with m_event set to nullptr.");
|
QCOMPARE(EventHandler::time(nullptr), QDateTime());
|
||||||
QCOMPARE(noEventHandler.getTime(), QDateTime());
|
|
||||||
|
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
|
QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
|
||||||
QCOMPARE(eventHandler.getTime(true), QDateTime());
|
QCOMPARE(EventHandler::time(room->messageEvents().at(0).get(), true), QDateTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::timeString()
|
void EventHandlerTest::timeString()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
const auto event = room->messageEvents().at(0).get();
|
||||||
|
|
||||||
KFormat format;
|
KFormat format;
|
||||||
|
|
||||||
QCOMPARE(eventHandler.getTimeString(false),
|
QCOMPARE(EventHandler::timeString(event, false),
|
||||||
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toLocalTime().time(), QLocale::ShortFormat));
|
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toLocalTime().time(), QLocale::ShortFormat));
|
||||||
QCOMPARE(eventHandler.getTimeString(true),
|
QCOMPARE(EventHandler::timeString(event, true),
|
||||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toLocalTime().date(), QLocale::ShortFormat));
|
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toLocalTime().date(), QLocale::ShortFormat));
|
||||||
QCOMPARE(eventHandler.getTimeString(false, QLocale::ShortFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
QCOMPARE(EventHandler::timeString(event, false, QLocale::ShortFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
||||||
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::ShortFormat));
|
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::ShortFormat));
|
||||||
QCOMPARE(eventHandler.getTimeString(true, QLocale::ShortFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
QCOMPARE(EventHandler::timeString(event, true, QLocale::ShortFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
||||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::ShortFormat));
|
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::ShortFormat));
|
||||||
QCOMPARE(eventHandler.getTimeString(false, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
QCOMPARE(EventHandler::timeString(event, false, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
||||||
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::LongFormat));
|
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::LongFormat));
|
||||||
QCOMPARE(eventHandler.getTimeString(true, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
QCOMPARE(EventHandler::timeString(event, true, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
|
||||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat));
|
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat));
|
||||||
}
|
QCOMPARE(EventHandler::timeString(event, QStringLiteral("hh:mm")),
|
||||||
|
QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toString(QStringLiteral("hh:mm")));
|
||||||
void EventHandlerTest::nullTimeString()
|
|
||||||
{
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getTimeString called with m_event set to nullptr.");
|
|
||||||
QCOMPARE(noEventHandler.getTimeString(false), QString());
|
|
||||||
|
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
|
|
||||||
QCOMPARE(eventHandler.getTimeString(false, QLocale::ShortFormat, true), QString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::highlighted()
|
void EventHandlerTest::highlighted()
|
||||||
{
|
{
|
||||||
EventHandler eventHandlerHighlight(room, room->messageEvents().at(2).get());
|
QCOMPARE(EventHandler::isHighlighted(room, room->messageEvents().at(2).get()), true);
|
||||||
QCOMPARE(eventHandlerHighlight.isHighlighted(), true);
|
QCOMPARE(EventHandler::isHighlighted(room, room->messageEvents().at(0).get()), false);
|
||||||
|
|
||||||
EventHandler eventHandlerNoHighlight(room, room->messageEvents().at(0).get());
|
|
||||||
QCOMPARE(eventHandlerNoHighlight.isHighlighted(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullHighlighted()
|
void EventHandlerTest::nullHighlighted()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.isHighlighted(), false);
|
QCOMPARE(EventHandler::isHighlighted(nullptr, nullptr), false);
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
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()
|
||||||
{
|
{
|
||||||
EventHandler eventHandlerHidden(room, room->messageEvents().at(3).get());
|
QCOMPARE(EventHandler::isHidden(room, room->messageEvents().at(3).get()), true);
|
||||||
QCOMPARE(eventHandlerHidden.isHidden(), true);
|
QCOMPARE(EventHandler::isHidden(room, room->messageEvents().at(0).get()), false);
|
||||||
|
|
||||||
EventHandler eventHandlerNoHidden(room, room->messageEvents().at(0).get());
|
|
||||||
QCOMPARE(eventHandlerNoHidden.isHidden(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullHidden()
|
void EventHandlerTest::nullHidden()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "isHidden called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "isHidden called with room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.isHidden(), false);
|
QCOMPARE(EventHandler::isHidden(nullptr, nullptr), false);
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
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()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
const auto event = room->messageEvents().at(0).get();
|
||||||
|
|
||||||
QCOMPARE(eventHandler.getRichBody(), QStringLiteral("<b>This is an example<br>text message</b>"));
|
QCOMPARE(EventHandler::richBody(room, event), QStringLiteral("<b>This is an example<br>text message</b>"));
|
||||||
QCOMPARE(eventHandler.getRichBody(true), QStringLiteral("<b>This is an example text message</b>"));
|
QCOMPARE(EventHandler::richBody(room, event, true), QStringLiteral("<b>This is an example text message</b>"));
|
||||||
QCOMPARE(eventHandler.getPlainBody(), QStringLiteral("This is an example\ntext message"));
|
QCOMPARE(EventHandler::plainBody(room, event), QStringLiteral("This is an example\ntext message"));
|
||||||
QCOMPARE(eventHandler.getPlainBody(true), QStringLiteral("This is an example text message"));
|
QCOMPARE(EventHandler::plainBody(room, event, true), QStringLiteral("This is an example text message"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullBody()
|
void EventHandlerTest::nullBody()
|
||||||
{
|
{
|
||||||
EventHandler noEventHandler(room, nullptr);
|
QTest::ignoreMessage(QtWarningMsg, "richBody called with room set to nullptr.");
|
||||||
|
QCOMPARE(EventHandler::richBody(nullptr, nullptr), QString());
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getRichBody called with m_event set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "richBody called with event set to nullptr.");
|
||||||
QCOMPARE(noEventHandler.getRichBody(), QString());
|
QCOMPARE(EventHandler::richBody(room, nullptr), QString());
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getPlainBody called with m_event set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "plainBody called with room set to nullptr.");
|
||||||
QCOMPARE(noEventHandler.getPlainBody(), QString());
|
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()
|
||||||
@@ -282,47 +225,45 @@ void EventHandlerTest::genericBody()
|
|||||||
QFETCH(int, eventNum);
|
QFETCH(int, eventNum);
|
||||||
QFETCH(QString, output);
|
QFETCH(QString, output);
|
||||||
|
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(eventNum).get());
|
QCOMPARE(EventHandler::genericBody(room->messageEvents().at(eventNum).get()), output);
|
||||||
|
|
||||||
QCOMPARE(eventHandler.getGenericBody(), output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullGenericBody()
|
void EventHandlerTest::nullGenericBody()
|
||||||
{
|
{
|
||||||
EventHandler noEventHandler(room, nullptr);
|
QTest::ignoreMessage(QtWarningMsg, "genericBody called with event set to nullptr.");
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getGenericBody called with m_event set to nullptr.");
|
QCOMPARE(EventHandler::genericBody(nullptr), QString());
|
||||||
QCOMPARE(noEventHandler.getGenericBody(), QString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::markdownBody()
|
void EventHandlerTest::markdownBody()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
QCOMPARE(EventHandler::markdownBody(room->messageEvents().at(0).get()), QStringLiteral("This is an example\ntext message"));
|
||||||
|
}
|
||||||
|
|
||||||
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("This is an example\ntext message"));
|
void EventHandlerTest::markdownBodyReply()
|
||||||
|
{
|
||||||
|
QCOMPARE(EventHandler::markdownBody(room->messageEvents().at(5).get()), QStringLiteral("reply"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::subtitle()
|
void EventHandlerTest::subtitle()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
QCOMPARE(EventHandler::subtitleText(room, room->messageEvents().at(0).get()), QStringLiteral("after: This is an example text message"));
|
||||||
QCOMPARE(eventHandler.subtitleText(), QStringLiteral("after: This is an example text message"));
|
QCOMPARE(EventHandler::subtitleText(room, room->messageEvents().at(2).get()),
|
||||||
|
QStringLiteral("after: This is a highlight @bob:kde.org and this is a link https://kde.org"));
|
||||||
EventHandler eventHandler2(room, room->messageEvents().at(2).get());
|
|
||||||
QCOMPARE(eventHandler2.subtitleText(), QStringLiteral("after: This is a highlight @bob:kde.org and this is a link https://kde.org"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullSubtitle()
|
void EventHandlerTest::nullSubtitle()
|
||||||
{
|
{
|
||||||
EventHandler noEventHandler(room, nullptr);
|
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();
|
||||||
EventHandler eventHandler(room, event);
|
auto mediaInfo = EventHandler::mediaInfo(room, event);
|
||||||
|
|
||||||
auto mediaInfo = eventHandler.getMediaInfo();
|
|
||||||
auto thumbnailInfo = mediaInfo["tempInfo"_ls].toMap();
|
auto thumbnailInfo = mediaInfo["tempInfo"_ls].toMap();
|
||||||
|
|
||||||
QCOMPARE(mediaInfo["source"_ls], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/1234567"_ls)));
|
QCOMPARE(mediaInfo["source"_ls], room->makeMediaUrl(event->id(), QUrl("mxc://kde.org/1234567"_ls)));
|
||||||
@@ -342,231 +283,102 @@ void EventHandlerTest::mediaInfo()
|
|||||||
|
|
||||||
void EventHandlerTest::nullMediaInfo()
|
void EventHandlerTest::nullMediaInfo()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getMediaInfo called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "mediaInfo called with room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getMediaInfo(), QVariantMap());
|
QCOMPARE(EventHandler::mediaInfo(nullptr, nullptr), QVariantMap());
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
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()
|
void EventHandlerTest::hasReply()
|
||||||
{
|
{
|
||||||
EventHandler eventHandlerReply(room, room->messageEvents().at(5).get());
|
QCOMPARE(EventHandler::hasReply(room->messageEvents().at(5).get()), true);
|
||||||
QCOMPARE(eventHandlerReply.hasReply(), true);
|
QCOMPARE(EventHandler::hasReply(room->messageEvents().at(0).get()), false);
|
||||||
|
|
||||||
EventHandler eventHandlerNoReply(room, room->messageEvents().at(0).get());
|
|
||||||
QCOMPARE(eventHandlerNoReply.hasReply(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullHasReply()
|
void EventHandlerTest::nullHasReply()
|
||||||
{
|
{
|
||||||
EventHandler noEventHandler(room, nullptr);
|
QTest::ignoreMessage(QtWarningMsg, "hasReply called with event set to nullptr.");
|
||||||
QTest::ignoreMessage(QtWarningMsg, "hasReply called with m_event set to nullptr.");
|
QCOMPARE(EventHandler::hasReply(nullptr), false);
|
||||||
QCOMPARE(noEventHandler.hasReply(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::replyId()
|
void EventHandlerTest::replyId()
|
||||||
{
|
{
|
||||||
EventHandler eventHandlerReply(room, room->messageEvents().at(5).get());
|
QCOMPARE(EventHandler::replyId(room->messageEvents().at(5).get()), QStringLiteral("$153456789:example.org"));
|
||||||
QCOMPARE(eventHandlerReply.getReplyId(), QStringLiteral("$153456789:example.org"));
|
QCOMPARE(EventHandler::replyId(room->messageEvents().at(0).get()), QStringLiteral(""));
|
||||||
|
|
||||||
EventHandler eventHandlerNoReply(room, room->messageEvents().at(0).get());
|
|
||||||
QCOMPARE(eventHandlerNoReply.getReplyId(), QStringLiteral(""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullReplyId()
|
void EventHandlerTest::nullReplyId()
|
||||||
{
|
{
|
||||||
EventHandler noEventHandler(room, nullptr);
|
QTest::ignoreMessage(QtWarningMsg, "replyId called with event set to nullptr.");
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getReplyId called with m_event set to nullptr.");
|
QCOMPARE(EventHandler::replyId(nullptr), QString());
|
||||||
QCOMPARE(noEventHandler.getReplyId(), QString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::replyAuthor()
|
void EventHandlerTest::replyAuthor()
|
||||||
{
|
{
|
||||||
auto replyEvent = room->messageEvents().at(0).get();
|
auto replyEvent = room->messageEvents().at(0).get();
|
||||||
auto replyAuthor = room->user(replyEvent->senderId());
|
auto replyAuthor = room->member(replyEvent->senderId());
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(5).get());
|
auto eventHandlerReplyAuthor = EventHandler::replyAuthor(room, room->messageEvents().at(5).get());
|
||||||
|
|
||||||
auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
|
QCOMPARE(eventHandlerReplyAuthor.isLocalMember(), replyAuthor.id() == room->localMember().id());
|
||||||
|
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(eventHandlerReplyAuthor["isLocalUser"_ls], replyAuthor->id() == room->localUser()->id());
|
QCOMPARE(EventHandler::replyAuthor(room, room->messageEvents().at(0).get()), RoomMember());
|
||||||
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));
|
|
||||||
|
|
||||||
EventHandler eventHandlerNoAuthor(room, room->messageEvents().at(0).get());
|
|
||||||
QCOMPARE(eventHandlerNoAuthor.getReplyAuthor(), room->getUser(nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullReplyAuthor()
|
void EventHandlerTest::nullReplyAuthor()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "replyAuthor called with room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getReplyAuthor(), QVariantMap());
|
QCOMPARE(EventHandler::replyAuthor(nullptr, nullptr), RoomMember());
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
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()
|
|
||||||
{
|
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(5).get());
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
|
||||||
|
|
||||||
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 eventHandler(room, 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());
|
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getReplyMediaInfo called with m_event set to nullptr.");
|
|
||||||
QCOMPARE(noEventHandler.getReplyMediaInfo(), QVariantMap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::thread()
|
void EventHandlerTest::thread()
|
||||||
{
|
{
|
||||||
EventHandler eventHandlerNoThread(room, room->messageEvents().at(0).get());
|
QCOMPARE(EventHandler::isThreaded(room->messageEvents().at(0).get()), false);
|
||||||
QCOMPARE(eventHandlerNoThread.isThreaded(), false);
|
QCOMPARE(EventHandler::threadRoot(room->messageEvents().at(0).get()), QString());
|
||||||
QCOMPARE(eventHandlerNoThread.threadRoot(), QString());
|
|
||||||
|
|
||||||
EventHandler eventHandlerThreadRoot(room, room->messageEvents().at(9).get());
|
QCOMPARE(EventHandler::isThreaded(room->messageEvents().at(9).get()), true);
|
||||||
QCOMPARE(eventHandlerThreadRoot.isThreaded(), true);
|
QCOMPARE(EventHandler::threadRoot(room->messageEvents().at(9).get()), QStringLiteral("$threadroot:example.org"));
|
||||||
QCOMPARE(eventHandlerThreadRoot.threadRoot(), QStringLiteral("$threadroot:example.org"));
|
QCOMPARE(EventHandler::replyId(room->messageEvents().at(9).get()), QStringLiteral("$threadroot:example.org"));
|
||||||
QCOMPARE(eventHandlerThreadRoot.getReplyId(), QStringLiteral("$threadroot:example.org"));
|
|
||||||
|
|
||||||
EventHandler eventHandlerThreadReply(room, room->messageEvents().at(10).get());
|
QCOMPARE(EventHandler::isThreaded(room->messageEvents().at(10).get()), true);
|
||||||
QCOMPARE(eventHandlerThreadReply.isThreaded(), true);
|
QCOMPARE(EventHandler::threadRoot(room->messageEvents().at(10).get()), QStringLiteral("$threadroot:example.org"));
|
||||||
QCOMPARE(eventHandlerThreadReply.threadRoot(), QStringLiteral("$threadroot:example.org"));
|
QCOMPARE(EventHandler::replyId(room->messageEvents().at(10).get()), QStringLiteral("$threadmessage1:example.org"));
|
||||||
QCOMPARE(eventHandlerThreadReply.getReplyId(), QStringLiteral("$threadmessage1:example.org"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullThread()
|
void EventHandlerTest::nullThread()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "isThreaded called with m_event set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "isThreaded called with event set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.isThreaded(), false);
|
QCOMPARE(EventHandler::isThreaded(nullptr), false);
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
QTest::ignoreMessage(QtWarningMsg, "threadRoot called with event set to nullptr.");
|
||||||
QTest::ignoreMessage(QtWarningMsg, "threadRoot called with m_event set to nullptr.");
|
QCOMPARE(EventHandler::threadRoot(nullptr), QString());
|
||||||
QCOMPARE(noEventHandler.threadRoot(), QString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::location()
|
void EventHandlerTest::location()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(7).get());
|
QCOMPARE(EventHandler::latitude(room->messageEvents().at(7).get()), QStringLiteral("51.7035").toFloat());
|
||||||
|
QCOMPARE(EventHandler::longitude(room->messageEvents().at(7).get()), QStringLiteral("-1.14394").toFloat());
|
||||||
QCOMPARE(eventHandler.getLatitude(), QStringLiteral("51.7035").toFloat());
|
QCOMPARE(EventHandler::locationAssetType(room->messageEvents().at(7).get()), QStringLiteral("m.pin"));
|
||||||
QCOMPARE(eventHandler.getLongitude(), QStringLiteral("-1.14394").toFloat());
|
|
||||||
QCOMPARE(eventHandler.getLocationAssetType(), QStringLiteral("m.pin"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullLocation()
|
void EventHandlerTest::nullLocation()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getLatitude called with m_event set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "latitude called with event set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getLatitude(), -100.0);
|
QCOMPARE(EventHandler::latitude(nullptr), -100.0);
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getLongitude called with m_event set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "longitude called with event set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getLongitude(), -200.0);
|
QCOMPARE(EventHandler::longitude(nullptr), -200.0);
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getLocationAssetType called with m_event set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "locationAssetType called with event set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getLocationAssetType(), QString());
|
QCOMPARE(EventHandler::locationAssetType(nullptr), QString());
|
||||||
}
|
|
||||||
|
|
||||||
void EventHandlerTest::readMarkers()
|
|
||||||
{
|
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
|
||||||
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"));
|
|
||||||
|
|
||||||
EventHandler eventHandler2(room, room->messageEvents().at(2).get());
|
|
||||||
QCOMPARE(eventHandler2.hasReadMarkers(), true);
|
|
||||||
|
|
||||||
readMarkers = eventHandler2.getReadMarkers();
|
|
||||||
|
|
||||||
QCOMPARE(readMarkers.size(), 5);
|
|
||||||
|
|
||||||
QCOMPARE(eventHandler2.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(eventHandler2.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());
|
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(EventHandlerTest)
|
QTEST_MAIN(EventHandlerTest)
|
||||||
|
|||||||
@@ -6,12 +6,11 @@
|
|||||||
|
|
||||||
#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;
|
||||||
@@ -30,6 +29,9 @@ 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();
|
||||||
};
|
};
|
||||||
@@ -42,45 +44,59 @@ void LinkPreviewerTest::initTestCase()
|
|||||||
|
|
||||||
void LinkPreviewerTest::linkPreviewsMatch_data()
|
void LinkPreviewerTest::linkPreviewsMatch_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("eventSource");
|
QTest::addColumn<QString>("inputString");
|
||||||
QTest::addColumn<QUrl>("testOutputLink");
|
QTest::addColumn<QUrl>("testOutputLink");
|
||||||
|
|
||||||
QTest::newRow("plainHttps") << QStringLiteral("test-validplainlink-event.json") << QUrl("https://kde.org"_ls);
|
QTest::newRow("plainHttps") << QStringLiteral("https://kde.org") << QUrl("https://kde.org"_ls);
|
||||||
QTest::newRow("richHttps") << QStringLiteral("test-validrichlink-event.json") << QUrl("https://kde.org"_ls);
|
QTest::newRow("richHttps") << QStringLiteral("<a href=\"https://kde.org\">Rich Link</a>") << QUrl("https://kde.org"_ls);
|
||||||
QTest::newRow("plainWww") << QStringLiteral("test-validplainwwwlink-event.json") << QUrl("www.example.org"_ls);
|
QTest::newRow("richHttpsLinkDescription") << QStringLiteral("<a href=\"https://kde.org\">https://kde.org</a>") << QUrl("https://kde.org"_ls);
|
||||||
QTest::newRow("multipleHttps") << QStringLiteral("test-multiplelink-event.json") << QUrl("www.example.org"_ls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkPreviewerTest::linkPreviewsMatch()
|
void LinkPreviewerTest::linkPreviewsMatch()
|
||||||
{
|
{
|
||||||
QFETCH(QString, eventSource);
|
QFETCH(QString, inputString);
|
||||||
QFETCH(QUrl, testOutputLink);
|
QFETCH(QUrl, testOutputLink);
|
||||||
|
|
||||||
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
auto link = LinkPreviewer::linkPreviews(inputString)[0];
|
||||||
auto linkPreviewer = LinkPreviewer(LinkPreviewer::linkPreview(event.get()), connection);
|
|
||||||
|
|
||||||
QCOMPARE(linkPreviewer.empty(), false);
|
QCOMPARE(link, testOutputLink);
|
||||||
QCOMPARE(linkPreviewer.url(), testOutputLink);
|
}
|
||||||
|
|
||||||
|
void LinkPreviewerTest::multipleLinkPreviewsMatch_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("inputString");
|
||||||
|
QTest::addColumn<QList<QUrl>>("testOutputLinks");
|
||||||
|
|
||||||
|
QTest::newRow("multipleHttps") << QStringLiteral("www.example.org https://kde.org") << QList{QUrl("www.example.org"_ls), QUrl("https://kde.org"_ls)};
|
||||||
|
QTest::newRow("multipleHttps1Invalid") << QStringLiteral("www.example.org mxc://example.org/SEsfnsuifSDFSSEF") << QList{QUrl("www.example.org"_ls)};
|
||||||
|
}
|
||||||
|
|
||||||
|
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>("eventSource");
|
QTest::addColumn<QString>("inputString");
|
||||||
|
|
||||||
QTest::newRow("mxc") << QStringLiteral("test-invalidmxclink-event.json");
|
QTest::newRow("mxc") << QStringLiteral("mxc://example.org/SEsfnsuifSDFSSEF");
|
||||||
QTest::newRow("matrixTo") << QStringLiteral("test-invalidmatrixtolink-event.json");
|
QTest::newRow("matrixTo") << QStringLiteral("https://matrix.to/#/@alice:example.org");
|
||||||
QTest::newRow("noSpace") << QStringLiteral("test-invalidnospacelink-event.json");
|
QTest::newRow("noSpace") << QStringLiteral("testhttps://kde.org");
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkPreviewerTest::linkPreviewsReject()
|
void LinkPreviewerTest::linkPreviewsReject()
|
||||||
{
|
{
|
||||||
QFETCH(QString, eventSource);
|
QFETCH(QString, inputString);
|
||||||
|
|
||||||
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
auto links = LinkPreviewer::linkPreviews(inputString);
|
||||||
auto linkPreviewer = LinkPreviewer(LinkPreviewer::linkPreview(event.get()), connection);
|
|
||||||
|
|
||||||
QCOMPARE(linkPreviewer.empty(), true);
|
QCOMPARE(links.empty(), true);
|
||||||
QCOMPARE(linkPreviewer.url(), QUrl());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(LinkPreviewerTest)
|
QTEST_MAIN(LinkPreviewerTest)
|
||||||
|
|||||||
@@ -52,10 +52,8 @@ void ReactionModelTest::basicReaction()
|
|||||||
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), QStringLiteral("<span style=\"font-family: 'emoji';\">👍</span>"));
|
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), QStringLiteral("<span style=\"font-family: 'emoji';\">👍</span>"));
|
||||||
QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), QStringLiteral("👍"));
|
QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), QStringLiteral("👍"));
|
||||||
QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole),
|
QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole),
|
||||||
QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
QStringLiteral("Alice Margatroid 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::HasLocalMember), false);
|
||||||
QCOMPARE(model.data(model.index(0), ReactionModel::AuthorsRole), authorList);
|
|
||||||
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalUser), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReactionModelTest::newReaction()
|
void ReactionModelTest::newReaction()
|
||||||
@@ -65,7 +63,7 @@ void ReactionModelTest::newReaction()
|
|||||||
|
|
||||||
QCOMPARE(model->rowCount(), 1);
|
QCOMPARE(model->rowCount(), 1);
|
||||||
QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole),
|
QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole),
|
||||||
QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
QStringLiteral("Alice Margatroid reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
||||||
|
|
||||||
QSignalSpy spy(model, SIGNAL(modelReset()));
|
QSignalSpy spy(model, SIGNAL(modelReset()));
|
||||||
|
|
||||||
@@ -74,7 +72,7 @@ void ReactionModelTest::newReaction()
|
|||||||
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), QStringLiteral("😆"));
|
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),
|
||||||
QStringLiteral("@alice:matrix.org and @bob:example.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
QStringLiteral("Alice Margatroid and Bob reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
||||||
|
|
||||||
delete model;
|
delete model;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ private Q_SLOTS:
|
|||||||
void sendCustomEmojiCode_data();
|
void sendCustomEmojiCode_data();
|
||||||
void sendCustomEmojiCode();
|
void sendCustomEmojiCode();
|
||||||
|
|
||||||
|
void receiveSpacelessSelfClosingTag();
|
||||||
void receiveStripReply();
|
void receiveStripReply();
|
||||||
void receivePlainTextIn();
|
void receivePlainTextIn();
|
||||||
|
|
||||||
@@ -252,6 +253,19 @@ void TextHandlerTest::sendCustomEmojiCode()
|
|||||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextHandlerTest::receiveSpacelessSelfClosingTag()
|
||||||
|
{
|
||||||
|
const QString testInputString = QStringLiteral("Test...<br/>...ing");
|
||||||
|
const QString testRichOutputString = QStringLiteral("Test...<br/>...ing");
|
||||||
|
const QString testPlainOutputString = QStringLiteral("Test...\n...ing");
|
||||||
|
|
||||||
|
TextHandler testTextHandler;
|
||||||
|
testTextHandler.setData(testInputString);
|
||||||
|
|
||||||
|
QCOMPARE(testTextHandler.handleRecieveRichText(), testRichOutputString);
|
||||||
|
QCOMPARE(testTextHandler.handleRecievePlainText(Qt::RichText), testPlainOutputString);
|
||||||
|
}
|
||||||
|
|
||||||
void TextHandlerTest::receiveStripReply()
|
void TextHandlerTest::receiveStripReply()
|
||||||
{
|
{
|
||||||
const QString testInputString = QStringLiteral(
|
const QString testInputString = QStringLiteral(
|
||||||
@@ -274,6 +288,7 @@ void TextHandlerTest::receiveRichInPlainOut_data()
|
|||||||
QTest::newRow("ampersand") << QStringLiteral("a & b") << QStringLiteral("a & b");
|
QTest::newRow("ampersand") << QStringLiteral("a & b") << QStringLiteral("a & b");
|
||||||
QTest::newRow("quote") << QStringLiteral(""a and b"") << QStringLiteral("\"a and b\"");
|
QTest::newRow("quote") << QStringLiteral(""a and b"") << QStringLiteral("\"a and b\"");
|
||||||
QTest::newRow("new line") << QStringLiteral("new<br>line") << QStringLiteral("new\nline");
|
QTest::newRow("new line") << QStringLiteral("new<br>line") << QStringLiteral("new\nline");
|
||||||
|
QTest::newRow("unescape") << QStringLiteral("can't") << QStringLiteral("can't");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::receiveRichInPlainOut()
|
void TextHandlerTest::receiveRichInPlainOut()
|
||||||
@@ -448,6 +463,9 @@ void TextHandlerTest::receiveRichPlainUrl()
|
|||||||
QString testOutputStringMxId = QStringLiteral(
|
QString testOutputStringMxId = QStringLiteral(
|
||||||
"<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>");
|
"<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 = QStringLiteral("a @user:kde.org b");
|
||||||
|
QString testOutputStringMxIdWithPrefix = QStringLiteral("a <b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> b");
|
||||||
|
|
||||||
TextHandler testTextHandler;
|
TextHandler testTextHandler;
|
||||||
testTextHandler.setData(testInputStringLink1);
|
testTextHandler.setData(testInputStringLink1);
|
||||||
|
|
||||||
@@ -461,6 +479,9 @@ void TextHandlerTest::receiveRichPlainUrl()
|
|||||||
|
|
||||||
testTextHandler.setData(testInputStringMxId);
|
testTextHandler.setData(testInputStringMxId);
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxId);
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxId);
|
||||||
|
|
||||||
|
testTextHandler.setData(testInputStringMxIdWithPrefix);
|
||||||
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxIdWithPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::receiveRichEdited_data()
|
void TextHandlerTest::receiveRichEdited_data()
|
||||||
@@ -535,7 +556,7 @@ void TextHandlerTest::componentOutput_data()
|
|||||||
"someField }\nCustomQml {\n someTextProperty: someField.text\n}\n</code></pre>Sure you can, it's still local to the same file where you "
|
"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")
|
"defined the id")
|
||||||
<< QList<MessageComponent>{
|
<< QList<MessageComponent>{
|
||||||
MessageComponent{MessageComponentType::Text, QStringLiteral("Ah, you mean something like"), {}},
|
MessageComponent{MessageComponentType::Text, QStringLiteral("Ah, you mean something like<br/>"), {}},
|
||||||
MessageComponent{
|
MessageComponent{
|
||||||
MessageComponentType::Code,
|
MessageComponentType::Code,
|
||||||
QStringLiteral(
|
QStringLiteral(
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ class WindowControllerTest : public QObject
|
|||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void nullWindow();
|
void nullWindow();
|
||||||
void geometry();
|
|
||||||
void showAndRaise();
|
void showAndRaise();
|
||||||
void toggle();
|
void toggle();
|
||||||
|
|
||||||
@@ -30,32 +29,10 @@ 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();
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
<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="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>
|
||||||
@@ -61,6 +62,7 @@
|
|||||||
<summary xml:lang="fi">Keskustelu ystäviesi kanssa Matrixissa</summary>
|
<summary xml:lang="fi">Keskustelu ystäviesi kanssa Matrixissa</summary>
|
||||||
<summary xml:lang="fr">Discuter avec vos ami(e)s sur le réseau Matrix</summary>
|
<summary xml:lang="fr">Discuter avec vos ami(e)s sur le réseau Matrix</summary>
|
||||||
<summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary>
|
<summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary>
|
||||||
|
<summary xml:lang="he">התכתבות עם החברים שלך ב־matrix</summary>
|
||||||
<summary xml:lang="hu">Csevegjen barátaival a matrixon</summary>
|
<summary xml:lang="hu">Csevegjen barátaival a matrixon</summary>
|
||||||
<summary xml:lang="ia">Starta Conversation con tu amicos sur matrix</summary>
|
<summary xml:lang="ia">Starta Conversation con tu amicos sur matrix</summary>
|
||||||
<summary xml:lang="it">Conversa con i tuoi contatti su matrix</summary>
|
<summary xml:lang="it">Conversa con i tuoi contatti su matrix</summary>
|
||||||
@@ -89,6 +91,8 @@
|
|||||||
<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="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 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="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 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="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 é 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="he">NeoChat הוא יישום התכתבות שמאפשר לך לנצל את רשת Matrix במלואה. הוא מספק דרך מאובטחת לשליחת הודעות כתובות, סרטונים וקובצי שמע למשפחה, לעמיתים לעבודה ולחברים.</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="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="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="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="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="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>
|
||||||
@@ -114,6 +118,7 @@
|
|||||||
<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 é implementar a 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="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 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="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>
|
||||||
@@ -142,6 +147,7 @@
|
|||||||
<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="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>
|
||||||
@@ -172,6 +178,7 @@
|
|||||||
<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="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>
|
||||||
@@ -200,6 +207,7 @@
|
|||||||
<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="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>
|
||||||
@@ -229,6 +237,7 @@
|
|||||||
<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="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>
|
||||||
@@ -292,6 +301,7 @@
|
|||||||
<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="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>
|
||||||
@@ -323,6 +333,8 @@
|
|||||||
<caption xml:lang="eu">Ezagutu komunitate berriak Matrixeko Tokiak erabiliz</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="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="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="hu">Fedezzen fel új közösségeket a Matrix Terek segítségével</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="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="it">Scopri nuove comunità con Matrix Spaces</caption>
|
||||||
@@ -358,6 +370,7 @@
|
|||||||
<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="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>
|
||||||
@@ -391,6 +404,7 @@
|
|||||||
<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="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>
|
||||||
@@ -415,6 +429,8 @@
|
|||||||
<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.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.2" date="2024-07-04"/>
|
||||||
<release version="24.05.1" date="2024-06-13"/>
|
<release version="24.05.1" date="2024-06-13"/>
|
||||||
<release version="24.05.0" date="2024-05-23"/>
|
<release version="24.05.0" date="2024-05-23"/>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ 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[hu]=NeoChat
|
Name[hu]=NeoChat
|
||||||
Name[ia]=Neochat
|
Name[ia]=Neochat
|
||||||
Name[id]=NeoChat
|
Name[id]=NeoChat
|
||||||
@@ -59,6 +60,7 @@ 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[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
|
||||||
@@ -99,6 +101,7 @@ Comment[eu]=Matrix protokolorako bezeroa
|
|||||||
Comment[fi]=Asiakas Matrix-yhteyskäytännölle
|
Comment[fi]=Asiakas Matrix-yhteyskäytännölle
|
||||||
Comment[fr]=Client pour le protocole « Matrix »
|
Comment[fr]=Client pour le protocole « Matrix »
|
||||||
Comment[gl]=Cliente para o protocolo Matrix.
|
Comment[gl]=Cliente para o protocolo Matrix.
|
||||||
|
Comment[he]=לקוח לפרוטוקול Matrix
|
||||||
Comment[hu]=Kliens a Matrix protokollhoz
|
Comment[hu]=Kliens a Matrix protokollhoz
|
||||||
Comment[ia]=Cliente per le protocollo de Matrix
|
Comment[ia]=Cliente per le protocollo de Matrix
|
||||||
Comment[id]=Klien untuk protokol Matrix
|
Comment[id]=Klien untuk protokol Matrix
|
||||||
|
|||||||
2768
po/ar/neochat.po
2768
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
2446
po/ast/neochat.po
2446
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
3030
po/az/neochat.po
3030
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
2809
po/ca/neochat.po
2809
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2689
po/cs/neochat.po
2689
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
2750
po/da/neochat.po
2750
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
3036
po/de/neochat.po
3036
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
3045
po/el/neochat.po
3045
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
2778
po/en_GB/neochat.po
2778
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
2696
po/eo/neochat.po
2696
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
2771
po/es/neochat.po
2771
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
2770
po/eu/neochat.po
2770
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
2999
po/fi/neochat.po
2999
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
2793
po/fr/neochat.po
2793
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
5724
po/gl/neochat.po
Normal file
5724
po/gl/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
2860
po/hu/neochat.po
2860
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
2776
po/ia/neochat.po
2776
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
3046
po/id/neochat.po
3046
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
2921
po/ie/neochat.po
2921
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
2831
po/it/neochat.po
2831
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
2444
po/ja/neochat.po
2444
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
2770
po/ka/neochat.po
2770
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
2985
po/ko/neochat.po
2985
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
2450
po/lt/neochat.po
2450
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
2978
po/lv/neochat.po
2978
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
2803
po/nl/neochat.po
2803
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
2629
po/nn/neochat.po
2629
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
2943
po/pa/neochat.po
2943
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
2776
po/pl/neochat.po
2776
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
3032
po/pt/neochat.po
3032
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
3062
po/pt_BR/neochat.po
3062
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
3008
po/ru/neochat.po
3008
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
2973
po/sk/neochat.po
2973
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
2750
po/sl/neochat.po
2750
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
2782
po/sv/neochat.po
2782
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
2761
po/ta/neochat.po
2761
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
2739
po/tok/neochat.po
2739
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
2739
po/tr/neochat.po
2739
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
2798
po/uk/neochat.po
2798
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
2530
po/zh_CN/neochat.po
2530
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
2719
po/zh_TW/neochat.po
2719
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -20,8 +20,6 @@ add_library(neochat STATIC
|
|||||||
models/customemojimodel.h
|
models/customemojimodel.h
|
||||||
clipboard.cpp
|
clipboard.cpp
|
||||||
clipboard.h
|
clipboard.h
|
||||||
matriximageprovider.cpp
|
|
||||||
matriximageprovider.h
|
|
||||||
models/messageeventmodel.cpp
|
models/messageeventmodel.cpp
|
||||||
models/messageeventmodel.h
|
models/messageeventmodel.h
|
||||||
models/messagefiltermodel.cpp
|
models/messagefiltermodel.cpp
|
||||||
@@ -136,6 +134,8 @@ add_library(neochat STATIC
|
|||||||
jobs/neochatdeletedevicejob.h
|
jobs/neochatdeletedevicejob.h
|
||||||
jobs/neochatchangepasswordjob.cpp
|
jobs/neochatchangepasswordjob.cpp
|
||||||
jobs/neochatchangepasswordjob.h
|
jobs/neochatchangepasswordjob.h
|
||||||
|
jobs/neochatgetcommonroomsjob.cpp
|
||||||
|
jobs/neochatgetcommonroomsjob.h
|
||||||
mediasizehelper.cpp
|
mediasizehelper.cpp
|
||||||
mediasizehelper.h
|
mediasizehelper.h
|
||||||
eventhandler.cpp
|
eventhandler.cpp
|
||||||
@@ -158,7 +158,6 @@ add_library(neochat STATIC
|
|||||||
models/linemodel.cpp
|
models/linemodel.cpp
|
||||||
models/linemodel.h
|
models/linemodel.h
|
||||||
events/locationbeaconevent.h
|
events/locationbeaconevent.h
|
||||||
events/serveraclevent.h
|
|
||||||
events/widgetevent.h
|
events/widgetevent.h
|
||||||
enums/messagecomponenttype.h
|
enums/messagecomponenttype.h
|
||||||
models/messagecontentmodel.cpp
|
models/messagecontentmodel.cpp
|
||||||
@@ -177,13 +176,31 @@ add_library(neochat STATIC
|
|||||||
foreigntypes.h
|
foreigntypes.h
|
||||||
models/threepidmodel.cpp
|
models/threepidmodel.cpp
|
||||||
models/threepidmodel.h
|
models/threepidmodel.h
|
||||||
|
threepidaddhelper.cpp
|
||||||
|
threepidaddhelper.h
|
||||||
|
jobs/neochatadd3pidjob.cpp
|
||||||
|
jobs/neochatadd3pidjob.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
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||||
QT_QML_SINGLETON_TYPE TRUE
|
QT_QML_SINGLETON_TYPE TRUE
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
||||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
|
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
|
||||||
QML_FILES
|
QML_FILES
|
||||||
qml/Main.qml
|
qml/Main.qml
|
||||||
@@ -207,16 +224,10 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
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/EmojiPicker.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
|
||||||
@@ -231,14 +242,9 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/EditMenu.qml
|
qml/EditMenu.qml
|
||||||
qml/MessageDelegateContextMenu.qml
|
qml/MessageDelegateContextMenu.qml
|
||||||
qml/FileDelegateContextMenu.qml
|
qml/FileDelegateContextMenu.qml
|
||||||
|
qml/FileDelegateContextMenuMobile.qml
|
||||||
qml/MessageSourceSheet.qml
|
qml/MessageSourceSheet.qml
|
||||||
qml/ReportSheet.qml
|
|
||||||
qml/ConfirmEncryptionDialog.qml
|
qml/ConfirmEncryptionDialog.qml
|
||||||
qml/RemoveSheet.qml
|
|
||||||
qml/BanSheet.qml
|
|
||||||
qml/EmojiTonesPicker.qml
|
|
||||||
qml/EmojiDelegate.qml
|
|
||||||
qml/EmojiGrid.qml
|
|
||||||
qml/RoomSearchPage.qml
|
qml/RoomSearchPage.qml
|
||||||
qml/LocationChooser.qml
|
qml/LocationChooser.qml
|
||||||
qml/TimelineView.qml
|
qml/TimelineView.qml
|
||||||
@@ -262,7 +268,6 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/SelectParentDialog.qml
|
qml/SelectParentDialog.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/SearchPage.qml
|
||||||
qml/ServerComboBox.qml
|
qml/ServerComboBox.qml
|
||||||
@@ -280,14 +285,29 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/ConfirmLeaveDialog.qml
|
qml/ConfirmLeaveDialog.qml
|
||||||
qml/CodeMaximizeComponent.qml
|
qml/CodeMaximizeComponent.qml
|
||||||
qml/EditStateDialog.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(settings)
|
||||||
add_subdirectory(timeline)
|
add_subdirectory(timeline)
|
||||||
add_subdirectory(devtools)
|
add_subdirectory(devtools)
|
||||||
add_subdirectory(login)
|
add_subdirectory(login)
|
||||||
|
add_subdirectory(chatbar)
|
||||||
|
|
||||||
if(UNIX)
|
if(NOT ANDROID AND NOT WIN32)
|
||||||
qt_target_qml_sources(neochat QML_FILES qml/ShareAction.qml)
|
qt_target_qml_sources(neochat QML_FILES qml/ShareAction.qml)
|
||||||
else()
|
else()
|
||||||
set_source_files_properties(qml/ShareActionStub.qml PROPERTIES
|
set_source_files_properties(qml/ShareActionStub.qml PROPERTIES
|
||||||
@@ -379,7 +399,7 @@ else()
|
|||||||
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)
|
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
|
||||||
@@ -407,7 +427,7 @@ if (TARGET KF6::Crash)
|
|||||||
target_link_libraries(neochat PUBLIC KF6::Crash)
|
target_link_libraries(neochat PUBLIC KF6::Crash)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
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)
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ void ActionsHandler::handleMessageEvent(ChatBarCache *chatBarCache)
|
|||||||
|
|
||||||
QString handledText = chatBarCache->text();
|
QString handledText = chatBarCache->text();
|
||||||
handledText = handleMentions(handledText, chatBarCache->mentions());
|
handledText = handleMentions(handledText, chatBarCache->mentions());
|
||||||
handleMessage(m_room->mainCache()->text(), handledText, chatBarCache);
|
handleMessage(chatBarCache->text(), handledText, chatBarCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ActionsHandler::handleMentions(QString handledText, QList<Mention> *mentions)
|
QString ActionsHandler::handleMentions(QString handledText, QList<Mention> *mentions)
|
||||||
@@ -91,7 +91,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
|
|||||||
|
|
||||||
for (auto it = m_room->messageEvents().crbegin(); it != m_room->messageEvents().crend(); it++) {
|
for (auto it = m_room->messageEvents().crbegin(); it != m_room->messageEvents().crend(); it++) {
|
||||||
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
|
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
|
||||||
if (event->senderId() == m_room->localUser()->id() && event->hasTextContent()) {
|
if (event->senderId() == m_room->localMember().id() && event->hasTextContent()) {
|
||||||
QString originalString;
|
QString originalString;
|
||||||
if (event->content()) {
|
if (event->content()) {
|
||||||
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
|
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ QQC2.Popup {
|
|||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.close();
|
root.close();
|
||||||
var fileDialog = openFileDialog.createObject(QQC2.ApplicationWindow.overlay);
|
var fileDialog = openFileDialog.createObject(QQC2.Overlay.overlay);
|
||||||
fileDialog.chosen.connect(path => root.chosen(path));
|
fileDialog.chosen.connect(path => root.chosen(path));
|
||||||
fileDialog.open();
|
fileDialog.open();
|
||||||
}
|
}
|
||||||
19
src/chatbar/CMakeLists.txt
Normal file
19
src/chatbar/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
qt_add_library(chatbar STATIC)
|
||||||
|
ecm_add_qml_module(chatbar GENERATE_PLUGIN_SOURCE
|
||||||
|
URI org.kde.neochat.chatbar
|
||||||
|
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/chatbar
|
||||||
|
QML_FILES
|
||||||
|
AttachDialog.qml
|
||||||
|
ChatBar.qml
|
||||||
|
CompletionMenu.qml
|
||||||
|
EmojiDelegate.qml
|
||||||
|
EmojiGrid.qml
|
||||||
|
ReplyPane.qml
|
||||||
|
PieProgressBar.qml
|
||||||
|
EmojiPicker.qml
|
||||||
|
EmojiDialog.qml
|
||||||
|
EmojiTonesPicker.qml
|
||||||
|
)
|
||||||
@@ -115,7 +115,7 @@ QQC2.Control {
|
|||||||
displayHint: QQC2.AbstractButton.IconOnly
|
displayHint: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
locationChooser.createObject(QQC2.ApplicationWindow.overlay, {
|
locationChooser.createObject(QQC2.Overlay.overlay, {
|
||||||
room: root.currentRoom
|
room: root.currentRoom
|
||||||
}).open();
|
}).open();
|
||||||
}
|
}
|
||||||
@@ -219,7 +219,7 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
if (!repeatTimer.running && Config.typingNotifications) {
|
if (!repeatTimer.running && NeoChatConfig.typingNotifications) {
|
||||||
var textExists = text.length > 0;
|
var textExists = text.length > 0;
|
||||||
root.currentRoom.sendTypingNotification(textExists);
|
root.currentRoom.sendTypingNotification(textExists);
|
||||||
textExists ? repeatTimer.start() : repeatTimer.stop();
|
textExists ? repeatTimer.start() : repeatTimer.stop();
|
||||||
@@ -353,8 +353,8 @@ QQC2.Control {
|
|||||||
startBreakpoint: Kirigami.Units.gridUnit * 46
|
startBreakpoint: Kirigami.Units.gridUnit * 46
|
||||||
endBreakpoint: Kirigami.Units.gridUnit * 66
|
endBreakpoint: Kirigami.Units.gridUnit * 66
|
||||||
startPercentWidth: 100
|
startPercentWidth: 100
|
||||||
endPercentWidth: Config.compactLayout ? 100 : 85
|
endPercentWidth: NeoChatConfig.compactLayout ? 100 : 85
|
||||||
maxWidth: Config.compactLayout ? -1 : Kirigami.Units.gridUnit * 60
|
maxWidth: NeoChatConfig.compactLayout ? -1 : Kirigami.Units.gridUnit * 60
|
||||||
|
|
||||||
parentWidth: root.width
|
parentWidth: root.width
|
||||||
}
|
}
|
||||||
@@ -364,7 +364,7 @@ QQC2.Control {
|
|||||||
ReplyPane {
|
ReplyPane {
|
||||||
userName: _private.chatBarCache.relationUser.displayName
|
userName: _private.chatBarCache.relationUser.displayName
|
||||||
userColor: _private.chatBarCache.relationUser.color
|
userColor: _private.chatBarCache.relationUser.color
|
||||||
userAvatar: _private.chatBarCache.relationUser.avatarSource
|
userAvatar: _private.chatBarCache.relationUser.avatarUrl
|
||||||
text: _private.chatBarCache.relationMessage
|
text: _private.chatBarCache.relationMessage
|
||||||
|
|
||||||
onCancel: {
|
onCancel: {
|
||||||
@@ -395,7 +395,7 @@ QQC2.Control {
|
|||||||
repeatTimer.stop();
|
repeatTimer.stop();
|
||||||
root.currentRoom.markAllMessagesAsRead();
|
root.currentRoom.markAllMessagesAsRead();
|
||||||
textField.clear();
|
textField.clear();
|
||||||
_private.chatBarCache.replyId = "";
|
_private.chatBarCache.clearRelations();
|
||||||
messageSent();
|
messageSent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ QQC2.ItemDelegate {
|
|||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
Kirigami.Heading {
|
Kirigami.Heading {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: !root.emoji.startsWith("image") && !root.isImage
|
visible: !root.emoji.startsWith("mxc") && !root.isImage
|
||||||
text: root.emoji
|
text: root.emoji
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
@@ -41,7 +41,7 @@ QQC2.ItemDelegate {
|
|||||||
}
|
}
|
||||||
Image {
|
Image {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: root.emoji.startsWith("image") || root.isImage
|
visible: root.emoji.startsWith("mxc") || root.isImage
|
||||||
source: visible ? root.emoji : ""
|
source: visible ? root.emoji : ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,18 +38,22 @@ QQC2.Popup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
background: Kirigami.ShadowedRectangle {
|
background: Kirigami.ShadowedRectangle {
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
|
||||||
color: Kirigami.Theme.backgroundColor
|
|
||||||
radius: Kirigami.Units.cornerRadius
|
radius: Kirigami.Units.cornerRadius
|
||||||
shadow {
|
color: Kirigami.Theme.backgroundColor
|
||||||
size: Kirigami.Units.largeSpacing
|
|
||||||
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)
|
|
||||||
yOffset: 2
|
|
||||||
}
|
|
||||||
border {
|
border {
|
||||||
color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
|
width: 1
|
||||||
width: 2
|
color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, Kirigami.Theme.frameContrast)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shadow {
|
||||||
|
size: Kirigami.Units.gridUnit
|
||||||
|
yOffset: 0
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Theme.inherit: false
|
||||||
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||||
}
|
}
|
||||||
|
|
||||||
modal: true
|
modal: true
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "chatbarcache.h"
|
#include "chatbarcache.h"
|
||||||
|
|
||||||
|
#include <Quotient/roommember.h>
|
||||||
|
|
||||||
#include "chatdocumenthandler.h"
|
#include "chatdocumenthandler.h"
|
||||||
#include "eventhandler.h"
|
#include "eventhandler.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
@@ -84,7 +86,7 @@ void ChatBarCache::setEditId(const QString &editId)
|
|||||||
Q_EMIT attachmentPathChanged();
|
Q_EMIT attachmentPathChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap ChatBarCache::relationUser() const
|
Quotient::RoomMember ChatBarCache::relationUser() const
|
||||||
{
|
{
|
||||||
if (parent() == nullptr) {
|
if (parent() == nullptr) {
|
||||||
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
|
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
|
||||||
@@ -96,9 +98,9 @@ QVariantMap ChatBarCache::relationUser() const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (m_relationId.isEmpty()) {
|
if (m_relationId.isEmpty()) {
|
||||||
return room->getUser(nullptr);
|
return room->member(QString());
|
||||||
}
|
}
|
||||||
return room->getUser(room->user((*room->findInTimeline(m_relationId))->senderId()));
|
return room->member((*room->findInTimeline(m_relationId))->senderId());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ChatBarCache::relationMessage() const
|
QString ChatBarCache::relationMessage() const
|
||||||
@@ -117,8 +119,7 @@ QString ChatBarCache::relationMessage() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (auto event = room->findInTimeline(m_relationId); event != room->historyEdge()) {
|
if (auto event = room->findInTimeline(m_relationId); event != room->historyEdge()) {
|
||||||
EventHandler eventhandler(room, &**event);
|
return EventHandler::markdownBody(&**event);
|
||||||
return eventhandler.getMarkdownBody();
|
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -138,8 +139,8 @@ void ChatBarCache::setThreadId(const QString &threadId)
|
|||||||
if (m_threadId == threadId) {
|
if (m_threadId == threadId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_threadId = threadId;
|
const auto oldThreadId = std::exchange(m_threadId, threadId);
|
||||||
Q_EMIT threadIdChanged();
|
Q_EMIT threadIdChanged(oldThreadId, m_threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ChatBarCache::attachmentPath() const
|
QString ChatBarCache::attachmentPath() const
|
||||||
@@ -159,6 +160,16 @@ void ChatBarCache::setAttachmentPath(const QString &attachmentPath)
|
|||||||
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatBarCache::clearRelations()
|
||||||
|
{
|
||||||
|
const auto oldEventId = std::exchange(m_relationId, QString());
|
||||||
|
const auto oldThreadId = std::exchange(m_threadId, QString());
|
||||||
|
m_attachmentPath = QString();
|
||||||
|
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
||||||
|
Q_EMIT threadIdChanged(oldThreadId, m_threadId);
|
||||||
|
Q_EMIT attachmentPathChanged();
|
||||||
|
}
|
||||||
|
|
||||||
QList<Mention> *ChatBarCache::mentions()
|
QList<Mention> *ChatBarCache::mentions()
|
||||||
{
|
{
|
||||||
return &m_mentions;
|
return &m_mentions;
|
||||||
|
|||||||
@@ -10,6 +10,12 @@
|
|||||||
|
|
||||||
class ChatDocumentHandler;
|
class ChatDocumentHandler;
|
||||||
|
|
||||||
|
namespace Quotient
|
||||||
|
{
|
||||||
|
class RoomMember;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Defines a user mention in the current chat or edit text.
|
* @brief Defines a user mention in the current chat or edit text.
|
||||||
*/
|
*/
|
||||||
@@ -27,7 +33,7 @@ struct Mention {
|
|||||||
* A class to cache data from a chat bar.
|
* A class to cache data from a chat bar.
|
||||||
*
|
*
|
||||||
* A chat bar can be anything that allows users to compose or edit message, it doesn't
|
* A chat bar can be anything that allows users to compose or edit message, it doesn't
|
||||||
* necessarily have to use the ChatBar component, e.g. MessageEditComponent.
|
* necessarily have to use the ChatBar component, e.g. ChatBarComponent.
|
||||||
*
|
*
|
||||||
* This object is intended to allow the current contents of a chat bar to be cached
|
* This object is intended to allow the current contents of a chat bar to be cached
|
||||||
* between different rooms, i.e. there is an expectation that each NeoChatRoom could
|
* between different rooms, i.e. there is an expectation that each NeoChatRoom could
|
||||||
@@ -37,7 +43,7 @@ struct Mention {
|
|||||||
* as it's parent. This is necessary for certain functions which need to get
|
* as it's parent. This is necessary for certain functions which need to get
|
||||||
* relevant room information.
|
* relevant room information.
|
||||||
*
|
*
|
||||||
* @sa ChatBar, MessageEditComponent, NeoChatRoom
|
* @sa ChatBar, ChatBarComponent, NeoChatRoom
|
||||||
*/
|
*/
|
||||||
class ChatBarCache : public QObject
|
class ChatBarCache : public QObject
|
||||||
{
|
{
|
||||||
@@ -88,26 +94,13 @@ class ChatBarCache : public QObject
|
|||||||
Q_PROPERTY(QString editId READ editId WRITE setEditId NOTIFY relationIdChanged)
|
Q_PROPERTY(QString editId READ editId WRITE setEditId NOTIFY relationIdChanged)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the user for the message being replied to.
|
* @brief Get the RoomMember object for the message being replied to.
|
||||||
*
|
*
|
||||||
* This is different to getting a Quotient::User object
|
* Returns an empty RoomMember if not replying to a message.
|
||||||
* as neither of those can provide details like the displayName or avatarMediaId
|
|
||||||
* without the room context as these can vary from room to room.
|
|
||||||
*
|
*
|
||||||
* Returns an empty user if not replying to a message.
|
* @sa Quotient::RoomMember
|
||||||
*
|
|
||||||
* The user QVariantMap has the following properties:
|
|
||||||
* - isLocalUser - Whether the user is the local user.
|
|
||||||
* - id - The matrix ID of the user.
|
|
||||||
* - displayName - Display name in the context of this room.
|
|
||||||
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
|
||||||
* - avatarMediaId - Avatar id in the context of this room.
|
|
||||||
* - color - Color for the user.
|
|
||||||
* - object - The Quotient::User object for the user.
|
|
||||||
*
|
|
||||||
* @sa getUser, Quotient::User
|
|
||||||
*/
|
*/
|
||||||
Q_PROPERTY(QVariantMap relationUser READ relationUser NOTIFY relationIdChanged)
|
Q_PROPERTY(Quotient::RoomMember relationUser READ relationUser NOTIFY relationIdChanged)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The content of the related message.
|
* @brief The content of the related message.
|
||||||
@@ -161,7 +154,7 @@ public:
|
|||||||
QString editId() const;
|
QString editId() const;
|
||||||
void setEditId(const QString &editId);
|
void setEditId(const QString &editId);
|
||||||
|
|
||||||
QVariantMap relationUser() const;
|
Quotient::RoomMember relationUser() const;
|
||||||
|
|
||||||
QString relationMessage() const;
|
QString relationMessage() const;
|
||||||
|
|
||||||
@@ -172,6 +165,13 @@ public:
|
|||||||
QString attachmentPath() const;
|
QString attachmentPath() const;
|
||||||
void setAttachmentPath(const QString &attachmentPath);
|
void setAttachmentPath(const QString &attachmentPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear all relations in the cache.
|
||||||
|
*
|
||||||
|
* This includes relation ID, thread root ID and attachment path.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void clearRelations();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve the mentions for the current chat bar text.
|
* @brief Retrieve the mentions for the current chat bar text.
|
||||||
*/
|
*/
|
||||||
@@ -195,7 +195,7 @@ public:
|
|||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void textChanged();
|
void textChanged();
|
||||||
void relationIdChanged(const QString &oldEventId, const QString &newEventId);
|
void relationIdChanged(const QString &oldEventId, const QString &newEventId);
|
||||||
void threadIdChanged();
|
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
|
||||||
void attachmentPathChanged();
|
void attachmentPathChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -26,23 +26,10 @@ void ColorSchemer::apply(int idx)
|
|||||||
c->activateScheme(c->model()->index(idx, 0));
|
c->activateScheme(c->model()->index(idx, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorSchemer::apply(const QString &name)
|
int ColorSchemer::indexForCurrentScheme()
|
||||||
{
|
{
|
||||||
c->activateScheme(c->indexForScheme(name));
|
return -1;
|
||||||
}
|
// return c->indexForSchemeId(c->activeSchemeId()).row();
|
||||||
|
|
||||||
int ColorSchemer::indexForScheme(const QString &name) const
|
|
||||||
{
|
|
||||||
auto index = c->indexForScheme(name).row();
|
|
||||||
if (index == -1) {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ColorSchemer::nameForIndex(int index) const
|
|
||||||
{
|
|
||||||
return c->model()->data(c->model()->index(index, 0), Qt::DisplayRole).toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_colorschemer.cpp"
|
#include "moc_colorschemer.cpp"
|
||||||
|
|||||||
@@ -44,21 +44,11 @@ public:
|
|||||||
Q_INVOKABLE void apply(int idx);
|
Q_INVOKABLE void apply(int idx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Activates the KColorScheme with the given name.
|
* @brief Get the row for the current color scheme.
|
||||||
*
|
*
|
||||||
* @sa KColorScheme
|
* @sa KColorScheme
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void apply(const QString &name);
|
Q_INVOKABLE int indexForCurrentScheme();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the index for the scheme with the given name.
|
|
||||||
*/
|
|
||||||
Q_INVOKABLE int indexForScheme(const QString &name) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the name for the scheme with the given index.
|
|
||||||
*/
|
|
||||||
Q_INVOKABLE QString nameForIndex(int index) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KColorSchemeManager *c;
|
KColorSchemeManager *c;
|
||||||
|
|||||||
@@ -9,27 +9,18 @@
|
|||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QNetworkProxy>
|
|
||||||
#include <QQuickTextDocument>
|
|
||||||
#include <QQuickWindow>
|
|
||||||
#include <QStandardPaths>
|
|
||||||
#include <QStringBuilder>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include <Quotient/accountregistry.h>
|
|
||||||
#include <Quotient/csapi/logout.h>
|
|
||||||
#include <Quotient/csapi/notifications.h>
|
#include <Quotient/csapi/notifications.h>
|
||||||
#include <Quotient/eventstats.h>
|
|
||||||
#include <Quotient/qt_connection_util.h>
|
#include <Quotient/qt_connection_util.h>
|
||||||
|
#include <Quotient/settings.h>
|
||||||
|
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
#include "neochatconnection.h"
|
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "notificationsmanager.h"
|
#include "notificationsmanager.h"
|
||||||
#include "proxycontroller.h"
|
#include "proxycontroller.h"
|
||||||
#include "roommanager.h"
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||||
#include "trayicon.h"
|
#include "trayicon.h"
|
||||||
@@ -45,6 +36,10 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_KUNIFIEDPUSH
|
||||||
|
#include <kunifiedpush/connector.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
bool testMode = false;
|
bool testMode = false;
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -67,7 +62,11 @@ Controller::Controller(QObject *parent)
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
auto c = new NeoChatConnection(this);
|
auto c = new NeoChatConnection(this);
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
|
c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("device_1234"), QStringLiteral("token_1234"));
|
||||||
|
#else
|
||||||
c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("token_1234"));
|
c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("token_1234"));
|
||||||
|
#endif
|
||||||
connect(c, &Connection::connected, this, [c, this]() {
|
connect(c, &Connection::connected, this, [c, this]() {
|
||||||
m_accountRegistry.add(c);
|
m_accountRegistry.add(c);
|
||||||
c->syncLoop();
|
c->syncLoop();
|
||||||
@@ -106,14 +105,16 @@ Controller::Controller(QObject *parent)
|
|||||||
connect(&m_accountRegistry, &AccountRegistry::accountCountChanged, this, [this]() {
|
connect(&m_accountRegistry, &AccountRegistry::accountCountChanged, this, [this]() {
|
||||||
if (m_accountRegistry.size() > oldAccountCount) {
|
if (m_accountRegistry.size() > oldAccountCount) {
|
||||||
auto connection = dynamic_cast<NeoChatConnection *>(m_accountRegistry.accounts()[m_accountRegistry.size() - 1]);
|
auto connection = dynamic_cast<NeoChatConnection *>(m_accountRegistry.accounts()[m_accountRegistry.size() - 1]);
|
||||||
connect(connection, &NeoChatConnection::syncDone, this, [connection]() {
|
connect(
|
||||||
NotificationsManager::instance().handleNotifications(connection);
|
connection,
|
||||||
});
|
&NeoChatConnection::syncDone,
|
||||||
connectSingleShot(connection, &NeoChatConnection::syncDone, this, [this, connection] {
|
this,
|
||||||
if (!m_endpoint.isEmpty()) {
|
[this, connection] {
|
||||||
connection->setupPushNotifications(m_endpoint);
|
if (!m_endpoint.isEmpty()) {
|
||||||
}
|
connection->setupPushNotifications(m_endpoint);
|
||||||
});
|
}
|
||||||
|
},
|
||||||
|
Qt::SingleShotConnection);
|
||||||
}
|
}
|
||||||
oldAccountCount = m_accountRegistry.size();
|
oldAccountCount = m_accountRegistry.size();
|
||||||
});
|
});
|
||||||
@@ -189,7 +190,7 @@ void Controller::invokeLogin()
|
|||||||
m_accountsLoading += accountId;
|
m_accountsLoading += accountId;
|
||||||
Q_EMIT accountsLoadingChanged();
|
Q_EMIT accountsLoadingChanged();
|
||||||
if (!account.homeserver().isEmpty()) {
|
if (!account.homeserver().isEmpty()) {
|
||||||
auto accessTokenLoadingJob = loadAccessTokenFromKeyChain(account);
|
auto accessTokenLoadingJob = loadAccessTokenFromKeyChain(account.userId());
|
||||||
connect(accessTokenLoadingJob, &QKeychain::Job::finished, this, [accountId, this, accessTokenLoadingJob](QKeychain::Job *) {
|
connect(accessTokenLoadingJob, &QKeychain::Job::finished, this, [accountId, this, accessTokenLoadingJob](QKeychain::Job *) {
|
||||||
AccountSettings account{accountId};
|
AccountSettings account{accountId};
|
||||||
QString accessToken;
|
QString accessToken;
|
||||||
@@ -203,25 +204,43 @@ void Controller::invokeLogin()
|
|||||||
m_connectionsLoading[accountId] = connection;
|
m_connectionsLoading[accountId] = connection;
|
||||||
connect(connection, &NeoChatConnection::connected, this, [this, connection, accountId] {
|
connect(connection, &NeoChatConnection::connected, this, [this, connection, accountId] {
|
||||||
connection->loadState();
|
connection->loadState();
|
||||||
addConnection(connection);
|
if (connection->allRooms().size() == 0 || connection->allRooms()[0]->currentState().get<RoomCreateEvent>()) {
|
||||||
m_accountsLoading.removeAll(connection->userId());
|
addConnection(connection);
|
||||||
m_connectionsLoading.remove(accountId);
|
m_accountsLoading.removeAll(connection->userId());
|
||||||
Q_EMIT accountsLoadingChanged();
|
m_connectionsLoading.remove(accountId);
|
||||||
|
Q_EMIT accountsLoadingChanged();
|
||||||
|
} else {
|
||||||
|
connect(
|
||||||
|
connection->allRooms()[0],
|
||||||
|
&Room::baseStateLoaded,
|
||||||
|
this,
|
||||||
|
[this, connection, accountId]() {
|
||||||
|
addConnection(connection);
|
||||||
|
m_accountsLoading.removeAll(connection->userId());
|
||||||
|
m_connectionsLoading.remove(accountId);
|
||||||
|
Q_EMIT accountsLoadingChanged();
|
||||||
|
},
|
||||||
|
Qt::SingleShotConnection);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
connect(connection, &NeoChatConnection::networkError, this, [this](const QString &error, const QString &, int, int) {
|
connect(connection, &NeoChatConnection::networkError, this, [this](const QString &error, const QString &, int, int) {
|
||||||
Q_EMIT errorOccured(i18n("Network Error: %1", error), {});
|
Q_EMIT errorOccured(i18n("Network Error: %1", error), {});
|
||||||
});
|
});
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
|
connection->assumeIdentity(account.userId(), account.deviceId(), accessToken);
|
||||||
|
#else
|
||||||
connection->assumeIdentity(account.userId(), accessToken);
|
connection->assumeIdentity(account.userId(), accessToken);
|
||||||
|
#endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const AccountSettings &account)
|
QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const QString &userId)
|
||||||
{
|
{
|
||||||
qDebug() << "Reading access token from the keychain for" << account.userId();
|
qDebug() << "Reading access token from the keychain for" << userId;
|
||||||
auto job = new QKeychain::ReadPasswordJob(qAppName(), this);
|
auto job = new QKeychain::ReadPasswordJob(qAppName(), this);
|
||||||
job->setKey(account.userId());
|
job->setKey(userId);
|
||||||
|
|
||||||
// Handling of errors
|
// Handling of errors
|
||||||
connect(job, &QKeychain::Job::finished, this, [this, job]() {
|
connect(job, &QKeychain::Job::finished, this, [this, job]() {
|
||||||
@@ -252,23 +271,19 @@ QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const Accoun
|
|||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::saveAccessTokenToKeyChain(const AccountSettings &account, const QByteArray &accessToken)
|
void Controller::saveAccessTokenToKeyChain(const QString &userId, const QByteArray &accessToken)
|
||||||
{
|
{
|
||||||
qDebug() << "Save the access token to the keychain for " << account.userId();
|
qDebug() << "Save the access token to the keychain for " << userId;
|
||||||
QKeychain::WritePasswordJob job(qAppName());
|
auto job = new QKeychain::WritePasswordJob(qAppName());
|
||||||
job.setAutoDelete(false);
|
job->setAutoDelete(true);
|
||||||
job.setKey(account.userId());
|
job->setKey(userId);
|
||||||
job.setBinaryData(accessToken);
|
job->setBinaryData(accessToken);
|
||||||
QEventLoop loop;
|
connect(job, &QKeychain::WritePasswordJob::finished, this, [job]() {
|
||||||
QKeychain::WritePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
|
if (job->error()) {
|
||||||
job.start();
|
qWarning() << "Could not save access token to the keychain: " << qPrintable(job->errorString());
|
||||||
loop.exec();
|
}
|
||||||
|
});
|
||||||
if (job.error()) {
|
job->start();
|
||||||
qWarning() << "Could not save access token to the keychain: " << qPrintable(job.errorString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::supportSystemTray() const
|
bool Controller::supportSystemTray() const
|
||||||
@@ -393,8 +408,6 @@ QString Controller::loadFileContent(const QString &path) const
|
|||||||
return QString::fromLatin1(file.readAll());
|
return QString::fromLatin1(file.readAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_controller.cpp"
|
|
||||||
|
|
||||||
void Controller::setTestMode(bool test)
|
void Controller::setTestMode(bool test)
|
||||||
{
|
{
|
||||||
testMode = test;
|
testMode = test;
|
||||||
@@ -410,11 +423,30 @@ void Controller::removeConnection(const QString &userId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::ssssSupported() const
|
bool Controller::csSupported() const
|
||||||
{
|
{
|
||||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
#if Quotient_VERSION_MINOR > 8
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Controller::revertToDefaultConfig()
|
||||||
|
{
|
||||||
|
const auto config = NeoChatConfig::self();
|
||||||
|
config->setDefaults();
|
||||||
|
config->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Controller::isImageShown(const QString &eventId)
|
||||||
|
{
|
||||||
|
return m_shownImages.contains(eventId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::markImageShown(const QString &eventId)
|
||||||
|
{
|
||||||
|
m_shownImages.append(eventId);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_controller.cpp"
|
||||||
|
|||||||
@@ -5,15 +5,9 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QQuickItem>
|
|
||||||
|
|
||||||
#include "neochatconnection.h"
|
#include "neochatconnection.h"
|
||||||
#include <Quotient/accountregistry.h>
|
#include <Quotient/accountregistry.h>
|
||||||
#include <Quotient/settings.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_KUNIFIEDPUSH
|
|
||||||
#include <kunifiedpush/connector.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class TrayIcon;
|
class TrayIcon;
|
||||||
class QQuickTextDocument;
|
class QQuickTextDocument;
|
||||||
@@ -56,9 +50,19 @@ class Controller : public QObject
|
|||||||
|
|
||||||
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
|
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
|
||||||
|
|
||||||
Q_PROPERTY(bool ssssSupported READ ssssSupported CONSTANT)
|
Q_PROPERTY(bool csSupported READ csSupported CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Define the types on inline messages that can be shown.
|
||||||
|
*/
|
||||||
|
enum MessageType {
|
||||||
|
Positive, /**< Positive message, typically green. */
|
||||||
|
Info, /**< Info message, typically highlight color. */
|
||||||
|
Error, /**< Error message, typically red. */
|
||||||
|
};
|
||||||
|
Q_ENUM(MessageType)
|
||||||
|
|
||||||
static Controller &instance();
|
static Controller &instance();
|
||||||
static Controller *create(QQmlEngine *engine, QJSEngine *)
|
static Controller *create(QQmlEngine *engine, QJSEngine *)
|
||||||
{
|
{
|
||||||
@@ -82,7 +86,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Save an access token to the keychain for the given account.
|
* @brief Save an access token to the keychain for the given account.
|
||||||
*/
|
*/
|
||||||
bool saveAccessTokenToKeyChain(const Quotient::AccountSettings &account, const QByteArray &accessToken);
|
void saveAccessTokenToKeyChain(const QString &userId, const QByteArray &accessToken);
|
||||||
|
|
||||||
[[nodiscard]] bool supportSystemTray() const;
|
[[nodiscard]] bool supportSystemTray() const;
|
||||||
|
|
||||||
@@ -102,7 +106,18 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE void removeConnection(const QString &userId);
|
Q_INVOKABLE void removeConnection(const QString &userId);
|
||||||
|
|
||||||
bool ssssSupported() const;
|
bool csSupported() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Revert all configuration values to their default.
|
||||||
|
*
|
||||||
|
* The parameters along with their defaults are specified in the config file
|
||||||
|
* neochatconfig.kcfg.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void revertToDefaultConfig();
|
||||||
|
|
||||||
|
Q_INVOKABLE bool isImageShown(const QString &eventId);
|
||||||
|
Q_INVOKABLE void markImageShown(const QString &eventId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Controller(QObject *parent = nullptr);
|
explicit Controller(QObject *parent = nullptr);
|
||||||
@@ -110,15 +125,13 @@ private:
|
|||||||
QPointer<NeoChatConnection> m_connection;
|
QPointer<NeoChatConnection> m_connection;
|
||||||
TrayIcon *m_trayIcon = nullptr;
|
TrayIcon *m_trayIcon = nullptr;
|
||||||
|
|
||||||
QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const Quotient::AccountSettings &account);
|
QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const QString &account);
|
||||||
|
|
||||||
void loadSettings();
|
|
||||||
void saveSettings() const;
|
|
||||||
|
|
||||||
Quotient::AccountRegistry m_accountRegistry;
|
Quotient::AccountRegistry m_accountRegistry;
|
||||||
QStringList m_accountsLoading;
|
QStringList m_accountsLoading;
|
||||||
QMap<QString, QPointer<NeoChatConnection>> m_connectionsLoading;
|
QMap<QString, QPointer<NeoChatConnection>> m_connectionsLoading;
|
||||||
QString m_endpoint;
|
QString m_endpoint;
|
||||||
|
QStringList m_shownImages;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void invokeLogin();
|
void invokeLogin();
|
||||||
@@ -131,4 +144,5 @@ Q_SIGNALS:
|
|||||||
void connectionDropped(NeoChatConnection *connection);
|
void connectionDropped(NeoChatConnection *connection);
|
||||||
void activeConnectionChanged(NeoChatConnection *connection);
|
void activeConnectionChanged(NeoChatConnection *connection);
|
||||||
void accountsLoadingChanged();
|
void accountsLoadingChanged();
|
||||||
|
void showMessage(MessageType messageType, const QString &message);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
qt_add_library(devtools STATIC)
|
qt_add_library(devtools STATIC)
|
||||||
qt_add_qml_module(devtools
|
ecm_add_qml_module(devtools GENERATE_PLUGIN_SOURCE
|
||||||
URI org.kde.neochat.devtools
|
URI org.kde.neochat.devtools
|
||||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/devtools
|
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/devtools
|
||||||
QML_FILES
|
QML_FILES
|
||||||
|
|||||||
@@ -17,25 +17,25 @@ FormCard.FormCardPage {
|
|||||||
|
|
||||||
FormCard.FormCheckDelegate {
|
FormCard.FormCheckDelegate {
|
||||||
text: i18nc("@option:check", "Show hidden events in the timeline")
|
text: i18nc("@option:check", "Show hidden events in the timeline")
|
||||||
checked: Config.showAllEvents
|
checked: NeoChatConfig.showAllEvents
|
||||||
|
|
||||||
onToggled: Config.showAllEvents = checked
|
onToggled: NeoChatConfig.showAllEvents = checked
|
||||||
}
|
}
|
||||||
FormCard.FormCheckDelegate {
|
FormCard.FormCheckDelegate {
|
||||||
id: roomAccountDataVisibleCheck
|
id: roomAccountDataVisibleCheck
|
||||||
text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification")
|
text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification")
|
||||||
description: i18n("Allow the user to start a verification session with devices that were already verified")
|
description: i18n("Allow the user to start a verification session with devices that were already verified")
|
||||||
checked: Config.alwaysVerifyDevice
|
checked: NeoChatConfig.alwaysVerifyDevice
|
||||||
|
|
||||||
onToggled: Config.alwaysVerifyDevice = checked
|
onToggled: NeoChatConfig.alwaysVerifyDevice = checked
|
||||||
}
|
}
|
||||||
FormCard.FormCheckDelegate {
|
FormCard.FormCheckDelegate {
|
||||||
text: i18nc("@option:check", "Show focus in window header")
|
text: i18nc("@option:check", "Show focus in window header")
|
||||||
checked: Config.windowTitleFocus
|
checked: NeoChatConfig.windowTitleFocus
|
||||||
|
|
||||||
onToggled: {
|
onToggled: {
|
||||||
Config.windowTitleFocus = checked;
|
NeoChatConfig.windowTitleFocus = checked;
|
||||||
Config.save();
|
NeoChatConfig.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ FormCard.FormCardPage {
|
|||||||
implicitWidth: tabBar.tabWidth
|
implicitWidth: tabBar.tabWidth
|
||||||
}
|
}
|
||||||
QQC2.TabButton {
|
QQC2.TabButton {
|
||||||
text: qsTr("Room Data")
|
text: i18nc("@title:tab", "Room Data")
|
||||||
|
|
||||||
implicitWidth: tabBar.tabWidth
|
implicitWidth: tabBar.tabWidth
|
||||||
}
|
}
|
||||||
QQC2.TabButton {
|
QQC2.TabButton {
|
||||||
text: qsTr("Server Info")
|
text: i18nc("@title:tab", "Server Info")
|
||||||
|
|
||||||
implicitWidth: tabBar.tabWidth
|
implicitWidth: tabBar.tabWidth
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,24 @@ FormCard.FormCardPage {
|
|||||||
FormCard.FormCheckDelegate {
|
FormCard.FormCheckDelegate {
|
||||||
id: roomAccountDataVisibleCheck
|
id: roomAccountDataVisibleCheck
|
||||||
text: i18nc("@option:check Enable the matrix 'threads' feature", "Threads")
|
text: i18nc("@option:check Enable the matrix 'threads' feature", "Threads")
|
||||||
checked: Config.threads
|
checked: NeoChatConfig.threads
|
||||||
|
|
||||||
onToggled: Config.threads = checked
|
onToggled: NeoChatConfig.threads = checked
|
||||||
}
|
}
|
||||||
FormCard.FormCheckDelegate {
|
FormCard.FormCheckDelegate {
|
||||||
text: i18nc("@option:check Enable the matrix 'secret backup' feature", "Secret Backup")
|
text: i18nc("@option:check Enable the matrix 'secret backup' feature", "Secret Backup")
|
||||||
checked: Config.secretBackup
|
checked: NeoChatConfig.secretBackup
|
||||||
|
|
||||||
onToggled: Config.secretBackup = checked
|
onToggled: NeoChatConfig.secretBackup = checked
|
||||||
|
}
|
||||||
|
FormCard.FormCheckDelegate {
|
||||||
|
text: i18nc("@option:check Enable the matrix feature to add a phone number as a third party ID", "Add phone numbers as 3PIDs")
|
||||||
|
checked: NeoChatConfig.phone3PId
|
||||||
|
|
||||||
|
onToggled: {
|
||||||
|
NeoChatConfig.phone3PId = checked
|
||||||
|
NeoChatConfig.save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ public:
|
|||||||
ReadMarker, /**< The local user read marker. */
|
ReadMarker, /**< The local user read marker. */
|
||||||
Loading, /**< A delegate to tell the user more messages are being loaded. */
|
Loading, /**< A delegate to tell the user more messages are being loaded. */
|
||||||
TimelineEnd, /**< A delegate to inform that all messages are loaded. */
|
TimelineEnd, /**< A delegate to inform that all messages are loaded. */
|
||||||
|
Predecessor, /**< A delegate to show a room predecessor. */
|
||||||
|
Successor, /**< A delegate to show a room successor. */
|
||||||
Other, /**< Anything that cannot be classified as another type. */
|
Other, /**< Anything that cannot be classified as another type. */
|
||||||
};
|
};
|
||||||
Q_ENUM(Type);
|
Q_ENUM(Type);
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ public:
|
|||||||
* a room message.
|
* a room message.
|
||||||
*/
|
*/
|
||||||
enum Type {
|
enum Type {
|
||||||
|
Author, /**< The message sender and time. */
|
||||||
Text, /**< A text message. */
|
Text, /**< A text message. */
|
||||||
Image, /**< A message that is an image. */
|
Image, /**< A message that is an image. */
|
||||||
Audio, /**< A message that is an audio recording. */
|
Audio, /**< A message that is an audio recording. */
|
||||||
@@ -47,11 +48,11 @@ public:
|
|||||||
LiveLocation, /**< The initial event of a shared live location (i.e., the place where this is supposed to be shown in the timeline). */
|
LiveLocation, /**< The initial event of a shared live location (i.e., the place where this is supposed to be shown in the timeline). */
|
||||||
Encrypted, /**< An encrypted message that cannot be decrypted. */
|
Encrypted, /**< An encrypted message that cannot be decrypted. */
|
||||||
Reply, /**< A component to show a replied-to message. */
|
Reply, /**< A component to show a replied-to message. */
|
||||||
ReplyLoad, /**< A loading dialog for a reply. */
|
|
||||||
LinkPreview, /**< A preview of a URL in the message. */
|
LinkPreview, /**< A preview of a URL in the message. */
|
||||||
LinkPreviewLoad, /**< A loading dialog for a link preview. */
|
LinkPreviewLoad, /**< A loading dialog for a link preview. */
|
||||||
Edit, /**< A text edit for editing a message. */
|
ChatBar, /**< A text edit for editing a message. */
|
||||||
Verification, /**< A user verification session start message. */
|
Verification, /**< A user verification session start message. */
|
||||||
|
Loading, /**< The component is loading. */
|
||||||
Other, /**< Anything that cannot be classified as another type. */
|
Other, /**< Anything that cannot be classified as another type. */
|
||||||
};
|
};
|
||||||
Q_ENUM(Type);
|
Q_ENUM(Type);
|
||||||
|
|||||||
109
src/enums/powerlevel.cpp
Normal file
109
src/enums/powerlevel.cpp
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
// 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 "powerlevel.h"
|
||||||
|
|
||||||
|
QString PowerLevel::nameForLevel(Level level)
|
||||||
|
{
|
||||||
|
switch (level) {
|
||||||
|
case PowerLevel::Member:
|
||||||
|
return i18n("Member");
|
||||||
|
case PowerLevel::Moderator:
|
||||||
|
return i18n("Moderator");
|
||||||
|
case PowerLevel::Admin:
|
||||||
|
return i18n("Admin");
|
||||||
|
case PowerLevel::Mute:
|
||||||
|
return i18n("Mute");
|
||||||
|
case PowerLevel::Custom:
|
||||||
|
return i18n("Custom");
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PowerLevel::valueForLevel(Level level)
|
||||||
|
{
|
||||||
|
switch (level) {
|
||||||
|
case PowerLevel::Member:
|
||||||
|
return 0;
|
||||||
|
case PowerLevel::Moderator:
|
||||||
|
return 50;
|
||||||
|
case PowerLevel::Admin:
|
||||||
|
return 100;
|
||||||
|
case PowerLevel::Mute:
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PowerLevel::Level PowerLevel::levelForValue(int value)
|
||||||
|
{
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
return PowerLevel::Member;
|
||||||
|
case 50:
|
||||||
|
return PowerLevel::Moderator;
|
||||||
|
case 100:
|
||||||
|
return PowerLevel::Admin;
|
||||||
|
case -1:
|
||||||
|
return PowerLevel::Mute;
|
||||||
|
default:
|
||||||
|
return PowerLevel::Custom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PowerLevelModel::PowerLevelModel(QObject *parent)
|
||||||
|
: QAbstractListModel(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PowerLevelModel::showMute() const
|
||||||
|
{
|
||||||
|
return m_showMute;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PowerLevelModel::setShowMute(bool showMute)
|
||||||
|
{
|
||||||
|
if (showMute == m_showMute) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_showMute = showMute;
|
||||||
|
Q_EMIT showMuteChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PowerLevelModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (index.row() >= rowCount()) {
|
||||||
|
qDebug() << "PowerLevelModel, something's wrong: index.row() >= m_rules.count()";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto level = static_cast<PowerLevel::Level>(index.row());
|
||||||
|
if (role == NameRole) {
|
||||||
|
return i18nc("%1 is the name of the power level, e.g. admin and %2 is the value that represents.",
|
||||||
|
"%1 (%2)",
|
||||||
|
PowerLevel::nameForLevel(level),
|
||||||
|
PowerLevel::valueForLevel(level));
|
||||||
|
}
|
||||||
|
if (role == ValueRole) {
|
||||||
|
return PowerLevel::valueForLevel(level);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int PowerLevelModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return PowerLevel::NUMLevels - (m_showMute ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> PowerLevelModel::roleNames() const
|
||||||
|
{
|
||||||
|
return {{NameRole, "name"}, {ValueRole, "value"}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_powerlevel.cpp"
|
||||||
110
src/enums/powerlevel.h
Normal file
110
src/enums/powerlevel.h
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
// 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 <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PowerLevel
|
||||||
|
*
|
||||||
|
* This class is designed to define the PowerLevel enumeration.
|
||||||
|
*/
|
||||||
|
class PowerLevel : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_UNCREATABLE("")
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief The type of delegate that is needed for the event.
|
||||||
|
*
|
||||||
|
* @note While similar this is not the matrix event or message type. This is
|
||||||
|
* to tell a QML ListView what delegate to show for each event. So while
|
||||||
|
* similar to the spec it is not the same.
|
||||||
|
*/
|
||||||
|
enum Level {
|
||||||
|
Member, /**< A basic member. */
|
||||||
|
Moderator, /**< A moderator with enhanced powers. */
|
||||||
|
Admin, /**< The highest power level in the room. */
|
||||||
|
Mute, /**< The level to remove posting privileges. */
|
||||||
|
NUMLevels,
|
||||||
|
Custom, /**< A non-standard value. Intentionally after NUMLevels so it doesn't appear in the model. */
|
||||||
|
};
|
||||||
|
Q_ENUM(Level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a string representation of the enum value.
|
||||||
|
*/
|
||||||
|
static QString nameForLevel(Level level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the integer representation of the enum value.
|
||||||
|
*/
|
||||||
|
static int valueForLevel(Level level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the enum value for the given integer power level.
|
||||||
|
*/
|
||||||
|
static Level levelForValue(int value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PowerLevelModel
|
||||||
|
*
|
||||||
|
* A model visualize the allowed power levels.
|
||||||
|
*/
|
||||||
|
class PowerLevelModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
|
||||||
|
Q_PROPERTY(bool showMute READ showMute WRITE setShowMute NOTIFY showMuteChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Defines the model roles.
|
||||||
|
*/
|
||||||
|
enum Roles {
|
||||||
|
NameRole = Qt::DisplayRole, /**< The power level name. */
|
||||||
|
ValueRole, /**< The power level value. */
|
||||||
|
};
|
||||||
|
Q_ENUM(Roles)
|
||||||
|
|
||||||
|
explicit PowerLevelModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
[[nodiscard]] bool showMute() const;
|
||||||
|
void setShowMute(bool showMute);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the given role value at the given index.
|
||||||
|
*
|
||||||
|
* @sa QAbstractItemModel::data
|
||||||
|
*/
|
||||||
|
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of rows in the model.
|
||||||
|
*
|
||||||
|
* @sa QAbstractItemModel::rowCount
|
||||||
|
*/
|
||||||
|
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a mapping from Role enum values to role names.
|
||||||
|
*
|
||||||
|
* @sa Roles, QAbstractItemModel::roleNames()
|
||||||
|
*/
|
||||||
|
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void showMuteChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_showMute = true;
|
||||||
|
};
|
||||||
@@ -5,29 +5,27 @@
|
|||||||
|
|
||||||
#include <QMovie>
|
#include <QMovie>
|
||||||
|
|
||||||
|
#include <KFormat>
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
#include <Quotient/eventitem.h>
|
|
||||||
#include <Quotient/events/encryptionevent.h>
|
#include <Quotient/events/encryptionevent.h>
|
||||||
|
#include <Quotient/events/event.h>
|
||||||
#include <Quotient/events/reactionevent.h>
|
#include <Quotient/events/reactionevent.h>
|
||||||
#include <Quotient/events/redactionevent.h>
|
#include <Quotient/events/redactionevent.h>
|
||||||
#include <Quotient/events/roomavatarevent.h>
|
#include <Quotient/events/roomavatarevent.h>
|
||||||
#include <Quotient/events/roomcanonicalaliasevent.h>
|
#include <Quotient/events/roomcanonicalaliasevent.h>
|
||||||
|
#include <Quotient/events/roomevent.h>
|
||||||
#include <Quotient/events/roommemberevent.h>
|
#include <Quotient/events/roommemberevent.h>
|
||||||
#include <Quotient/events/roommessageevent.h>
|
|
||||||
#include <Quotient/events/roompowerlevelsevent.h>
|
#include <Quotient/events/roompowerlevelsevent.h>
|
||||||
#include <Quotient/events/simplestateevents.h>
|
#include <Quotient/events/simplestateevents.h>
|
||||||
#include <Quotient/events/stickerevent.h>
|
#include <Quotient/events/stickerevent.h>
|
||||||
#include <Quotient/quotient_common.h>
|
#include <Quotient/quotient_common.h>
|
||||||
|
#include <Quotient/roommember.h>
|
||||||
|
|
||||||
#include "eventhandler_logging.h"
|
#include "eventhandler_logging.h"
|
||||||
#include "events/locationbeaconevent.h"
|
#include "events/locationbeaconevent.h"
|
||||||
#include "events/pollevent.h"
|
#include "events/pollevent.h"
|
||||||
#include "events/serveraclevent.h"
|
|
||||||
#include "events/widgetevent.h"
|
#include "events/widgetevent.h"
|
||||||
#include "linkpreviewer.h"
|
|
||||||
#include "messagecomponenttype.h"
|
|
||||||
#include "models/reactionmodel.h"
|
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "texthandler.h"
|
#include "texthandler.h"
|
||||||
@@ -35,85 +33,53 @@
|
|||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
EventHandler::EventHandler(const NeoChatRoom *room, const RoomEvent *event)
|
QString EventHandler::id(const Quotient::RoomEvent *event)
|
||||||
: m_room(room)
|
|
||||||
, m_event(event)
|
|
||||||
{
|
{
|
||||||
}
|
if (event == nullptr) {
|
||||||
|
qCWarning(EventHandling) << "id called with event set to nullptr.";
|
||||||
QString EventHandler::getId() const
|
|
||||||
{
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getId called with m_event set to nullptr.";
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return !m_event->id().isEmpty() ? m_event->id() : m_event->transactionId();
|
return !event->id().isEmpty() ? event->id() : event->transactionId();
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageComponentType::Type EventHandler::messageComponentType() const
|
QString EventHandler::authorDisplayName(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool isPending)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (room == nullptr) {
|
||||||
qCWarning(EventHandling) << "messageComponentType called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "authorDisplayName called with room set to nullptr.";
|
||||||
return MessageComponentType::Other;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MessageComponentType::typeForEvent(*m_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantMap EventHandler::getAuthor(bool isPending) const
|
|
||||||
{
|
|
||||||
if (m_room == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getAuthor called with m_room set to nullptr.";
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
// If we have a room we can return an empty user by handing nullptr to m_room->getUser.
|
if (event == nullptr) {
|
||||||
if (m_event == nullptr) {
|
qCWarning(EventHandling) << "authorDisplayName called with event set to nullptr.";
|
||||||
qCWarning(EventHandling) << "getAuthor called with m_event set to nullptr. Returning empty user.";
|
|
||||||
return m_room->getUser(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
|
||||||
return m_room->getUser(author);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString EventHandler::getAuthorDisplayName(bool isPending) const
|
|
||||||
{
|
|
||||||
if (m_room == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getAuthorDisplayName called with m_room set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getAuthorDisplayName called with m_event set to nullptr.";
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is<RoomMemberEvent>(*m_event) && !m_event->unsignedJson()[QStringLiteral("prev_content")][QStringLiteral("displayname")].isNull()
|
if (is<RoomMemberEvent>(*event) && !event->unsignedJson()[QStringLiteral("prev_content")][QStringLiteral("displayname")].isNull()
|
||||||
&& m_event->stateKey() == m_event->senderId()) {
|
&& event->stateKey() == event->senderId()) {
|
||||||
auto previousDisplayName = m_event->unsignedJson()[QStringLiteral("prev_content")][QStringLiteral("displayname")].toString().toHtmlEscaped();
|
auto previousDisplayName = event->unsignedJson()[QStringLiteral("prev_content")][QStringLiteral("displayname")].toString().toHtmlEscaped();
|
||||||
if (previousDisplayName.isEmpty()) {
|
if (previousDisplayName.isEmpty()) {
|
||||||
previousDisplayName = m_event->senderId();
|
previousDisplayName = event->senderId();
|
||||||
}
|
}
|
||||||
return previousDisplayName;
|
return previousDisplayName;
|
||||||
} else {
|
} else {
|
||||||
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
const auto author = isPending ? room->localMember() : room->member(event->senderId());
|
||||||
return m_room->htmlSafeMemberName(author->id());
|
return author.htmlSafeDisplayName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::singleLineAuthorDisplayname(bool isPending) const
|
QString EventHandler::singleLineAuthorDisplayname(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool isPending)
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getAuthorDisplayName called with m_room set to nullptr.";
|
qCWarning(EventHandling) << "singleLineAuthorDisplayname called with room set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getAuthorDisplayName called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "singleLineAuthorDisplayname called with event set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
const auto author = isPending ? room->localMember() : room->member(event->senderId());
|
||||||
auto displayName = m_room->safeMemberName(author->id());
|
auto displayName = author.displayName();
|
||||||
displayName.replace(QStringLiteral("<br>\n"), QStringLiteral(" "));
|
displayName.replace(QStringLiteral("<br>\n"), QStringLiteral(" "));
|
||||||
displayName.replace(QStringLiteral("<br>"), QStringLiteral(" "));
|
displayName.replace(QStringLiteral("<br>"), QStringLiteral(" "));
|
||||||
displayName.replace(QStringLiteral("<br />\n"), QStringLiteral(" "));
|
displayName.replace(QStringLiteral("<br />\n"), QStringLiteral(" "));
|
||||||
@@ -123,10 +89,10 @@ QString EventHandler::singleLineAuthorDisplayname(bool isPending) const
|
|||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime EventHandler::getTime(bool isPending, QDateTime lastUpdated) const
|
QDateTime EventHandler::time(const Quotient::RoomEvent *event, bool isPending, QDateTime lastUpdated)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getTime called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "time called with event set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (isPending && lastUpdated == QDateTime()) {
|
if (isPending && lastUpdated == QDateTime()) {
|
||||||
@@ -134,24 +100,16 @@ QDateTime EventHandler::getTime(bool isPending, QDateTime lastUpdated) const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return isPending ? lastUpdated : m_event->originTimestamp();
|
return isPending ? lastUpdated : event->originTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getTimeString(bool relative, QLocale::FormatType format, bool isPending, QDateTime lastUpdated) const
|
QString EventHandler::timeString(const Quotient::RoomEvent *event, bool relative, QLocale::FormatType format, bool isPending, QDateTime lastUpdated)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
auto ts = time(event, isPending, lastUpdated);
|
||||||
qCWarning(EventHandling) << "getTimeString called with m_event set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (isPending && lastUpdated == QDateTime()) {
|
|
||||||
qCWarning(EventHandling) << "a value must be provided for lastUpdated for a pending event.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ts = getTime(isPending, lastUpdated);
|
|
||||||
if (ts.isValid()) {
|
if (ts.isValid()) {
|
||||||
if (relative) {
|
if (relative) {
|
||||||
return m_format.formatRelativeDate(ts.toLocalTime().date(), format);
|
KFormat formatter;
|
||||||
|
return formatter.formatRelativeDate(ts.toLocalTime().date(), format);
|
||||||
} else {
|
} else {
|
||||||
return QLocale().toString(ts.toLocalTime().time(), format);
|
return QLocale().toString(ts.toLocalTime().time(), format);
|
||||||
}
|
}
|
||||||
@@ -159,39 +117,45 @@ QString EventHandler::getTimeString(bool relative, QLocale::FormatType format, b
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventHandler::isHighlighted()
|
QString EventHandler::timeString(const Quotient::RoomEvent *event, const QString &format, bool isPending, const QDateTime &lastUpdated)
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
return time(event, isPending, lastUpdated).toLocalTime().toString(format);
|
||||||
qCWarning(EventHandling) << "isHighlighted called with m_room set to nullptr.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "isHighlighted called with m_event set to nullptr.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !m_room->isDirectChat() && m_room->isEventHighlighted(m_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventHandler::isHidden()
|
bool EventHandler::isHighlighted(const NeoChatRoom *room, const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (room == nullptr) {
|
||||||
qCWarning(EventHandling) << "isHidden called with m_room set to nullptr.";
|
qCWarning(EventHandling) << "isHighlighted called with room set to nullptr.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "isHidden called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "isHighlighted called with event set to nullptr.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_event->isStateEvent() && !NeoChatConfig::self()->showStateEvent()) {
|
return !room->isDirectChat() && room->isEventHighlighted(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EventHandler::isHidden(const NeoChatRoom *room, const Quotient::RoomEvent *event)
|
||||||
|
{
|
||||||
|
if (room == nullptr) {
|
||||||
|
qCWarning(EventHandling) << "isHidden called with room set to nullptr.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (event == nullptr) {
|
||||||
|
qCWarning(EventHandling) << "isHidden called with event set to nullptr.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->isStateEvent() && !NeoChatConfig::self()->showStateEvent()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto roomMemberEvent = eventCast<const RoomMemberEvent>(m_event)) {
|
if (auto roomMemberEvent = eventCast<const RoomMemberEvent>(event)) {
|
||||||
if ((roomMemberEvent->isJoin() || roomMemberEvent->isLeave()) && !NeoChatConfig::self()->showLeaveJoinEvent()) {
|
if ((roomMemberEvent->isJoin() || roomMemberEvent->isLeave()) && !NeoChatConfig::self()->showLeaveJoinEvent()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (roomMemberEvent->isRename() && !roomMemberEvent->isJoin() && !roomMemberEvent->isLeave() && !NeoChatConfig::self()->showRename()) {
|
} else if (roomMemberEvent->isRename() && roomMemberEvent->prevContent() && roomMemberEvent->prevContent()->membership == roomMemberEvent->membership()
|
||||||
|
&& !NeoChatConfig::self()->showRename()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (roomMemberEvent->isAvatarUpdate() && !roomMemberEvent->isJoin() && !roomMemberEvent->isLeave()
|
} else if (roomMemberEvent->isAvatarUpdate() && !roomMemberEvent->isJoin() && !roomMemberEvent->isLeave()
|
||||||
&& !NeoChatConfig::self()->showAvatarUpdate()) {
|
&& !NeoChatConfig::self()->showAvatarUpdate()) {
|
||||||
@@ -199,33 +163,33 @@ bool EventHandler::isHidden()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_event->isStateEvent() && eventCast<const StateEvent>(m_event)->repeatsState()) {
|
if (event->isStateEvent() && eventCast<const StateEvent>(event)->repeatsState()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// isReplacement?
|
// isReplacement?
|
||||||
if (auto e = eventCast<const RoomMessageEvent>(m_event)) {
|
if (auto e = eventCast<const RoomMessageEvent>(event)) {
|
||||||
if (!e->replacedEvent().isEmpty()) {
|
if (!e->replacedEvent().isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is<RedactionEvent>(*m_event) || is<ReactionEvent>(*m_event)) {
|
if (is<RedactionEvent>(*event) || is<ReactionEvent>(*event)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto e = eventCast<const RoomMessageEvent>(m_event)) {
|
if (auto e = eventCast<const RoomMessageEvent>(event)) {
|
||||||
if (!e->replacedEvent().isEmpty() && e->replacedEvent() != e->id()) {
|
if (!e->replacedEvent().isEmpty() && e->replacedEvent() != e->id()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_room->connection()->isIgnored(m_room->user(m_event->senderId()))) {
|
if (room->connection()->isIgnored(event->senderId())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// hide ending live location beacons
|
// hide ending live location beacons
|
||||||
if (m_event->isStateEvent() && m_event->matrixType() == "org.matrix.msc3672.beacon_info"_ls && !m_event->contentJson()["live"_ls].toBool()) {
|
if (event->isStateEvent() && event->matrixType() == "org.matrix.msc3672.beacon_info"_ls && !event->contentJson()["live"_ls].toBool()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,60 +207,73 @@ Qt::TextFormat EventHandler::messageBodyInputFormat(const Quotient::RoomMessageE
|
|||||||
|
|
||||||
QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
|
QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
|
||||||
{
|
{
|
||||||
|
QString body;
|
||||||
|
|
||||||
if (event.hasFileContent()) {
|
if (event.hasFileContent()) {
|
||||||
auto fileCaption = event.content()->fileInfo()->originalName;
|
// if filename is given or body is equal to filename,
|
||||||
if (fileCaption.isEmpty()) {
|
// then body is a caption
|
||||||
fileCaption = event.plainBody();
|
QString filename = event.content()->fileInfo()->originalName;
|
||||||
} else if (event.content()->fileInfo()->originalName != event.plainBody()) {
|
QString body = event.plainBody();
|
||||||
fileCaption = event.plainBody() + " | "_ls + fileCaption;
|
if (filename.isEmpty() || filename == body) {
|
||||||
|
return QString();
|
||||||
}
|
}
|
||||||
return fileCaption;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString body;
|
|
||||||
if (event.hasTextContent() && event.content()) {
|
if (event.hasTextContent() && event.content()) {
|
||||||
body = static_cast<const MessageEventContent::TextContent *>(event.content())->body;
|
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
||||||
} else {
|
} else {
|
||||||
body = event.plainBody();
|
body = event.plainBody();
|
||||||
}
|
}
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getRichBody(bool stripNewlines) const
|
QString EventHandler::richBody(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool stripNewlines)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getRichBody called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "richBody called with room set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return getBody(m_event, Qt::RichText, stripNewlines);
|
if (event == nullptr) {
|
||||||
|
qCWarning(EventHandling) << "richBody called with event set to nullptr.";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return getBody(room, event, Qt::RichText, stripNewlines);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getPlainBody(bool stripNewlines) const
|
QString EventHandler::plainBody(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool stripNewlines)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getPlainBody called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "plainBody called with room set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return getBody(m_event, Qt::PlainText, stripNewlines);
|
if (event == nullptr) {
|
||||||
|
qCWarning(EventHandling) << "plainBody called with event set to nullptr.";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return getBody(room, event, Qt::PlainText, stripNewlines);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getMarkdownBody() const
|
QString EventHandler::markdownBody(const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getMarkdownBody called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "markdownBody called with event set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_event->is<RoomMessageEvent>()) {
|
if (!event->is<RoomMessageEvent>()) {
|
||||||
qCWarning(EventHandling) << "getMarkdownBody called when m_event isn't a RoomMessageEvent.";
|
qCWarning(EventHandling) << "markdownBody called when event isn't a RoomMessageEvent.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto roomMessageEvent = eventCast<const RoomMessageEvent>(m_event);
|
const auto roomMessageEvent = eventCast<const RoomMessageEvent>(event);
|
||||||
return roomMessageEvent->plainBody();
|
|
||||||
|
QString plainBody = roomMessageEvent->plainBody();
|
||||||
|
plainBody.remove(TextRegex::removeReply);
|
||||||
|
return plainBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines) const
|
QString EventHandler::getBody(const NeoChatRoom *room, const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines)
|
||||||
{
|
{
|
||||||
if (event->isRedacted()) {
|
if (event->isRedacted()) {
|
||||||
auto reason = event->redactedBecause()->reason();
|
auto reason = event->redactedBecause()->reason();
|
||||||
@@ -307,23 +284,27 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
|||||||
|
|
||||||
return switchOnType(
|
return switchOnType(
|
||||||
*event,
|
*event,
|
||||||
[this, format, stripNewlines](const RoomMessageEvent &event) {
|
[room, format, stripNewlines](const RoomMessageEvent &event) {
|
||||||
return getMessageBody(event, format, stripNewlines);
|
return getMessageBody(room, event, format, stripNewlines);
|
||||||
},
|
},
|
||||||
[](const StickerEvent &e) {
|
[](const StickerEvent &e) {
|
||||||
return e.body();
|
return e.body();
|
||||||
},
|
},
|
||||||
[this, prettyPrint](const RoomMemberEvent &e) {
|
[room, prettyPrint](const RoomMemberEvent &e) {
|
||||||
// FIXME: Rewind to the name that was at the time of this event
|
// FIXME: Rewind to the name that was at the time of this event
|
||||||
auto subjectName = m_room->htmlSafeMemberName(e.userId());
|
auto subjectName = room->member(e.userId()).htmlSafeDisplayName();
|
||||||
if (e.membership() == Membership::Leave) {
|
if (e.membership() == Membership::Leave) {
|
||||||
if (e.prevContent() && e.prevContent()->displayName) {
|
if (e.prevContent() && e.prevContent()->displayName) {
|
||||||
subjectName = sanitized(*e.prevContent()->displayName).toHtmlEscaped();
|
subjectName = sanitized(*e.prevContent()->displayName);
|
||||||
|
if (prettyPrint) {
|
||||||
|
subjectName = subjectName.toHtmlEscaped();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prettyPrint) {
|
if (prettyPrint) {
|
||||||
subjectName = QStringLiteral("<a href=\"https://matrix.to/#/%1\">%2</a>").arg(e.userId(), subjectName);
|
subjectName = QStringLiteral("<a href=\"https://matrix.to/#/%1\" style=\"color: %2\">%3</a>")
|
||||||
|
.arg(e.userId(), room->member(e.userId()).color().name(), subjectName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The below code assumes senderName output in AuthorRole
|
// The below code assumes senderName output in AuthorRole
|
||||||
@@ -386,9 +367,13 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
|||||||
if (e.prevContent() && e.prevContent()->membership == Membership::Ban) {
|
if (e.prevContent() && e.prevContent()->membership == Membership::Ban) {
|
||||||
return (e.senderId() != e.userId()) ? i18n("unbanned %1", subjectName) : i18n("self-unbanned");
|
return (e.senderId() != e.userId()) ? i18n("unbanned %1", subjectName) : i18n("self-unbanned");
|
||||||
}
|
}
|
||||||
return (e.senderId() != e.userId())
|
if (e.senderId() == e.userId()) {
|
||||||
? i18n("has put %1 out of the room: %2", subjectName, e.contentJson()["reason"_ls].toString().toHtmlEscaped())
|
return i18n("left the room");
|
||||||
: i18n("left the room");
|
}
|
||||||
|
if (const auto &reason = e.contentJson()["reason"_ls].toString().toHtmlEscaped(); !reason.isEmpty()) {
|
||||||
|
return i18n("has put %1 out of the room: %2", subjectName, reason);
|
||||||
|
}
|
||||||
|
return i18n("has put %1 out of the room", subjectName);
|
||||||
case Membership::Ban:
|
case Membership::Ban:
|
||||||
if (e.senderId() != e.userId()) {
|
if (e.senderId() != e.userId()) {
|
||||||
if (e.reason().isEmpty()) {
|
if (e.reason().isEmpty()) {
|
||||||
@@ -437,7 +422,7 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
|||||||
[](const LocationBeaconEvent &e) {
|
[](const LocationBeaconEvent &e) {
|
||||||
return e.contentJson()["description"_ls].toString();
|
return e.contentJson()["description"_ls].toString();
|
||||||
},
|
},
|
||||||
[](const ServerAclEvent &) {
|
[](const RoomServerAclEvent &) {
|
||||||
return i18n("changed the server access control lists for this room");
|
return i18n("changed the server access control lists for this room");
|
||||||
},
|
},
|
||||||
[](const WidgetEvent &e) {
|
[](const WidgetEvent &e) {
|
||||||
@@ -459,7 +444,7 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
|||||||
i18n("Unknown event"));
|
i18n("Unknown event"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getMessageBody(const RoomMessageEvent &event, Qt::TextFormat format, bool stripNewlines) const
|
QString EventHandler::getMessageBody(const NeoChatRoom *room, const RoomMessageEvent &event, Qt::TextFormat format, bool stripNewlines)
|
||||||
{
|
{
|
||||||
TextHandler textHandler;
|
TextHandler textHandler;
|
||||||
|
|
||||||
@@ -476,7 +461,7 @@ QString EventHandler::getMessageBody(const RoomMessageEvent &event, Qt::TextForm
|
|||||||
|
|
||||||
QString body;
|
QString body;
|
||||||
if (event.hasTextContent() && event.content()) {
|
if (event.hasTextContent() && event.content()) {
|
||||||
body = static_cast<const MessageEventContent::TextContent *>(event.content())->body;
|
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
||||||
} else {
|
} else {
|
||||||
body = event.plainBody();
|
body = event.plainBody();
|
||||||
}
|
}
|
||||||
@@ -491,24 +476,24 @@ QString EventHandler::getMessageBody(const RoomMessageEvent &event, Qt::TextForm
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (format == Qt::RichText) {
|
if (format == Qt::RichText) {
|
||||||
return textHandler.handleRecieveRichText(inputFormat, m_room, &event, stripNewlines, event.isReplaced());
|
return textHandler.handleRecieveRichText(inputFormat, room, &event, stripNewlines, event.isReplaced());
|
||||||
} else {
|
} else {
|
||||||
return textHandler.handleRecievePlainText(inputFormat, stripNewlines);
|
return textHandler.handleRecievePlainText(inputFormat, stripNewlines);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getGenericBody() const
|
QString EventHandler::genericBody(const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getGenericBody called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "genericBody called with event set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (m_event->isRedacted()) {
|
if (event->isRedacted()) {
|
||||||
return i18n("<i>[This message was deleted]</i>");
|
return i18n("<i>[This message was deleted]</i>");
|
||||||
}
|
}
|
||||||
|
|
||||||
return switchOnType(
|
return switchOnType(
|
||||||
*m_event,
|
*event,
|
||||||
[](const RoomMessageEvent &e) {
|
[](const RoomMessageEvent &e) {
|
||||||
Q_UNUSED(e)
|
Q_UNUSED(e)
|
||||||
return i18n("sent a message");
|
return i18n("sent a message");
|
||||||
@@ -606,7 +591,7 @@ QString EventHandler::getGenericBody() const
|
|||||||
[](const LocationBeaconEvent &) {
|
[](const LocationBeaconEvent &) {
|
||||||
return i18n("sent a live location beacon");
|
return i18n("sent a live location beacon");
|
||||||
},
|
},
|
||||||
[](const ServerAclEvent &) {
|
[](const RoomServerAclEvent &) {
|
||||||
return i18n("changed the server access control lists for this room");
|
return i18n("changed the server access control lists for this room");
|
||||||
},
|
},
|
||||||
[](const WidgetEvent &e) {
|
[](const WidgetEvent &e) {
|
||||||
@@ -628,53 +613,68 @@ QString EventHandler::getGenericBody() const
|
|||||||
i18n("Unknown event"));
|
i18n("Unknown event"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::subtitleText() const
|
QString EventHandler::subtitleText(const NeoChatRoom *room, const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (room == nullptr) {
|
||||||
qCWarning(EventHandling) << "subtitleText called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "subtitleText called with room set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return singleLineAuthorDisplayname() + (m_event->isStateEvent() ? QLatin1String(" ") : QLatin1String(": ")) + getPlainBody(true);
|
if (event == nullptr) {
|
||||||
|
qCWarning(EventHandling) << "subtitleText called with event set to nullptr.";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return singleLineAuthorDisplayname(room, event) + (event->isStateEvent() ? QLatin1String(" ") : QLatin1String(": ")) + plainBody(room, event, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap EventHandler::getMediaInfo() const
|
QVariantMap EventHandler::mediaInfo(const NeoChatRoom *room, const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getMediaInfo called with m_room set to nullptr.";
|
qCWarning(EventHandling) << "mediaInfo called with room set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getMediaInfo called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "mediaInfo called with event set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return getMediaInfoForEvent(m_event);
|
return getMediaInfoForEvent(room, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap EventHandler::getMediaInfoForEvent(const Quotient::RoomEvent *event) const
|
QVariantMap EventHandler::getMediaInfoForEvent(const NeoChatRoom *room, const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
QString eventId = event->id();
|
QString eventId = event->id();
|
||||||
|
|
||||||
// Get the file info for the event.
|
// Get the file info for the event.
|
||||||
const EventContent::FileInfo *fileInfo;
|
|
||||||
bool isSticker = false;
|
|
||||||
if (event->is<RoomMessageEvent>()) {
|
if (event->is<RoomMessageEvent>()) {
|
||||||
auto roomMessageEvent = eventCast<const RoomMessageEvent>(event);
|
auto roomMessageEvent = eventCast<const RoomMessageEvent>(event);
|
||||||
if (!roomMessageEvent->hasFileContent()) {
|
if (!roomMessageEvent->hasFileContent()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EventContent::FileInfo *fileInfo;
|
||||||
fileInfo = roomMessageEvent->content()->fileInfo();
|
fileInfo = roomMessageEvent->content()->fileInfo();
|
||||||
|
QVariantMap mediaInfo = getMediaInfoFromFileInfo(room, fileInfo, eventId, false, false);
|
||||||
|
// if filename isn't specifically given, it is in body
|
||||||
|
// https://spec.matrix.org/latest/client-server-api/#mfile
|
||||||
|
mediaInfo["filename"_ls] = (fileInfo->originalName.isEmpty()) ? roomMessageEvent->plainBody() : fileInfo->originalName;
|
||||||
|
|
||||||
|
return mediaInfo;
|
||||||
} else if (event->is<StickerEvent>()) {
|
} else if (event->is<StickerEvent>()) {
|
||||||
|
const EventContent::FileInfo *fileInfo;
|
||||||
|
|
||||||
auto stickerEvent = eventCast<const StickerEvent>(event);
|
auto stickerEvent = eventCast<const StickerEvent>(event);
|
||||||
fileInfo = &stickerEvent->image();
|
fileInfo = &stickerEvent->image();
|
||||||
isSticker = true;
|
|
||||||
|
return getMediaInfoFromFileInfo(room, fileInfo, eventId, false, true);
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return getMediaInfoFromFileInfo(fileInfo, eventId, false, isSticker);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap EventHandler::getMediaInfoFromFileInfo(const EventContent::FileInfo *fileInfo, const QString &eventId, bool isThumbnail, bool isSticker) const
|
QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
||||||
|
const EventContent::FileInfo *fileInfo,
|
||||||
|
const QString &eventId,
|
||||||
|
bool isThumbnail,
|
||||||
|
bool isSticker)
|
||||||
{
|
{
|
||||||
QVariantMap mediaInfo;
|
QVariantMap mediaInfo;
|
||||||
|
|
||||||
@@ -682,7 +682,7 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const EventContent::FileInfo
|
|||||||
if (!fileInfo->url().isValid() || fileInfo->url().scheme() != QStringLiteral("mxc") || eventId.isEmpty()) {
|
if (!fileInfo->url().isValid() || fileInfo->url().scheme() != QStringLiteral("mxc") || eventId.isEmpty()) {
|
||||||
mediaInfo["source"_ls] = QUrl();
|
mediaInfo["source"_ls] = QUrl();
|
||||||
} else {
|
} else {
|
||||||
QUrl source = m_room->makeMediaUrl(eventId, fileInfo->url());
|
QUrl source = room->makeMediaUrl(eventId, fileInfo->url());
|
||||||
|
|
||||||
if (source.isValid()) {
|
if (source.isValid()) {
|
||||||
mediaInfo["source"_ls] = source;
|
mediaInfo["source"_ls] = source;
|
||||||
@@ -714,7 +714,7 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const EventContent::FileInfo
|
|||||||
|
|
||||||
if (!isThumbnail) {
|
if (!isThumbnail) {
|
||||||
QVariantMap tempInfo;
|
QVariantMap tempInfo;
|
||||||
auto thumbnailInfo = getMediaInfoFromFileInfo(castInfo->thumbnailInfo(), eventId, true);
|
auto thumbnailInfo = getMediaInfoFromFileInfo(room, castInfo->thumbnailInfo(), eventId, true);
|
||||||
if (thumbnailInfo["source"_ls].toUrl().scheme() == "mxc"_ls) {
|
if (thumbnailInfo["source"_ls].toUrl().scheme() == "mxc"_ls) {
|
||||||
tempInfo = thumbnailInfo;
|
tempInfo = thumbnailInfo;
|
||||||
} else {
|
} else {
|
||||||
@@ -737,7 +737,7 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const EventContent::FileInfo
|
|||||||
|
|
||||||
if (!isThumbnail) {
|
if (!isThumbnail) {
|
||||||
QVariantMap tempInfo;
|
QVariantMap tempInfo;
|
||||||
auto thumbnailInfo = getMediaInfoFromFileInfo(castInfo->thumbnailInfo(), eventId, true);
|
auto thumbnailInfo = getMediaInfoFromFileInfo(room, castInfo->thumbnailInfo(), eventId, true);
|
||||||
if (thumbnailInfo["source"_ls].toUrl().scheme() == "mxc"_ls) {
|
if (thumbnailInfo["source"_ls].toUrl().scheme() == "mxc"_ls) {
|
||||||
tempInfo = thumbnailInfo;
|
tempInfo = thumbnailInfo;
|
||||||
} else {
|
} else {
|
||||||
@@ -761,160 +761,89 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const EventContent::FileInfo
|
|||||||
return mediaInfo;
|
return mediaInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventHandler::hasReply() const
|
bool EventHandler::hasReply(const Quotient::RoomEvent *event, bool showFallbacks)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "hasReply called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "hasReply called with event set to nullptr.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !m_event->contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString().isEmpty();
|
|
||||||
|
const auto relations = event->contentPart<QJsonObject>("m.relates_to"_ls);
|
||||||
|
if (!relations.isEmpty()) {
|
||||||
|
const bool hasReplyRelation = relations.contains("m.in_reply_to"_ls);
|
||||||
|
bool isFallingBack = relations["is_falling_back"_ls].toBool();
|
||||||
|
return hasReplyRelation && (showFallbacks ? true : !isFallingBack);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getReplyId() const
|
QString EventHandler::replyId(const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getReplyId called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "replyId called with event set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return m_event->contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString();
|
return event->contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageComponentType::Type EventHandler::replyMessageComponentType() const
|
Quotient::RoomMember EventHandler::replyAuthor(const NeoChatRoom *room, const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (room == nullptr) {
|
||||||
qCWarning(EventHandling) << "replyMessageComponentType called with m_room set to nullptr.";
|
qCWarning(EventHandling) << "replyAuthor called with room set to nullptr.";
|
||||||
return MessageComponentType::Other;
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "replyMessageComponentType called with m_event set to nullptr.";
|
|
||||||
return MessageComponentType::Other;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto replyEvent = m_room->getReplyForEvent(*m_event);
|
|
||||||
if (replyEvent == nullptr) {
|
|
||||||
return MessageComponentType::Other;
|
|
||||||
}
|
|
||||||
return MessageComponentType::typeForEvent(*replyEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantMap EventHandler::getReplyAuthor() const
|
|
||||||
{
|
|
||||||
if (m_room == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReplyAuthor called with m_room set to nullptr.";
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
// If we have a room we can return an empty user by handing nullptr to m_room->getUser.
|
if (event == nullptr) {
|
||||||
if (m_event == nullptr) {
|
qCWarning(EventHandling) << "replyAuthor called with event set to nullptr. Returning empty user.";
|
||||||
qCWarning(EventHandling) << "getReplyAuthor called with m_event set to nullptr. Returning empty user.";
|
return {};
|
||||||
return m_room->getUser(nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto replyPtr = m_room->getReplyForEvent(*m_event);
|
if (auto replyPtr = room->getReplyForEvent(*event)) {
|
||||||
|
return room->member(replyPtr->senderId());
|
||||||
if (replyPtr) {
|
|
||||||
auto replyUser = m_room->user(replyPtr->senderId());
|
|
||||||
return m_room->getUser(replyUser);
|
|
||||||
} else {
|
} else {
|
||||||
return m_room->getUser(nullptr);
|
return room->member(QString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getReplyRichBody(bool stripNewlines) const
|
bool EventHandler::isThreaded(const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getReplyRichBody called with m_room set to nullptr.";
|
qCWarning(EventHandling) << "isThreaded called with event set to nullptr.";
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReplyRichBody called with m_event set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto replyEvent = m_room->getReplyForEvent(*m_event);
|
|
||||||
if (replyEvent == nullptr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return getBody(replyEvent, Qt::RichText, stripNewlines);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString EventHandler::getReplyPlainBody(bool stripNewlines) const
|
|
||||||
{
|
|
||||||
if (m_room == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReplyPlainBody called with m_room set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReplyPlainBody called with m_event set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto replyEvent = m_room->getReplyForEvent(*m_event);
|
|
||||||
if (replyEvent == nullptr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return getBody(replyEvent, Qt::PlainText, stripNewlines);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantMap EventHandler::getReplyMediaInfo() const
|
|
||||||
{
|
|
||||||
if (m_room == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReplyMediaInfo called with m_room set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReplyMediaInfo called with m_event set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto replyPtr = m_room->getReplyForEvent(*m_event);
|
|
||||||
if (!replyPtr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return getMediaInfoForEvent(replyPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EventHandler::isThreaded() const
|
|
||||||
{
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "isThreaded called with m_event set to nullptr.";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (m_event->contentPart<QJsonObject>("m.relates_to"_ls).contains("rel_type"_ls)
|
return (event->contentPart<QJsonObject>("m.relates_to"_ls).contains("rel_type"_ls)
|
||||||
&& m_event->contentPart<QJsonObject>("m.relates_to"_ls)["rel_type"_ls].toString() == "m.thread"_ls)
|
&& event->contentPart<QJsonObject>("m.relates_to"_ls)["rel_type"_ls].toString() == "m.thread"_ls)
|
||||||
|| (!m_event->unsignedPart<QJsonObject>("m.relations"_ls).isEmpty() && m_event->unsignedPart<QJsonObject>("m.relations"_ls).contains("m.thread"_ls));
|
|| (!event->unsignedPart<QJsonObject>("m.relations"_ls).isEmpty() && event->unsignedPart<QJsonObject>("m.relations"_ls).contains("m.thread"_ls));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::threadRoot() const
|
QString EventHandler::threadRoot(const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "threadRoot called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "threadRoot called with event set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the thread root ID from m.relates_to if it exists.
|
// Get the thread root ID from m.relates_to if it exists.
|
||||||
if (m_event->contentPart<QJsonObject>("m.relates_to"_ls).contains("rel_type"_ls)
|
if (event->contentPart<QJsonObject>("m.relates_to"_ls).contains("rel_type"_ls)
|
||||||
&& m_event->contentPart<QJsonObject>("m.relates_to"_ls)["rel_type"_ls].toString() == "m.thread"_ls) {
|
&& event->contentPart<QJsonObject>("m.relates_to"_ls)["rel_type"_ls].toString() == "m.thread"_ls) {
|
||||||
return m_event->contentPart<QJsonObject>("m.relates_to"_ls)["event_id"_ls].toString();
|
return event->contentPart<QJsonObject>("m.relates_to"_ls)["event_id"_ls].toString();
|
||||||
}
|
}
|
||||||
// For thread root events they have an m.relations in the unsigned part with a m.thread object.
|
// For thread root events they have an m.relations in the unsigned part with a m.thread object.
|
||||||
// If so return the event ID as it is the root.
|
// If so return the event ID as it is the root.
|
||||||
if (!m_event->unsignedPart<QJsonObject>("m.relations"_ls).isEmpty() && m_event->unsignedPart<QJsonObject>("m.relations"_ls).contains("m.thread"_ls)) {
|
if (!event->unsignedPart<QJsonObject>("m.relations"_ls).isEmpty() && event->unsignedPart<QJsonObject>("m.relations"_ls).contains("m.thread"_ls)) {
|
||||||
return getId();
|
return id(event);
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
float EventHandler::getLatitude() const
|
float EventHandler::latitude(const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getLatitude called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "latitude called with event set to nullptr.";
|
||||||
return -100.0;
|
return -100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto geoUri = m_event->contentJson()["geo_uri"_ls].toString();
|
const auto geoUri = event->contentJson()["geo_uri"_ls].toString();
|
||||||
if (geoUri.isEmpty()) {
|
if (geoUri.isEmpty()) {
|
||||||
return -100.0; // latitude runs from -90deg to +90deg so -100 is out of range.
|
return -100.0; // latitude runs from -90deg to +90deg so -100 is out of range.
|
||||||
}
|
}
|
||||||
@@ -922,14 +851,14 @@ float EventHandler::getLatitude() const
|
|||||||
return latitude.toFloat();
|
return latitude.toFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
float EventHandler::getLongitude() const
|
float EventHandler::longitude(const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getLongitude called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "longitude called with event set to nullptr.";
|
||||||
return -200.0;
|
return -200.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto geoUri = m_event->contentJson()["geo_uri"_ls].toString();
|
const auto geoUri = event->contentJson()["geo_uri"_ls].toString();
|
||||||
if (geoUri.isEmpty()) {
|
if (geoUri.isEmpty()) {
|
||||||
return -200.0; // longitude runs from -180deg to +180deg so -200 is out of range.
|
return -200.0; // longitude runs from -180deg to +180deg so -200 is out of range.
|
||||||
}
|
}
|
||||||
@@ -937,115 +866,18 @@ float EventHandler::getLongitude() const
|
|||||||
return latitude.toFloat();
|
return latitude.toFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getLocationAssetType() const
|
QString EventHandler::locationAssetType(const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getLocationAssetType called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "locationAssetType called with event set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto assetType = m_event->contentJson()["org.matrix.msc3488.asset"_ls].toObject()["type"_ls].toString();
|
const auto assetType = event->contentJson()["org.matrix.msc3488.asset"_ls].toObject()["type"_ls].toString();
|
||||||
if (assetType.isEmpty()) {
|
if (assetType.isEmpty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return assetType;
|
return assetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventHandler::hasReadMarkers() const
|
|
||||||
{
|
|
||||||
if (m_room == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "hasReadMarkers called with m_room set to nullptr.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "hasReadMarkers called with m_event set to nullptr.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
|
||||||
userIds.remove(m_room->localUser()->id());
|
|
||||||
return userIds.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantList EventHandler::getReadMarkers(int maxMarkers) const
|
|
||||||
{
|
|
||||||
if (m_room == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReadMarkers called with m_room set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReadMarkers called with m_event set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto userIds_temp = m_room->userIdsAtEvent(m_event->id());
|
|
||||||
userIds_temp.remove(m_room->localUser()->id());
|
|
||||||
|
|
||||||
auto userIds = userIds_temp.values();
|
|
||||||
if (userIds.count() > maxMarkers) {
|
|
||||||
userIds = userIds.mid(0, maxMarkers);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantList users;
|
|
||||||
users.reserve(userIds.size());
|
|
||||||
for (const auto &userId : userIds) {
|
|
||||||
auto user = m_room->user(userId);
|
|
||||||
users += m_room->getUser(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString EventHandler::getNumberExcessReadMarkers(int maxMarkers) const
|
|
||||||
{
|
|
||||||
if (m_room == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getNumberExcessReadMarkers called with m_room set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getNumberExcessReadMarkers called with m_event set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
|
||||||
userIds.remove(m_room->localUser()->id());
|
|
||||||
|
|
||||||
if (userIds.count() > maxMarkers) {
|
|
||||||
return QStringLiteral("+ ") + QString::number(userIds.count() - maxMarkers);
|
|
||||||
} else {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString EventHandler::getReadMarkersString() const
|
|
||||||
{
|
|
||||||
if (m_room == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReadMarkersString called with m_room set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (m_event == nullptr) {
|
|
||||||
qCWarning(EventHandling) << "getReadMarkersString called with m_event set to nullptr.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
|
||||||
userIds.remove(m_room->localUser()->id());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The string ends up in the form
|
|
||||||
* "x users: user1DisplayName, user2DisplayName, etc."
|
|
||||||
*/
|
|
||||||
QString readMarkersString = i18np("1 user: ", "%1 users: ", userIds.size());
|
|
||||||
for (const auto &userId : userIds) {
|
|
||||||
auto user = m_room->user(userId);
|
|
||||||
auto displayName = user->displayname(m_room);
|
|
||||||
if (displayName.isEmpty()) {
|
|
||||||
displayName = userId;
|
|
||||||
}
|
|
||||||
readMarkersString += displayName + i18nc("list separator", ", ");
|
|
||||||
}
|
|
||||||
readMarkersString.chop(2);
|
|
||||||
return readMarkersString;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_eventhandler.cpp"
|
#include "moc_eventhandler.cpp"
|
||||||
|
|||||||
@@ -3,19 +3,22 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QDateTime>
|
||||||
|
#include <QString>
|
||||||
|
#include <Quotient/events/eventcontent.h>
|
||||||
|
|
||||||
#include <KFormat>
|
namespace Quotient
|
||||||
|
{
|
||||||
|
namespace EventContent
|
||||||
|
{
|
||||||
|
class FileInfo;
|
||||||
|
}
|
||||||
|
class RoomEvent;
|
||||||
|
class RoomMember;
|
||||||
|
class RoomMessageEvent;
|
||||||
|
}
|
||||||
|
|
||||||
#include <Quotient/eventitem.h>
|
|
||||||
#include <Quotient/events/roomevent.h>
|
|
||||||
#include <Quotient/events/roommessageevent.h>
|
|
||||||
|
|
||||||
#include "enums/messagecomponenttype.h"
|
|
||||||
|
|
||||||
class LinkPreviewer;
|
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
class ReactionModel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class EventHandler
|
* @class EventHandler
|
||||||
@@ -33,53 +36,19 @@ class ReactionModel;
|
|||||||
*/
|
*/
|
||||||
class EventHandler
|
class EventHandler
|
||||||
{
|
{
|
||||||
Q_GADGET
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EventHandler(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the Matrix ID of the event.
|
* @brief Return the ID of the event.
|
||||||
|
*
|
||||||
|
* Returns the transaction ID if the Matrix ID is empty, which may be the case
|
||||||
|
* for a pending event.
|
||||||
*/
|
*/
|
||||||
QString getId() const;
|
static QString id(const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The MessageComponentType to use to visualise the main event content.
|
|
||||||
*/
|
|
||||||
MessageComponentType::Type messageComponentType() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the author of the event in context of the room.
|
|
||||||
*
|
|
||||||
* This is different to getting a Quotient::User object
|
|
||||||
* as neither of those can provide details like the displayName or avatarMediaId
|
|
||||||
* without the room context as these can vary from room to room. This function
|
|
||||||
* uses the room context and outputs the result as QVariantMap.
|
|
||||||
*
|
|
||||||
* An empty QVariantMap will be returned if the EventHandler hasn't had the room
|
|
||||||
* intialised. An empty user (i.e. a QVariantMap with all the correct keys
|
|
||||||
* but empty values) will be returned if the room has been set but not an event.
|
|
||||||
*
|
|
||||||
* @param isPending if the event is pending, i.e. has not been confirmed by
|
|
||||||
* the server.
|
|
||||||
*
|
|
||||||
* @return a QVariantMap for the user with the following properties:
|
|
||||||
* - isLocalUser - Whether the user is the local user.
|
|
||||||
* - id - The matrix ID of the user.
|
|
||||||
* - displayName - Display name in the context of this room.
|
|
||||||
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
|
||||||
* - avatarMediaId - Avatar id in the context of this room.
|
|
||||||
* - color - Color for the user.
|
|
||||||
* - object - The Quotient::User object for the user.
|
|
||||||
*
|
|
||||||
* @sa Quotient::User
|
|
||||||
*/
|
|
||||||
QVariantMap getAuthor(bool isPending = false) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the display name of the event author.
|
* @brief Get the display name of the event author.
|
||||||
*
|
*
|
||||||
* This method is separate from getAuthor() and special in that it will return
|
* This method is special in that it will return
|
||||||
* the old display name of the author if the current event is one that caused it
|
* the old display name of the author if the current event is one that caused it
|
||||||
* to change. This allows for scenarios where the UI wishes to notify that a
|
* to change. This allows for scenarios where the UI wishes to notify that a
|
||||||
* user's display name has changed and what it changed from.
|
* user's display name has changed and what it changed from.
|
||||||
@@ -87,7 +56,7 @@ public:
|
|||||||
* @param isPending whether the event is pending as this cannot be derived from
|
* @param isPending whether the event is pending as this cannot be derived from
|
||||||
* just the event object.
|
* just the event object.
|
||||||
*/
|
*/
|
||||||
QString getAuthorDisplayName(bool isPending = false) const;
|
static QString authorDisplayName(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool isPending = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the display name of the event author but with any newlines removed.
|
* @brief Get the display name of the event author but with any newlines removed.
|
||||||
@@ -98,12 +67,12 @@ public:
|
|||||||
* @param isPending whether the event is pending as this cannot be derived from
|
* @param isPending whether the event is pending as this cannot be derived from
|
||||||
* just the event object.
|
* just the event object.
|
||||||
*/
|
*/
|
||||||
QString singleLineAuthorDisplayname(bool isPending = false) const;
|
static QString singleLineAuthorDisplayname(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool isPending = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a QDateTime object for the event timestamp.
|
* @brief Return a QDateTime object for the event timestamp.
|
||||||
*/
|
*/
|
||||||
QDateTime getTime(bool isPending = false, QDateTime lastUpdated = {}) const;
|
static QDateTime time(const Quotient::RoomEvent *event, bool isPending = false, QDateTime lastUpdated = {});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a QString for the event timestamp.
|
* @brief Return a QString for the event timestamp.
|
||||||
@@ -119,14 +88,32 @@ public:
|
|||||||
* @param lastUpdated the time the event was last updated locally as this cannot be
|
* @param lastUpdated the time the event was last updated locally as this cannot be
|
||||||
* obtained from the event.
|
* obtained from the event.
|
||||||
*/
|
*/
|
||||||
QString getTimeString(bool relative, QLocale::FormatType format = QLocale::ShortFormat, bool isPending = false, QDateTime lastUpdated = {}) const;
|
static QString timeString(const Quotient::RoomEvent *event,
|
||||||
|
bool relative,
|
||||||
|
QLocale::FormatType format = QLocale::ShortFormat,
|
||||||
|
bool isPending = false,
|
||||||
|
QDateTime lastUpdated = {});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a QString for the event timestamp.
|
||||||
|
*
|
||||||
|
* This is intended to return a string that is read for display in the UI without
|
||||||
|
* any further manipulation required.
|
||||||
|
*
|
||||||
|
* @param format the format to use as a string.
|
||||||
|
* @param isPending whether the event is pending as this cannot be derived from
|
||||||
|
* just the event object.
|
||||||
|
* @param lastUpdated the time the event was last updated locally as this cannot be
|
||||||
|
* obtained from the event.
|
||||||
|
*/
|
||||||
|
static QString timeString(const Quotient::RoomEvent *event, const QString &format, bool isPending = false, const QDateTime &lastUpdated = {});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the event should be highlighted in the timeline.
|
* @brief Whether the event should be highlighted in the timeline.
|
||||||
*
|
*
|
||||||
* @note Messages in direct chats are never highlighted.
|
* @note Messages in direct chats are never highlighted.
|
||||||
*/
|
*/
|
||||||
bool isHighlighted();
|
static bool isHighlighted(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the event should be hidden in the timeline.
|
* @brief Whether the event should be hidden in the timeline.
|
||||||
@@ -135,7 +122,7 @@ public:
|
|||||||
* user has hidden all state events or if the sender has been ignored by the local
|
* user has hidden all state events or if the sender has been ignored by the local
|
||||||
* user.
|
* user.
|
||||||
*/
|
*/
|
||||||
bool isHidden();
|
static bool isHidden(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The input format of the body in the message.
|
* @brief The input format of the body in the message.
|
||||||
@@ -167,7 +154,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param stripNewlines whether the output should have new lines in it.
|
* @param stripNewlines whether the output should have new lines in it.
|
||||||
*/
|
*/
|
||||||
QString getRichBody(bool stripNewlines = false) const;
|
static QString richBody(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool stripNewlines = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Output a string for the message content ready for display in a plain text field.
|
* @brief Output a string for the message content ready for display in a plain text field.
|
||||||
@@ -183,14 +170,14 @@ public:
|
|||||||
*
|
*
|
||||||
* @param stripNewlines whether the output should have new lines in it.
|
* @param stripNewlines whether the output should have new lines in it.
|
||||||
*/
|
*/
|
||||||
QString getPlainBody(bool stripNewlines = false) const;
|
static QString plainBody(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool stripNewlines = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Output the original body for the message content, useful for editing the original message.
|
* @brief Output the original body for the message content, useful for editing the original message.
|
||||||
*
|
*
|
||||||
* The event type must be a room message event.
|
* The event type must be a room message event.
|
||||||
*/
|
*/
|
||||||
QString getMarkdownBody() const;
|
static QString markdownBody(const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Output a generic string for the message content ready for display.
|
* @brief Output a generic string for the message content ready for display.
|
||||||
@@ -203,9 +190,9 @@ public:
|
|||||||
* E.g. For a message the text will be:
|
* E.g. For a message the text will be:
|
||||||
* "sent a message"
|
* "sent a message"
|
||||||
*
|
*
|
||||||
* @sa getRichBody(), getPlainBody()
|
* @sa richBody(), plainBody()
|
||||||
*/
|
*/
|
||||||
QString getGenericBody() const;
|
static QString genericBody(const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Output a string for the event to be used as a RoomList subtitle.
|
* @brief Output a string for the event to be used as a RoomList subtitle.
|
||||||
@@ -213,7 +200,7 @@ public:
|
|||||||
* The output includes the username followed by the plain message, all with no
|
* The output includes the username followed by the plain message, all with no
|
||||||
* line breaks.
|
* line breaks.
|
||||||
*/
|
*/
|
||||||
QString subtitleText() const;
|
static QString subtitleText(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the media info for the event.
|
* @brief Return the media info for the event.
|
||||||
@@ -231,113 +218,50 @@ public:
|
|||||||
* - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads.
|
* - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads.
|
||||||
* - isSticker - Whether the image is a sticker or not
|
* - isSticker - Whether the image is a sticker or not
|
||||||
*/
|
*/
|
||||||
QVariantMap getMediaInfo() const;
|
static QVariantMap mediaInfo(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the event is a reply to another in the timeline.
|
* @brief Whether the event is a reply to another in the timeline.
|
||||||
|
*
|
||||||
|
* @param showFallbacks whether message that have is_falling_back set true should
|
||||||
|
* show the fallback reply. Leave true for non-threaded
|
||||||
|
* timelines.
|
||||||
*/
|
*/
|
||||||
bool hasReply() const;
|
static bool hasReply(const Quotient::RoomEvent *event, bool showFallbacks = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the Matrix ID of the event replied to.
|
* @brief Return the Matrix ID of the event replied to.
|
||||||
*/
|
*/
|
||||||
QString getReplyId() const;
|
static QString replyId(const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The MessageComponentType to use to visualise the reply content.
|
|
||||||
*/
|
|
||||||
MessageComponentType::Type replyMessageComponentType() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the author of the event replied to in context of the room.
|
* @brief Get the author of the event replied to in context of the room.
|
||||||
*
|
*
|
||||||
* This is different to getting a Quotient::User object
|
* An empty Quotient::RoomMember will be returned if the EventHandler hasn't had
|
||||||
* as neither of those can provide details like the displayName or avatarMediaId
|
* the room or event initialised.
|
||||||
* without the room context as these can vary from room to room. This function
|
|
||||||
* uses the room context and outputs the result as QVariantMap.
|
|
||||||
*
|
*
|
||||||
* An empty QVariantMap will be returned if the EventHandler hasn't had the room
|
* @param isPending if the event is pending, i.e. has not been confirmed by
|
||||||
* intialised. An empty user (i.e. a QVariantMap with all the correct keys
|
* the server.
|
||||||
* but empty values) will be returned if the room has been set but not an event.
|
|
||||||
*
|
*
|
||||||
* @return a QVariantMap for the user with the following properties:
|
* @return a Quotient::RoomMember object for the user.
|
||||||
* - isLocalUser - Whether the user is the local user.
|
|
||||||
* - id - The matrix ID of the user.
|
|
||||||
* - displayName - Display name in the context of this room.
|
|
||||||
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
|
||||||
* - avatarMediaId - Avatar id in the context of this room.
|
|
||||||
* - color - Color for the user.
|
|
||||||
* - object - The Quotient::User object for the user.
|
|
||||||
*
|
*
|
||||||
* @sa Quotient::User
|
* @sa Quotient::RoomMember
|
||||||
*/
|
*/
|
||||||
QVariantMap getReplyAuthor() const;
|
static Quotient::RoomMember replyAuthor(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Output a string for the message content of the event replied to ready
|
|
||||||
* for display in a rich text field.
|
|
||||||
*
|
|
||||||
* The output string is dependant upon the event type and the desired output format.
|
|
||||||
*
|
|
||||||
* For most messages this is the body content of the message. For media messages
|
|
||||||
* this will be the caption and for state events it will be a string specific
|
|
||||||
* to that event with some dynamic details about the event added.
|
|
||||||
*
|
|
||||||
* E.g. For a room topic state event the text will be:
|
|
||||||
* "set the topic to: <new topic text>"
|
|
||||||
*
|
|
||||||
* @param stripNewlines whether the output should have new lines in it.
|
|
||||||
*/
|
|
||||||
QString getReplyRichBody(bool stripNewlines = false) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Output a string for the message content of the event replied to ready
|
|
||||||
* for display in a plain text field.
|
|
||||||
*
|
|
||||||
* The output string is dependant upon the event type and the desired output format.
|
|
||||||
*
|
|
||||||
* For most messages this is the body content of the message. For media messages
|
|
||||||
* this will be the caption and for state events it will be a string specific
|
|
||||||
* to that event with some dynamic details about the event added.
|
|
||||||
*
|
|
||||||
* E.g. For a room topic state event the text will be:
|
|
||||||
* "set the topic to: <new topic text>"
|
|
||||||
*
|
|
||||||
* @param stripNewlines whether the output should have new lines in it.
|
|
||||||
*/
|
|
||||||
QString getReplyPlainBody(bool stripNewlines = false) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the media info for the event replied to.
|
|
||||||
*
|
|
||||||
* An empty QVariantMap will be returned for any event that doesn't have any
|
|
||||||
* media info.
|
|
||||||
*
|
|
||||||
* @return This should consist of the following:
|
|
||||||
* - source - The mxc URL for the media.
|
|
||||||
* - mimeType - The MIME type of the media (should be image/xxx for this delegate).
|
|
||||||
* - mimeIcon - The MIME icon name (should be image-xxx).
|
|
||||||
* - size - The file size in bytes.
|
|
||||||
* - width - The width in pixels of the audio media.
|
|
||||||
* - height - The height in pixels of the audio media.
|
|
||||||
* - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads.
|
|
||||||
* - isSticker - Whether the image is a sticker or not
|
|
||||||
*/
|
|
||||||
QVariantMap getReplyMediaInfo() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the message is part of a thread.
|
* @brief Whether the message is part of a thread.
|
||||||
*
|
*
|
||||||
* i.e. There is a rel_type of m.thread.
|
* i.e. There is a rel_type of m.thread.
|
||||||
*/
|
*/
|
||||||
bool isThreaded() const;
|
static bool isThreaded(const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the Matrix ID of the thread's root message.
|
* @brief Return the Matrix ID of the thread's root message.
|
||||||
*
|
*
|
||||||
* Empty if this not part of a thread.
|
* Empty if this not part of a thread.
|
||||||
*/
|
*/
|
||||||
QString threadRoot() const;
|
static QString threadRoot(const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the latitude for the event.
|
* @brief Return the latitude for the event.
|
||||||
@@ -345,7 +269,7 @@ public:
|
|||||||
* Returns -100.0 if the event doesn't have a location (latitudes are in the
|
* Returns -100.0 if the event doesn't have a location (latitudes are in the
|
||||||
* range -90deg to +90deg so -100 is out of range).
|
* range -90deg to +90deg so -100 is out of range).
|
||||||
*/
|
*/
|
||||||
float getLatitude() const;
|
static float latitude(const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the longitude for the event.
|
* @brief Return the longitude for the event.
|
||||||
@@ -353,60 +277,21 @@ public:
|
|||||||
* Returns -200.0 if the event doesn't have a location (latitudes are in the
|
* Returns -200.0 if the event doesn't have a location (latitudes are in the
|
||||||
* range -180deg to +180deg so -200 is out of range).
|
* range -180deg to +180deg so -200 is out of range).
|
||||||
*/
|
*/
|
||||||
float getLongitude() const;
|
static float longitude(const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the type of location marker for the event.
|
* @brief Return the type of location marker for the event.
|
||||||
*/
|
*/
|
||||||
QString getLocationAssetType() const;
|
static QString locationAssetType(const Quotient::RoomEvent *event);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Whether the event has any read marker for other users.
|
|
||||||
*/
|
|
||||||
bool hasReadMarkers() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a list of user read marker for the event.
|
|
||||||
*
|
|
||||||
* @param maxMarkers the maximum number of users to return. Usually the number
|
|
||||||
* of user read makers shown is limited to not clutter the UI.
|
|
||||||
* This needs to be the same as used in getNumberExcessReadMarkers
|
|
||||||
* so that the markers line up with the number displayed, i.e.
|
|
||||||
* the number of users shown plus the excess number will be
|
|
||||||
* the total number of other user read markers at an event.
|
|
||||||
*/
|
|
||||||
QVariantList getReadMarkers(int maxMarkers = 5) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the number of excess user read markers for the event.
|
|
||||||
*
|
|
||||||
* This returns a string in the form "+ x" ready for use in the UI.
|
|
||||||
*
|
|
||||||
* @param maxMarkers the maximum number of markers shown in the UI. This needs to
|
|
||||||
* be the same as used in getReadMarkers so that the value lines
|
|
||||||
* up with the number displayed, i.e. the number of users shown
|
|
||||||
* plus the excess number will be the total number of other user
|
|
||||||
* read markers at an event.
|
|
||||||
*/
|
|
||||||
QString getNumberExcessReadMarkers(int maxMarkers = 5) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a string with the names of the read markers at the event.
|
|
||||||
*
|
|
||||||
* This is in the form "x users: name 1, name 2, ...".
|
|
||||||
*/
|
|
||||||
QString getReadMarkersString() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const NeoChatRoom *m_room = nullptr;
|
static QString getBody(const NeoChatRoom *room, const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines);
|
||||||
const Quotient::RoomEvent *m_event = nullptr;
|
static QString getMessageBody(const NeoChatRoom *room, const Quotient::RoomMessageEvent &event, Qt::TextFormat format, bool stripNewlines);
|
||||||
|
|
||||||
KFormat m_format;
|
static QVariantMap getMediaInfoForEvent(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
||||||
|
QVariantMap static getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
||||||
QString getBody(const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines) const;
|
const Quotient::EventContent::FileInfo *fileInfo,
|
||||||
QString getMessageBody(const Quotient::RoomMessageEvent &event, Qt::TextFormat format, bool stripNewlines) const;
|
const QString &eventId,
|
||||||
|
bool isThumbnail = false,
|
||||||
QVariantMap getMediaInfoForEvent(const Quotient::RoomEvent *event) const;
|
bool isSticker = false);
|
||||||
QVariantMap
|
|
||||||
getMediaInfoFromFileInfo(const Quotient::EventContent::FileInfo *fileInfo, const QString &eventId, bool isThumbnail = false, bool isSticker = false) const;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "imagepackevent.h"
|
#include "imagepackevent.h"
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
@@ -16,16 +17,16 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
|
|||||||
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
pack = none;
|
pack = std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &keys = json["images"_ls].toObject().keys();
|
const auto &keys = json["images"_ls].toObject().keys();
|
||||||
for (const auto &k : keys) {
|
for (const auto &k : keys) {
|
||||||
Omittable<EventContent::ImageInfo> info;
|
std::optional<EventContent::ImageInfo> info;
|
||||||
if (json["images"_ls][k].toObject().contains(QStringLiteral("info"))) {
|
if (json["images"_ls][k].toObject().contains(QStringLiteral("info"))) {
|
||||||
info = EventContent::ImageInfo(QUrl(json["images"_ls][k]["url"_ls].toString()), json["images"_ls][k]["info"_ls].toObject(), k);
|
info = EventContent::ImageInfo(QUrl(json["images"_ls][k]["url"_ls].toString()), json["images"_ls][k]["info"_ls].toObject(), k);
|
||||||
} else {
|
} else {
|
||||||
info = none;
|
info = std::nullopt;
|
||||||
}
|
}
|
||||||
images += ImagePackImage{
|
images += ImagePackImage{
|
||||||
k,
|
k,
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ public:
|
|||||||
* @brief Defines the properties of an image pack.
|
* @brief Defines the properties of an image pack.
|
||||||
*/
|
*/
|
||||||
struct Pack {
|
struct Pack {
|
||||||
Quotient::Omittable<QString> displayName; /**< The display name of the pack. */
|
std::optional<QString> displayName; /**< The display name of the pack. */
|
||||||
Quotient::Omittable<QUrl> avatarUrl; /**< The source mxc URL for the pack avatar. */
|
std::optional<QUrl> avatarUrl; /**< The source mxc URL for the pack avatar. */
|
||||||
Quotient::Omittable<QStringList> usage; /**< An array of the usages for this pack. Possible usages are "emoticon" and "sticker". */
|
std::optional<QStringList> usage; /**< An array of the usages for this pack. Possible usages are "emoticon" and "sticker". */
|
||||||
Quotient::Omittable<QString> attribution; /**< The attribution for the pack author(s). */
|
std::optional<QString> attribution; /**< The attribution for the pack author(s). */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,14 +38,14 @@ public:
|
|||||||
struct ImagePackImage {
|
struct ImagePackImage {
|
||||||
QString shortcode; /**< The shortcode for the image. */
|
QString shortcode; /**< The shortcode for the image. */
|
||||||
QUrl url; /**< The mxc URL for this image. */
|
QUrl url; /**< The mxc URL for this image. */
|
||||||
Quotient::Omittable<QString> body; /**< An optional text body for this image. */
|
std::optional<QString> body; /**< An optional text body for this image. */
|
||||||
Quotient::Omittable<Quotient::EventContent::ImageInfo> info; /**< The ImageInfo object used for the info block of m.sticker events. */
|
std::optional<Quotient::EventContent::ImageInfo> info; /**< The ImageInfo object used for the info block of m.sticker events. */
|
||||||
/**
|
/**
|
||||||
* @brief An array of the usages for this image.
|
* @brief An array of the usages for this image.
|
||||||
*
|
*
|
||||||
* The possible values match those of the usage key of a pack object.
|
* The possible values match those of the usage key of a pack object.
|
||||||
*/
|
*/
|
||||||
Quotient::Omittable<QStringList> usage;
|
std::optional<QStringList> usage;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,7 +53,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @sa Pack
|
* @sa Pack
|
||||||
*/
|
*/
|
||||||
Quotient::Omittable<Pack> pack;
|
std::optional<Pack> pack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a vector of images in the pack.
|
* @brief Return a vector of images in the pack.
|
||||||
|
|||||||
@@ -1,14 +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 <Quotient/events/simplestateevents.h>
|
|
||||||
|
|
||||||
namespace Quotient
|
|
||||||
{
|
|
||||||
|
|
||||||
// Defined so we can directly switch on type.
|
|
||||||
DEFINE_SIMPLE_STATE_EVENT(ServerAclEvent, "m.room.server_acl", bool, allow_ip_literals, "allow_ip_literals")
|
|
||||||
|
|
||||||
} // namespace Quotient
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user