Compare commits
311 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bb55eece7 | ||
|
|
2877e40647 | ||
|
|
768ec242fa | ||
|
|
194751627f | ||
|
|
bc701c51d9 | ||
|
|
35939b4af4 | ||
|
|
a178b8b6ca | ||
|
|
a6994318de | ||
|
|
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,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": [
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/quotient-im/libQuotient.git",
|
"url": "https://github.com/quotient-im/libQuotient.git",
|
||||||
"branch": "dev",
|
"branch": "0.8.x",
|
||||||
"disable-submodules": true
|
"disable-submodules": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ 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
|
||||||
|
|||||||
@@ -40,4 +40,4 @@ Dependencies:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
per-test-timeout: 90
|
per-test-timeout: 90
|
||||||
require-passing-tests-on: [ '@all' ]
|
require-passing-tests-on: [ 'Linux', 'Android', 'FreeBSD' ]
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ 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 "04")
|
set(RELEASE_SERVICE_VERSION_MINOR "07")
|
||||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
set(RELEASE_SERVICE_VERSION_MICRO "80")
|
||||||
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})
|
||||||
@@ -60,6 +60,9 @@ set_package_properties(Qt6 PROPERTIES
|
|||||||
)
|
)
|
||||||
|
|
||||||
qt_policy(SET QTP0001 NEW)
|
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());
|
||||||
}
|
}
|
||||||
@@ -115,7 +116,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 +133,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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -56,6 +56,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();
|
||||||
@@ -74,8 +75,6 @@ private Q_SLOTS:
|
|||||||
void nullThread();
|
void nullThread();
|
||||||
void location();
|
void location();
|
||||||
void nullLocation();
|
void nullLocation();
|
||||||
void readMarkers();
|
|
||||||
void nullReadMarkers();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void EventHandlerTest::initTestCase()
|
void EventHandlerTest::initTestCase()
|
||||||
@@ -100,28 +99,27 @@ void EventHandlerTest::nullEventId()
|
|||||||
void EventHandlerTest::author()
|
void EventHandlerTest::author()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(0).get();
|
auto event = room->messageEvents().at(0).get();
|
||||||
auto author = room->user(event->senderId());
|
auto author = room->member(event->senderId());
|
||||||
EventHandler eventHandler(room, event);
|
EventHandler eventHandler(room, event);
|
||||||
|
|
||||||
auto eventHandlerAuthor = eventHandler.getAuthor();
|
auto eventHandlerAuthor = eventHandler.getAuthor();
|
||||||
|
|
||||||
QCOMPARE(eventHandlerAuthor["isLocalUser"_ls], author->id() == room->localUser()->id());
|
QCOMPARE(eventHandlerAuthor.isLocalMember(), author.id() == room->localMember().id());
|
||||||
QCOMPARE(eventHandlerAuthor["id"_ls], author->id());
|
QCOMPARE(eventHandlerAuthor.id(), author.id());
|
||||||
QCOMPARE(eventHandlerAuthor["displayName"_ls], author->displayname(room));
|
QCOMPARE(eventHandlerAuthor.displayName(), author.displayName());
|
||||||
QCOMPARE(eventHandlerAuthor["avatarSource"_ls], room->avatarForMember(author));
|
QCOMPARE(eventHandlerAuthor.avatarUrl(), author.avatarUrl());
|
||||||
QCOMPARE(eventHandlerAuthor["avatarMediaId"_ls], author->avatarMediaId(room));
|
QCOMPARE(eventHandlerAuthor.avatarMediaId(), author.avatarMediaId());
|
||||||
QCOMPARE(eventHandlerAuthor["color"_ls], Utils::getUserColor(author->hueF()));
|
QCOMPARE(eventHandlerAuthor.color(), author.color());
|
||||||
QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(author));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullAuthor()
|
void EventHandlerTest::nullAuthor()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getAuthor(), QVariantMap());
|
QCOMPARE(emptyHandler.getAuthor(), RoomMember());
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
EventHandler noEventHandler(room, nullptr);
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
|
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
|
||||||
QCOMPARE(noEventHandler.getAuthor(), room->getUser(nullptr));
|
QCOMPARE(noEventHandler.getAuthor(), RoomMember());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::authorDisplayName()
|
void EventHandlerTest::authorDisplayName()
|
||||||
@@ -301,6 +299,13 @@ void EventHandlerTest::markdownBody()
|
|||||||
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("This is an example\ntext message"));
|
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("This is an example\ntext message"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EventHandlerTest::markdownBodyReply()
|
||||||
|
{
|
||||||
|
EventHandler eventHandler(room, room->messageEvents().at(5).get());
|
||||||
|
|
||||||
|
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("reply"));
|
||||||
|
}
|
||||||
|
|
||||||
void EventHandlerTest::subtitle()
|
void EventHandlerTest::subtitle()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
||||||
@@ -385,31 +390,30 @@ void EventHandlerTest::nullReplyId()
|
|||||||
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());
|
EventHandler eventHandler(room, room->messageEvents().at(5).get());
|
||||||
|
|
||||||
auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
|
auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
|
||||||
|
|
||||||
QCOMPARE(eventHandlerReplyAuthor["isLocalUser"_ls], replyAuthor->id() == room->localUser()->id());
|
QCOMPARE(eventHandlerReplyAuthor.isLocalMember(), replyAuthor.id() == room->localMember().id());
|
||||||
QCOMPARE(eventHandlerReplyAuthor["id"_ls], replyAuthor->id());
|
QCOMPARE(eventHandlerReplyAuthor.id(), replyAuthor.id());
|
||||||
QCOMPARE(eventHandlerReplyAuthor["displayName"_ls], replyAuthor->displayname(room));
|
QCOMPARE(eventHandlerReplyAuthor.displayName(), replyAuthor.displayName());
|
||||||
QCOMPARE(eventHandlerReplyAuthor["avatarSource"_ls], room->avatarForMember(replyAuthor));
|
QCOMPARE(eventHandlerReplyAuthor.avatarUrl(), replyAuthor.avatarUrl());
|
||||||
QCOMPARE(eventHandlerReplyAuthor["avatarMediaId"_ls], replyAuthor->avatarMediaId(room));
|
QCOMPARE(eventHandlerReplyAuthor.avatarMediaId(), replyAuthor.avatarMediaId());
|
||||||
QCOMPARE(eventHandlerReplyAuthor["color"_ls], Utils::getUserColor(replyAuthor->hueF()));
|
QCOMPARE(eventHandlerReplyAuthor.color(), replyAuthor.color());
|
||||||
QCOMPARE(eventHandlerReplyAuthor["object"_ls], QVariant::fromValue(replyAuthor));
|
|
||||||
|
|
||||||
EventHandler eventHandlerNoAuthor(room, room->messageEvents().at(0).get());
|
EventHandler eventHandlerNoAuthor(room, room->messageEvents().at(0).get());
|
||||||
QCOMPARE(eventHandlerNoAuthor.getReplyAuthor(), room->getUser(nullptr));
|
QCOMPARE(eventHandlerNoAuthor.getReplyAuthor(), RoomMember());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullReplyAuthor()
|
void EventHandlerTest::nullReplyAuthor()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getReplyAuthor(), QVariantMap());
|
QCOMPARE(emptyHandler.getReplyAuthor(), RoomMember());
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
EventHandler noEventHandler(room, nullptr);
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_event set to nullptr. Returning empty user.");
|
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_event set to nullptr. Returning empty user.");
|
||||||
QCOMPARE(noEventHandler.getReplyAuthor(), room->getUser(nullptr));
|
QCOMPARE(noEventHandler.getReplyAuthor(), RoomMember());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::replyBody()
|
void EventHandlerTest::replyBody()
|
||||||
@@ -515,59 +519,5 @@ void EventHandlerTest::nullLocation()
|
|||||||
QCOMPARE(emptyHandler.getLocationAssetType(), QString());
|
QCOMPARE(emptyHandler.getLocationAssetType(), 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)
|
||||||
#include "eventhandlertest.moc"
|
#include "eventhandlertest.moc"
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
<summary xml:lang="ca">Xategeu amb els vostres amics a Matrix</summary>
|
<summary xml:lang="ca">Xategeu amb els vostres amics a Matrix</summary>
|
||||||
<summary xml:lang="ca-valencia">Xategeu amb els vostres amics a Matrix</summary>
|
<summary xml:lang="ca-valencia">Xategeu amb els vostres amics a Matrix</summary>
|
||||||
<summary xml:lang="cs">Mluvte se svými přáteli na Matrixu</summary>
|
<summary xml:lang="cs">Mluvte se svými přáteli na Matrixu</summary>
|
||||||
|
<summary xml:lang="en-GB">Chat with your friends on matrix</summary>
|
||||||
<summary xml:lang="eo">Babilu kun viaj amikoj sur matrix</summary>
|
<summary xml:lang="eo">Babilu kun viaj amikoj sur matrix</summary>
|
||||||
<summary xml:lang="es">Charle con sus amigos en matrix</summary>
|
<summary xml:lang="es">Charle con sus amigos en matrix</summary>
|
||||||
<summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary>
|
<summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary>
|
||||||
@@ -79,20 +80,25 @@
|
|||||||
<summary xml:lang="zh-TW">在 Matrix 上與您的朋友聊天</summary>
|
<summary xml:lang="zh-TW">在 Matrix 上與您的朋友聊天</summary>
|
||||||
<description>
|
<description>
|
||||||
<p>NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p>
|
<p>NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p>
|
||||||
|
<p xml:lang="ar">نيوتشات هو تطبيق دردشة يتيح لك الاستفادة الكاملة من شبكة Matrix. فهو يوفر لك طريقة آمنة لإرسال الرسائل النصية ومقاطع الفيديو والملفات الصوتية إلى عائلتك وزملائك وأصدقائك.</p>
|
||||||
<p xml:lang="ca">El NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p>
|
<p xml:lang="ca">El NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p>
|
||||||
<p xml:lang="ca-valencia">NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p>
|
<p xml:lang="ca-valencia">NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p>
|
||||||
|
<p xml:lang="en-GB">NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p>
|
||||||
<p xml:lang="eo">NeoChat estas babilej-apo, kiu ebligas al vi plene profiti de la Matrix-reto. Ĝi provizas al vi sekuran manieron sendi tekstmesaĝojn, filmetojn kaj sondosierojn al via familio, kolegoj kaj amikoj.</p>
|
<p xml:lang="eo">NeoChat estas babilej-apo, kiu ebligas al vi plene profiti de la Matrix-reto. Ĝi provizas al vi sekuran manieron sendi tekstmesaĝojn, filmetojn kaj sondosierojn al via familio, kolegoj kaj amikoj.</p>
|
||||||
<p xml:lang="es">NeoChat es una aplicación de chat que le permite aprovechar al máximo la red Matrix. Le proporciona un modo seguro de enviar mensajes de texto, vídeos y archivos de sonido a su familia, colegas y amigos.</p>
|
<p xml:lang="es">NeoChat es una aplicación de chat que le permite aprovechar al máximo la red Matrix. Le proporciona un modo seguro de enviar mensajes de texto, vídeos y archivos de sonido a su familia, colegas y amigos.</p>
|
||||||
<p xml:lang="eu">NeoChat, Matrix 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="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="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="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>
|
||||||
<p xml:lang="ka">NeoChat ჩატის აპია, რომელიც საშუალება გაძლევთ, Matrix-ის ქსელის საშუალებები ბოლომდე გამოიყენოთ. ის გაძლევთ უსაფრთხო გზას, გააგზავნოთ ტექსტური შეტყობინებები, ვიდეოებ და აუდიოფაილები თქვენს ოჯახთან, კოლეგებთან და მეგობრებთან.</p>
|
<p xml:lang="ka">NeoChat ჩატის აპია, რომელიც საშუალება გაძლევთ, Matrix-ის ქსელის საშუალებები ბოლომდე გამოიყენოთ. ის გაძლევთ უსაფრთხო გზას, გააგზავნოთ ტექსტური შეტყობინებები, ვიდეოებ და აუდიოფაილები თქვენს ოჯახთან, კოლეგებთან და მეგობრებთან.</p>
|
||||||
<p xml:lang="lv">„NeoChat“ ir tērzēšanas programma, kas ļauj pilnvērtīgi izmantot „Matrix“ tīklu. Tā sniedz drošu veidu teksta ziņu, video un audio sūtīšanai ģimenes locekļiem, kolēģiem un draugiem.</p>
|
<p xml:lang="lv">„NeoChat“ ir tērzēšanas programma, kas ļauj pilnvērtīgi izmantot „Matrix“ tīklu. Tā sniedz drošu veidu teksta ziņu, video un audio sūtīšanai ģimenes locekļiem, kolēģiem un draugiem.</p>
|
||||||
<p xml:lang="nl">NeoChat is een chat-toepassing die u het volledige voordeel van het Matrix-netwerk laat genieten. Het levert u op een veilige manier tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden te verzenden.</p>
|
<p xml:lang="nl">NeoChat is een chat-toepassing die u het volledige voordeel van het Matrix-netwerk laat genieten. Het levert u op een veilige manier tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden te verzenden.</p>
|
||||||
|
<p xml:lang="nn">NeoChat er ein prateapp som lèt deg bruka all funksjonalitet i Matrix-nettverket. Du kan utveksla tekst, lyd og videoar med vennar, familie og kollegaar på ein trygg måte.</p>
|
||||||
<p xml:lang="pl">NoeChat to aplikacja do rozmów, która umożliwia wykorzystanie wszystkich możliwości Matriksa. Umożliwia wysyłanie wiadomości tekstowych, filmów i dźwięków w bezpieczny sposób do twojej rodziny, kolegów i przyjaciół.</p>
|
<p xml:lang="pl">NoeChat to aplikacja do rozmów, która umożliwia wykorzystanie wszystkich możliwości Matriksa. Umożliwia wysyłanie wiadomości tekstowych, filmów i dźwięków w bezpieczny sposób do twojej rodziny, kolegów i przyjaciół.</p>
|
||||||
<p xml:lang="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p>
|
<p xml:lang="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p>
|
||||||
|
<p xml:lang="sv">NeoChat är ett chattprogram som låter dig dra full nytta av Matrix-nätverket. Det ger dig ett säkert sätt att skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner.</p>
|
||||||
<p xml:lang="tr">NeoChat, Matrix ağının tüm özelliklerini kullanan bir sohbet uygulamasıdır. Ailenize, arkadaşlarınıza ve iş arkadaşlarınıza metin iletileri, ses ve video dosyaları göndermenin kolay bir yolunu sunar.</p>
|
<p xml:lang="tr">NeoChat, Matrix ağının tüm özelliklerini kullanan bir sohbet uygulamasıdır. Ailenize, arkadaşlarınıza ve iş arkadaşlarınıza metin iletileri, ses ve video dosyaları göndermenin kolay bir yolunu sunar.</p>
|
||||||
<p xml:lang="uk">NeoChat є програмою для спілкування, за допомогою якої ви можете скористатися усіма перевагами мережі Matrix. За її допомогою ви можете безпечно надсилати текстові повідомлення, відео та звукові файли вашим родичам, колегам та друзям.</p>
|
<p xml:lang="uk">NeoChat є програмою для спілкування, за допомогою якої ви можете скористатися усіма перевагами мережі Matrix. За її допомогою ви можете безпечно надсилати текстові повідомлення, відео та звукові файли вашим родичам, колегам та друзям.</p>
|
||||||
<p xml:lang="x-test">xxNeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.xx</p>
|
<p xml:lang="x-test">xxNeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.xx</p>
|
||||||
@@ -109,7 +115,7 @@
|
|||||||
<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="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 plenemente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p>
|
<p xml:lang="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>
|
||||||
<p xml:lang="ka">NeoChat მიზნად ისახავს Matrix სპეციფიკაციის სრული განხორციელება ჰქონდეს. როგორც ასეთი, ყველაფერი მიმდინარე სპეციფიკაციიდან, VoIP-ის, ძაფებისა და გამჭოლი დაშიფვრის ზოგიერთი ასპექტის გარდა, მხარდაჭერილია. შეძლება ასევე იყოს მცირე ლაფსუსებიც იმის გამო, რომ Matrix-ის სპეციფიკაცია მუდმივად ვითარდება, მაგრამ ჩვენი მიზანი მისი სრული მხარდაჭერაა.</p>
|
<p xml:lang="ka">NeoChat მიზნად ისახავს Matrix სპეციფიკაციის სრული განხორციელება ჰქონდეს. როგორც ასეთი, ყველაფერი მიმდინარე სპეციფიკაციიდან, VoIP-ის, ძაფებისა და გამჭოლი დაშიფვრის ზოგიერთი ასპექტის გარდა, მხარდაჭერილია. შეძლება ასევე იყოს მცირე ლაფსუსებიც იმის გამო, რომ Matrix-ის სპეციფიკაცია მუდმივად ვითარდება, მაგრამ ჩვენი მიზანი მისი სრული მხარდაჭერაა.</p>
|
||||||
<p xml:lang="ko">NeoChat은 Matrix 표준을 따르는 프로그램을 목표로 합니다. 현재 안정 버전의 표준에서 제공하는 기능의 대부분을 지원하며, VoIP, 스레드, 일부 종단간 암호화와 같은 기능은 아직 지원하지 않습니다. Matrix 표준은 계속하여 진화 중이기 때문에 일부 기능이 빠져 있을 수도 있지만 장기적으로는 전체 표준을 지원하는 것이 목표입니다.</p>
|
<p xml:lang="ko">NeoChat은 Matrix 표준을 따르는 프로그램을 목표로 합니다. 현재 안정 버전의 표준에서 제공하는 기능의 대부분을 지원하며, VoIP, 스레드, 일부 종단간 암호화와 같은 기능은 아직 지원하지 않습니다. Matrix 표준은 계속하여 진화 중이기 때문에 일부 기능이 빠져 있을 수도 있지만 장기적으로는 전체 표준을 지원하는 것이 목표입니다.</p>
|
||||||
@@ -118,6 +124,7 @@
|
|||||||
<p xml:lang="nn">NeoChat har som mål å støtta all funksjonalitet i Matrix-spesifikasjonen. Førebels er alt i den gjeldande stabile spesifikasjonen støtta, med unntak av VoIP, trådar og nokre delar av ende-til-kryptering. Det finst òg andre småting som ikkje er støtta, sidan Matrix-spesifikasjon er i stadig endring, men målet er altså støtte for alt.</p>
|
<p xml:lang="nn">NeoChat har som mål å støtta all funksjonalitet i Matrix-spesifikasjonen. Førebels er alt i den gjeldande stabile spesifikasjonen støtta, med unntak av VoIP, trådar og nokre delar av ende-til-kryptering. Det finst òg andre småting som ikkje er støtta, sidan Matrix-spesifikasjon er i stadig endring, men målet er altså støtte for alt.</p>
|
||||||
<p xml:lang="pl">NeoChat w zamyśle ma być pełnowartościową aplikacją wg wytycznych Matriksa. Z tego powodu, wszystko, co jest obecnie w stabilnych wytycznych z pominięciem VoIP, wątków i niektórych części szyfrowania Użytkownik-do-Użytkownika są obecnie obsługiwane. Pominięto też kilka mniejszych rzeczy ze względu na ciągły rozwój wytycznych Matriksa, lecz celem nadal jest zapewnienie obsługi wszystkich wytycznych.</p>
|
<p xml:lang="pl">NeoChat w zamyśle ma być pełnowartościową aplikacją wg wytycznych Matriksa. Z tego powodu, wszystko, co jest obecnie w stabilnych wytycznych z pominięciem VoIP, wątków i niektórych części szyfrowania Użytkownik-do-Użytkownika są obecnie obsługiwane. Pominięto też kilka mniejszych rzeczy ze względu na ciągły rozwój wytycznych Matriksa, lecz celem nadal jest zapewnienie obsługi wszystkich wytycznych.</p>
|
||||||
<p xml:lang="pt">O NeoChat pretende ser uma aplicação completa para a especificação do Matrix. Como tal, tudo o que existe na especificação estável actual, com as notáveis excepções do VoIP, tópicos e alguns aspectos da Encriptação Ponto-a-Ponto, são suportados. Existem mais algumas omissões, devido ao facto que a norma do Matrix está em constante evolução, mas o objectivo continua a ser oferecer o suporte eventual para a norma por inteiro.</p>
|
<p xml:lang="pt">O NeoChat pretende ser uma aplicação completa para a especificação do Matrix. Como tal, tudo o que existe na especificação estável actual, com as notáveis excepções do VoIP, tópicos e alguns aspectos da Encriptação Ponto-a-Ponto, são suportados. Existem mais algumas omissões, devido ao facto que a norma do Matrix está em constante evolução, mas o objectivo continua a ser oferecer o suporte eventual para a norma por inteiro.</p>
|
||||||
|
<p xml:lang="ru">Целью создания NeoChat является полноценная реализация программы для спецификации Matrix. Как следствие, реализовано всё в текущей стабильной спецификации (за исключением голосовой интернет-связи, потоков и некоторых аспектов сквозного шифрования). Есть также несколько других незначительных пробелов, обусловленных постоянными изменениями спецификации Matrix. Тем не менее, стоит задача в итоге предоставить полную поддержку спецификации.</p>
|
||||||
<p xml:lang="sl">Neochat cilja, da bi bila popolna aplikacija po specifikaciji Matrixa. Kot takšna vsebuje vse v trenutni stabilni specifikaciji z pomembnimi izjemami pri VoIP, nitih in nekaterih vidikov šifriranja od konca do konca. Obstaja nekaj drugih manjših opustitev zaradi dejstva, da se specifikacija Matrix nenehno razvija, vendar cilj ostaja zagotoviti morebitno podporo celotni specifikaciji.</p>
|
<p xml:lang="sl">Neochat cilja, da bi bila popolna aplikacija po specifikaciji Matrixa. Kot takšna vsebuje vse v trenutni stabilni specifikaciji z pomembnimi izjemami pri VoIP, nitih in nekaterih vidikov šifriranja od konca do konca. Obstaja nekaj drugih manjših opustitev zaradi dejstva, da se specifikacija Matrix nenehno razvija, vendar cilj ostaja zagotoviti morebitno podporo celotni specifikaciji.</p>
|
||||||
<p xml:lang="sv">NeoChat har som mål att vara ett fullständigt program enligt Matrix-specifikationen. Som sådant stöds allt i den nuvarande stabila specifikationen, med de nämnvärda undantagen VoIP, trådar och några aspekter av kryptering hela vägen. Det finns några ytterligare utelämnanden på grund av att Matrix-specifikationen hela tiden utvecklas, men målet förblir att till slut erbjuda stöd för hela specifikationen.</p>
|
<p xml:lang="sv">NeoChat har som mål att vara ett fullständigt program enligt Matrix-specifikationen. Som sådant stöds allt i den nuvarande stabila specifikationen, med de nämnvärda undantagen VoIP, trådar och några aspekter av kryptering hela vägen. Det finns några ytterligare utelämnanden på grund av att Matrix-specifikationen hela tiden utvecklas, men målet förblir att till slut erbjuda stöd för hela specifikationen.</p>
|
||||||
<p xml:lang="tr">NeoChat, Matrix belirtimi için tam özellikli bir uygulama olmayı hedefler. Bu nedenle; VoIP, ileti zincirleri ve Uçtan Uca Şifreleme’nin bazı yönleri gibi dikkate değer istisnalar dışında var olan kararlı belirtimdeki her şey desteklenir. Matrix belirtiminin sürekli gelişmesi nedeniyle birkaç küçük eksiklik daha var; ancak amaç tüm belirtim için nihai destek sağlamak olmayı sürdürüyor.</p>
|
<p xml:lang="tr">NeoChat, Matrix belirtimi için tam özellikli bir uygulama olmayı hedefler. Bu nedenle; VoIP, ileti zincirleri ve Uçtan Uca Şifreleme’nin bazı yönleri gibi dikkate değer istisnalar dışında var olan kararlı belirtimdeki her şey desteklenir. Matrix belirtiminin sürekli gelişmesi nedeniyle birkaç küçük eksiklik daha var; ancak amaç tüm belirtim için nihai destek sağlamak olmayı sürdürüyor.</p>
|
||||||
@@ -145,6 +152,7 @@
|
|||||||
<p xml:lang="nn">På grunn av måten Matrix-spesifikasjonen vert utvikla på, støttar NeoChat òg nokre uferdige funksjonar:</p>
|
<p xml:lang="nn">På grunn av måten Matrix-spesifikasjonen vert utvikla på, støttar NeoChat òg nokre uferdige funksjonar:</p>
|
||||||
<p xml:lang="pl">Ze względu na sposób rozwoju Matriksa, NeoChat obsługuje także kilka niestabilnych możliwości. Obecnie są to:</p>
|
<p xml:lang="pl">Ze względu na sposób rozwoju Matriksa, NeoChat obsługuje także kilka niestabilnych możliwości. Obecnie są to:</p>
|
||||||
<p xml:lang="pt">Devido à natureza do desenvolvimento da especificação do Matrix, o NeoChat também suporta diversas funcionalidades instáveis. De momento são:</p>
|
<p xml:lang="pt">Devido à natureza do desenvolvimento da especificação do Matrix, o NeoChat também suporta diversas funcionalidades instáveis. De momento são:</p>
|
||||||
|
<p xml:lang="ru">В силу природы разработки спецификации Matrix в NeoChat тоже предусмотрена поддержка многочисленных нестабильных возможностей. В текущей версии это следующие возможности:</p>
|
||||||
<p xml:lang="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p>
|
<p xml:lang="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p>
|
||||||
<p xml:lang="sv">På grund av sättet Matrix-specifikationens utvecklas, stöder NeoChat också ett stor antal instabila funktioner. För närvarande är de:</p>
|
<p xml:lang="sv">På grund av sättet Matrix-specifikationens utvecklas, stöder NeoChat också ett stor antal instabila funktioner. För närvarande är de:</p>
|
||||||
<p xml:lang="ta">மேட்ரிக்ஸு நெறிமுறை வரையறுக்கப்படும் விதத்தின் காரணமாக, பல நிலையற்ற அம்சங்களையும் நியோச்சாட் ஆதரிக்கிறது. தற்போது ஆதரிக்கப்படுபவை:</p>
|
<p xml:lang="ta">மேட்ரிக்ஸு நெறிமுறை வரையறுக்கப்படும் விதத்தின் காரணமாக, பல நிலையற்ற அம்சங்களையும் நியோச்சாட் ஆதரிக்கிறது. தற்போது ஆதரிக்கப்படுபவை:</p>
|
||||||
@@ -202,10 +210,11 @@
|
|||||||
<li xml:lang="nn">Klistremerke-pakkar – MSC2545</li>
|
<li xml:lang="nn">Klistremerke-pakkar – MSC2545</li>
|
||||||
<li xml:lang="pl">Paczki naklejek - MSC2545</li>
|
<li xml:lang="pl">Paczki naklejek - MSC2545</li>
|
||||||
<li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li>
|
<li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li>
|
||||||
|
<li xml:lang="ru">Наборы стикеров — MSC2545</li>
|
||||||
<li xml:lang="sl">Sticker Packs - MSC2545</li>
|
<li xml:lang="sl">Sticker Packs - MSC2545</li>
|
||||||
<li xml:lang="sv">Sticker Packs - MSC2545</li>
|
<li xml:lang="sv">Sticker Packs - MSC2545</li>
|
||||||
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
|
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
|
||||||
<li xml:lang="tr">Yapışkan Paketleri — MSC2545</li>
|
<li xml:lang="tr">Çıkartma Paketleri — MSC2545</li>
|
||||||
<li xml:lang="uk">Пакунки наліпок - MSC2545</li>
|
<li xml:lang="uk">Пакунки наліпок - MSC2545</li>
|
||||||
<li xml:lang="x-test">xxSticker Packs - MSC2545xx</li>
|
<li xml:lang="x-test">xxSticker Packs - MSC2545xx</li>
|
||||||
<li xml:lang="zh-TW">貼圖包 - MSC2545</li>
|
<li xml:lang="zh-TW">貼圖包 - MSC2545</li>
|
||||||
@@ -230,6 +239,7 @@
|
|||||||
<li xml:lang="nn">Posisjonshendingar – MSC3488</li>
|
<li xml:lang="nn">Posisjonshendingar – MSC3488</li>
|
||||||
<li xml:lang="pl">Wydarzenia w miejscach - MSC3488</li>
|
<li xml:lang="pl">Wydarzenia w miejscach - MSC3488</li>
|
||||||
<li xml:lang="pt">Eventos com Localizações - MSC3488</li>
|
<li xml:lang="pt">Eventos com Localizações - MSC3488</li>
|
||||||
|
<li xml:lang="ru">События местоположения — MSC3488</li>
|
||||||
<li xml:lang="sl">Location Events - MSC3488</li>
|
<li xml:lang="sl">Location Events - MSC3488</li>
|
||||||
<li xml:lang="sv">Location Events - MSC3488</li>
|
<li xml:lang="sv">Location Events - MSC3488</li>
|
||||||
<li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li>
|
<li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li>
|
||||||
@@ -275,6 +285,7 @@
|
|||||||
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
||||||
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||||
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||||
|
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
|
||||||
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
|
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
|
||||||
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
|
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
|
||||||
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
|
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
|
||||||
@@ -291,6 +302,7 @@
|
|||||||
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
|
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
|
||||||
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
|
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
|
||||||
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
|
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
|
||||||
|
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
|
||||||
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
|
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
|
||||||
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
|
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
|
||||||
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
|
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
|
||||||
@@ -302,11 +314,14 @@
|
|||||||
<screenshot type="default">
|
<screenshot type="default">
|
||||||
<image>https://cdn.kde.org/screenshots/neochat/spaces.png</image>
|
<image>https://cdn.kde.org/screenshots/neochat/spaces.png</image>
|
||||||
<caption>Discover new communities with Matrix Spaces</caption>
|
<caption>Discover new communities with Matrix Spaces</caption>
|
||||||
|
<caption xml:lang="ar">اكتشف مجتمعات جديدة مع فضاءات ماتركس</caption>
|
||||||
<caption xml:lang="ca">Descobriu comunitats noves amb els espais de Matrix</caption>
|
<caption xml:lang="ca">Descobriu comunitats noves amb els espais de Matrix</caption>
|
||||||
<caption xml:lang="ca-valencia">Descobriu comunitats noves amb els espais de Matrix</caption>
|
<caption xml:lang="ca-valencia">Descobriu comunitats noves amb els espais de Matrix</caption>
|
||||||
|
<caption xml:lang="en-GB">Discover new communities with Matrix Spaces</caption>
|
||||||
<caption xml:lang="eo">Malkovru novajn komunumojn per Matrix Spaces</caption>
|
<caption xml:lang="eo">Malkovru novajn komunumojn per Matrix Spaces</caption>
|
||||||
<caption xml:lang="es">Descubra nuevas comunidades con los espacios de Matrix</caption>
|
<caption xml:lang="es">Descubra nuevas comunidades con los espacios de Matrix</caption>
|
||||||
<caption xml:lang="eu">Ezagutu komunitate berriak Matrixeko Tokiak erabiliz</caption>
|
<caption xml:lang="eu">Ezagutu komunitate berriak Matrixeko Tokiak erabiliz</caption>
|
||||||
|
<caption xml:lang="fi">Löydä uusia yhteisöjä Matrix Spacesillä</caption>
|
||||||
<caption xml:lang="fr">Découvrez de nouvelles communautés avec les espaces sous Matrix</caption>
|
<caption xml:lang="fr">Découvrez de nouvelles communautés avec les espaces sous Matrix</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>
|
||||||
@@ -314,8 +329,10 @@
|
|||||||
<caption xml:lang="ka">აღმოაჩინეთ ახალი საზოგადოებები Matrix Spaces-თან ერთად</caption>
|
<caption xml:lang="ka">აღმოაჩინეთ ახალი საზოგადოებები Matrix Spaces-თან ერთად</caption>
|
||||||
<caption xml:lang="lv">Atklājiet jaunas kopienas ar „Matrix“ telpām</caption>
|
<caption xml:lang="lv">Atklājiet jaunas kopienas ar „Matrix“ telpām</caption>
|
||||||
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption>
|
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption>
|
||||||
|
<caption xml:lang="nn">Oppdag nye fellesskap med Matrix Spaces</caption>
|
||||||
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
|
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
|
||||||
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
|
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
|
||||||
|
<caption xml:lang="sv">Upptäck nya gemenskaper med Matrix Spaces</caption>
|
||||||
<caption xml:lang="tr">Matrix Alanlar ile yeni topluluklar keşfedin</caption>
|
<caption xml:lang="tr">Matrix Alanlar ile yeni topluluklar keşfedin</caption>
|
||||||
<caption xml:lang="uk">Пошук нових спільнот за допомогою Matrix Spaces</caption>
|
<caption xml:lang="uk">Пошук нових спільнот за допомогою Matrix Spaces</caption>
|
||||||
<caption xml:lang="x-test">xxDiscover new communities with Matrix Spacesxx</caption>
|
<caption xml:lang="x-test">xxDiscover new communities with Matrix Spacesxx</caption>
|
||||||
@@ -334,6 +351,7 @@
|
|||||||
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
||||||
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||||
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||||
|
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
|
||||||
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
|
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
|
||||||
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
|
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
|
||||||
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
|
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
|
||||||
@@ -350,6 +368,7 @@
|
|||||||
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
|
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
|
||||||
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
|
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
|
||||||
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
|
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
|
||||||
|
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
|
||||||
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
|
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
|
||||||
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
|
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
|
||||||
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
|
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
|
||||||
@@ -365,6 +384,7 @@
|
|||||||
<caption xml:lang="ca">Pantalla d'inici de sessió</caption>
|
<caption xml:lang="ca">Pantalla d'inici de sessió</caption>
|
||||||
<caption xml:lang="ca-valencia">Pantalla d'inici de sessió</caption>
|
<caption xml:lang="ca-valencia">Pantalla d'inici de sessió</caption>
|
||||||
<caption xml:lang="cs">Přihlašovací obrazovka</caption>
|
<caption xml:lang="cs">Přihlašovací obrazovka</caption>
|
||||||
|
<caption xml:lang="en-GB">Login screen</caption>
|
||||||
<caption xml:lang="eo">Ensaluta ekrano</caption>
|
<caption xml:lang="eo">Ensaluta ekrano</caption>
|
||||||
<caption xml:lang="es">Pantalla de inicio de sesión</caption>
|
<caption xml:lang="es">Pantalla de inicio de sesión</caption>
|
||||||
<caption xml:lang="eu">Saio-hasteko pantaila</caption>
|
<caption xml:lang="eu">Saio-hasteko pantaila</caption>
|
||||||
@@ -381,6 +401,7 @@
|
|||||||
<caption xml:lang="nn">Innloggingsbilete</caption>
|
<caption xml:lang="nn">Innloggingsbilete</caption>
|
||||||
<caption xml:lang="pl">Ekran logowania</caption>
|
<caption xml:lang="pl">Ekran logowania</caption>
|
||||||
<caption xml:lang="pt">Ecrã de autenticação</caption>
|
<caption xml:lang="pt">Ecrã de autenticação</caption>
|
||||||
|
<caption xml:lang="ru">Окно входа</caption>
|
||||||
<caption xml:lang="sl">Prijavni zaslon</caption>
|
<caption xml:lang="sl">Prijavni zaslon</caption>
|
||||||
<caption xml:lang="sv">Inloggningsfönster</caption>
|
<caption xml:lang="sv">Inloggningsfönster</caption>
|
||||||
<caption xml:lang="ta">நுழைவுத் திரை</caption>
|
<caption xml:lang="ta">நுழைவுத் திரை</caption>
|
||||||
@@ -394,6 +415,9 @@
|
|||||||
<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.05.2" date="2024-07-04"/>
|
||||||
|
<release version="24.05.1" date="2024-06-13"/>
|
||||||
|
<release version="24.05.0" date="2024-05-23"/>
|
||||||
<release version="24.02.2" date="2024-04-11"/>
|
<release version="24.02.2" date="2024-04-11"/>
|
||||||
<release version="24.02.1" date="2024-03-21"/>
|
<release version="24.02.1" date="2024-03-21"/>
|
||||||
<release version="24.02.0" date="2024-02-28">
|
<release version="24.02.0" date="2024-02-28">
|
||||||
|
|||||||
3288
po/ar/neochat.po
3288
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
1991
po/ast/neochat.po
1991
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
2412
po/az/neochat.po
2412
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -77,7 +77,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
|||||||
></term>
|
></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para
|
<para
|
||||||
>L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:exemple.org o matrix:r/root:exemple.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para>
|
>L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:example.org o matrix:r/root:example.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|||||||
2137
po/ca/neochat.po
2137
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2178
po/cs/neochat.po
2178
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
2174
po/da/neochat.po
2174
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
2406
po/de/neochat.po
2406
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
2426
po/el/neochat.po
2426
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
3354
po/en_GB/neochat.po
3354
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
2167
po/eo/neochat.po
2167
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
2220
po/es/neochat.po
2220
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
2265
po/eu/neochat.po
2265
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
2497
po/fi/neochat.po
2497
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
2239
po/fr/neochat.po
2239
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
2569
po/hu/neochat.po
2569
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
2224
po/ia/neochat.po
2224
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
2413
po/id/neochat.po
2413
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
2321
po/ie/neochat.po
2321
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
2273
po/it/neochat.po
2273
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1989
po/ja/neochat.po
1989
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
2220
po/ka/neochat.po
2220
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
2365
po/ko/neochat.po
2365
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1995
po/lt/neochat.po
1995
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
2360
po/lv/neochat.po
2360
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
2221
po/nl/neochat.po
2221
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
3047
po/nn/neochat.po
3047
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
2312
po/pa/neochat.po
2312
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
2293
po/pl/neochat.po
2293
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
2401
po/pt/neochat.po
2401
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
2412
po/pt_BR/neochat.po
2412
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
2529
po/ru/neochat.po
2529
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
2337
po/sk/neochat.po
2337
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
2207
po/sl/neochat.po
2207
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
3054
po/sv/neochat.po
3054
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
2263
po/ta/neochat.po
2263
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
2149
po/tok/neochat.po
2149
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
2219
po/tr/neochat.po
2219
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
2236
po/uk/neochat.po
2236
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
2299
po/zh_CN/neochat.po
2299
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
2180
po/zh_TW/neochat.po
2180
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,27 @@ 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
|
||||||
)
|
)
|
||||||
|
|
||||||
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
|
||||||
@@ -204,20 +217,13 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/InviteUserPage.qml
|
qml/InviteUserPage.qml
|
||||||
qml/ImageEditorPage.qml
|
qml/ImageEditorPage.qml
|
||||||
qml/NeochatMaximizeComponent.qml
|
qml/NeochatMaximizeComponent.qml
|
||||||
qml/FancyEffectsContainer.qml
|
|
||||||
qml/TypingPane.qml
|
qml/TypingPane.qml
|
||||||
qml/QuickSwitcher.qml
|
qml/QuickSwitcher.qml
|
||||||
qml/HoverActions.qml
|
qml/HoverActions.qml
|
||||||
qml/ChatBar.qml
|
|
||||||
qml/AttachmentPane.qml
|
qml/AttachmentPane.qml
|
||||||
qml/ReplyPane.qml
|
|
||||||
qml/CompletionMenu.qml
|
|
||||||
qml/PieProgressBar.qml
|
|
||||||
qml/QuickFormatBar.qml
|
qml/QuickFormatBar.qml
|
||||||
qml/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
|
||||||
@@ -237,9 +243,6 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/ConfirmEncryptionDialog.qml
|
qml/ConfirmEncryptionDialog.qml
|
||||||
qml/RemoveSheet.qml
|
qml/RemoveSheet.qml
|
||||||
qml/BanSheet.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
|
||||||
@@ -263,7 +266,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
|
||||||
@@ -281,15 +283,25 @@ 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
|
||||||
RESOURCES
|
qml/ConsentDialog.qml
|
||||||
qml/confetti.png
|
qml/AskDirectChatConfirmation.qml
|
||||||
qml/glowdot.png
|
qml/HoverLinkIndicator.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(UNIX)
|
||||||
qt_target_qml_sources(neochat QML_FILES qml/ShareAction.qml)
|
qt_target_qml_sources(neochat QML_FILES qml/ShareAction.qml)
|
||||||
@@ -372,16 +384,18 @@ endif()
|
|||||||
|
|
||||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_RUNNER)
|
target_compile_definitions(neochat PUBLIC -DHAVE_RUNNER)
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_X11)
|
target_compile_definitions(neochat PUBLIC -DHAVE_X11=1)
|
||||||
target_sources(neochat PRIVATE runner.cpp)
|
target_sources(neochat PRIVATE runner.cpp)
|
||||||
|
|
||||||
if (TARGET KUnifiedPush)
|
if (TARGET KUnifiedPush)
|
||||||
target_sources(neochat PRIVATE fakerunner.cpp)
|
target_sources(neochat PRIVATE fakerunner.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
else()
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_X11=0)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
|
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
|
||||||
target_link_libraries(neochat PRIVATE settingsplugin timelineplugin devtoolsplugin loginplugin)
|
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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -13,13 +13,15 @@ import org.kde.neochat
|
|||||||
QQC2.Popup {
|
QQC2.Popup {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
padding: 16
|
padding: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
signal chosen(string path)
|
signal chosen(string path)
|
||||||
|
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
|
|
||||||
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
Layout.preferredWidth: 160
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
icon.name: 'mail-attachment'
|
icon.name: 'mail-attachment'
|
||||||
@@ -28,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();
|
||||||
}
|
}
|
||||||
@@ -37,11 +39,8 @@ QQC2.Popup {
|
|||||||
Kirigami.Separator {}
|
Kirigami.Separator {}
|
||||||
|
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
Layout.preferredWidth: 160
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
padding: 16
|
|
||||||
|
|
||||||
icon.name: 'insert-image'
|
icon.name: 'insert-image'
|
||||||
text: i18n("Clipboard image")
|
text: i18n("Clipboard image")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
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();
|
||||||
}
|
}
|
||||||
@@ -278,6 +278,8 @@ QQC2.Control {
|
|||||||
Keys.onTabPressed: {
|
Keys.onTabPressed: {
|
||||||
if (completionMenu.visible) {
|
if (completionMenu.visible) {
|
||||||
completionMenu.complete();
|
completionMenu.complete();
|
||||||
|
} else {
|
||||||
|
contextDrawer.handle.children[0].forceActiveFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Keys.onPressed: event => {
|
Keys.onPressed: event => {
|
||||||
@@ -362,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: {
|
||||||
@@ -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,17 +41,17 @@ 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 : ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: root.checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
|
color: root.checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
|
||||||
radius: Kirigami.Units.smallSpacing
|
radius: Kirigami.Units.cornerRadius
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
radius: Kirigami.Units.smallSpacing
|
radius: Kirigami.Units.cornerRadius
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Kirigami.Theme.highlightColor
|
color: Kirigami.Theme.highlightColor
|
||||||
opacity: root.hovered && !root.pressed ? 0.2 : 0
|
opacity: root.hovered && !root.pressed ? 0.2 : 0
|
||||||
@@ -38,18 +38,22 @@ QQC2.Popup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
background: Kirigami.ShadowedRectangle {
|
background: Kirigami.ShadowedRectangle {
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
radius: Kirigami.Units.cornerRadius
|
||||||
color: Kirigami.Theme.backgroundColor
|
color: Kirigami.Theme.backgroundColor
|
||||||
radius: Kirigami.Units.mediumSpacing
|
|
||||||
shadow {
|
|
||||||
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
|
||||||
@@ -30,7 +30,7 @@ QQC2.Popup {
|
|||||||
onOpened: x = Math.min(parent.mapFromGlobal(QQC2.Overlay.overlay.width - root.width, 0).x, -(width - parent.width) / 2)
|
onOpened: x = Math.min(parent.mapFromGlobal(QQC2.Overlay.overlay.width - root.width, 0).x, -(width - parent.width) / 2)
|
||||||
background: Kirigami.ShadowedRectangle {
|
background: Kirigami.ShadowedRectangle {
|
||||||
color: Kirigami.Theme.backgroundColor
|
color: Kirigami.Theme.backgroundColor
|
||||||
radius: Kirigami.Units.mediumSpacing
|
radius: Kirigami.Units.cornerRadius
|
||||||
shadow {
|
shadow {
|
||||||
size: Kirigami.Units.largeSpacing
|
size: Kirigami.Units.largeSpacing
|
||||||
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)
|
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
*/
|
*/
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -9,28 +9,20 @@
|
|||||||
#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/accountregistry.h>
|
||||||
#include <Quotient/connection.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 "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"
|
||||||
@@ -46,6 +38,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;
|
||||||
@@ -107,14 +103,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();
|
||||||
});
|
});
|
||||||
@@ -190,7 +188,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;
|
||||||
@@ -218,11 +216,11 @@ void Controller::invokeLogin()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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]() {
|
||||||
@@ -253,12 +251,12 @@ QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const Accoun
|
|||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::saveAccessTokenToKeyChain(const AccountSettings &account, const QByteArray &accessToken)
|
bool 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());
|
QKeychain::WritePasswordJob job(qAppName());
|
||||||
job.setAutoDelete(false);
|
job.setAutoDelete(false);
|
||||||
job.setKey(account.userId());
|
job.setKey(userId);
|
||||||
job.setBinaryData(accessToken);
|
job.setBinaryData(accessToken);
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
QKeychain::WritePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
|
QKeychain::WritePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
|
||||||
@@ -394,8 +392,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;
|
||||||
@@ -411,11 +407,13 @@ 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 > 9
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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);
|
bool saveAccessTokenToKeyChain(const QString &userId, const QByteArray &accessToken);
|
||||||
|
|
||||||
[[nodiscard]] bool supportSystemTray() const;
|
[[nodiscard]] bool supportSystemTray() const;
|
||||||
|
|
||||||
@@ -102,7 +106,7 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE void removeConnection(const QString &userId);
|
Q_INVOKABLE void removeConnection(const QString &userId);
|
||||||
|
|
||||||
bool ssssSupported() const;
|
bool csSupported() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Controller(QObject *parent = nullptr);
|
explicit Controller(QObject *parent = nullptr);
|
||||||
@@ -110,14 +114,14 @@ 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 loadSettings();
|
||||||
void saveSettings() const;
|
void saveSettings() const;
|
||||||
|
|
||||||
Quotient::AccountRegistry m_accountRegistry;
|
Quotient::AccountRegistry m_accountRegistry;
|
||||||
QStringList m_accountsLoading;
|
QStringList m_accountsLoading;
|
||||||
QMap<QString, QPointer<Quotient::Connection>> m_connectionsLoading;
|
QMap<QString, QPointer<NeoChatConnection>> m_connectionsLoading;
|
||||||
QString m_endpoint;
|
QString m_endpoint;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
@@ -131,4 +135,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
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ FormCard.FormCardPage {
|
|||||||
FormCard.FormCard {
|
FormCard.FormCard {
|
||||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
FormCard.FormCheckDelegate {
|
||||||
|
text: i18nc("@option:check", "Show hidden events in the timeline")
|
||||||
|
checked: Config.showAllEvents
|
||||||
|
|
||||||
|
onToggled: Config.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")
|
||||||
@@ -23,5 +29,14 @@ FormCard.FormCardPage {
|
|||||||
|
|
||||||
onToggled: Config.alwaysVerifyDevice = checked
|
onToggled: Config.alwaysVerifyDevice = checked
|
||||||
}
|
}
|
||||||
|
FormCard.FormCheckDelegate {
|
||||||
|
text: i18nc("@option:check", "Show focus in window header")
|
||||||
|
checked: Config.windowTitleFocus
|
||||||
|
|
||||||
|
onToggled: {
|
||||||
|
Config.windowTitleFocus = checked;
|
||||||
|
Config.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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,5 +28,14 @@ FormCard.FormCardPage {
|
|||||||
|
|
||||||
onToggled: Config.secretBackup = checked
|
onToggled: Config.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: Config.phone3PId
|
||||||
|
|
||||||
|
onToggled: {
|
||||||
|
Config.phone3PId = checked
|
||||||
|
Config.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ ColumnLayout {
|
|||||||
text: i18n("Room")
|
text: i18n("Room")
|
||||||
textRole: "escapedDisplayName"
|
textRole: "escapedDisplayName"
|
||||||
valueRole: "roomId"
|
valueRole: "roomId"
|
||||||
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.DisplayNameRole)
|
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.EscapedDisplayNameRole)
|
||||||
model: RoomManager.roomListModel
|
model: RoomManager.roomListModel
|
||||||
currentIndex: 0
|
currentIndex: 0
|
||||||
|
displayMode: FormCard.FormComboBoxDelegate.Page
|
||||||
Component.onCompleted: currentIndex = RoomManager.roomListModel.rowForRoom(root.room)
|
Component.onCompleted: currentIndex = RoomManager.roomListModel.rowForRoom(root.room)
|
||||||
onCurrentValueChanged: root.room = RoomManager.roomListModel.roomByAliasOrId(roomComboBox.currentValue)
|
onCurrentValueChanged: root.room = RoomManager.roomListModel.roomByAliasOrId(roomComboBox.currentValue)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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. */
|
Edit, /**< 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);
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ public:
|
|||||||
* @brief Defines the room list categories a room can be assigned.
|
* @brief Defines the room list categories a room can be assigned.
|
||||||
*/
|
*/
|
||||||
enum Types {
|
enum Types {
|
||||||
Search = 0, /**< So we can show a search delegate if needed, e.g. collapsed mode. */
|
|
||||||
Invited, /**< The user has been invited to the room. */
|
Invited, /**< The user has been invited to the room. */
|
||||||
Favorite, /**< The room is set as a favourite. */
|
Favorite, /**< The room is set as a favourite. */
|
||||||
Direct, /**< The room is a direct chat. */
|
Direct, /**< The room is a direct chat. */
|
||||||
@@ -68,8 +67,6 @@ public:
|
|||||||
return i18n("Low priority");
|
return i18n("Low priority");
|
||||||
case NeoChatRoomType::Space:
|
case NeoChatRoomType::Space:
|
||||||
return i18n("Spaces");
|
return i18n("Spaces");
|
||||||
case NeoChatRoomType::Search:
|
|
||||||
return i18n("Search");
|
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -89,8 +86,6 @@ public:
|
|||||||
return QStringLiteral("object-order-lower");
|
return QStringLiteral("object-order-lower");
|
||||||
case NeoChatRoomType::Space:
|
case NeoChatRoomType::Space:
|
||||||
return QStringLiteral("group");
|
return QStringLiteral("group");
|
||||||
case NeoChatRoomType::Search:
|
|
||||||
return QStringLiteral("search");
|
|
||||||
default:
|
default:
|
||||||
return QStringLiteral("tools-report-bug");
|
return QStringLiteral("tools-report-bug");
|
||||||
}
|
}
|
||||||
|
|||||||
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;
|
||||||
|
};
|
||||||
@@ -19,11 +19,11 @@
|
|||||||
#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 "linkpreviewer.h"
|
||||||
#include "messagecomponenttype.h"
|
#include "messagecomponenttype.h"
|
||||||
@@ -61,20 +61,18 @@ MessageComponentType::Type EventHandler::messageComponentType() const
|
|||||||
return MessageComponentType::typeForEvent(*m_event);
|
return MessageComponentType::typeForEvent(*m_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap EventHandler::getAuthor(bool isPending) const
|
Quotient::RoomMember EventHandler::getAuthor(bool isPending) const
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (m_room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getAuthor called with m_room set to 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 (m_event == nullptr) {
|
if (m_event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getAuthor called with m_event set to nullptr. Returning empty user.";
|
qCWarning(EventHandling) << "getAuthor called with m_event set to nullptr. Returning empty user.";
|
||||||
return m_room->getUser(nullptr);
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
return isPending ? m_room->localMember() : m_room->member(m_event->senderId());
|
||||||
return m_room->getUser(author);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getAuthorDisplayName(bool isPending) const
|
QString EventHandler::getAuthorDisplayName(bool isPending) const
|
||||||
@@ -96,8 +94,8 @@ QString EventHandler::getAuthorDisplayName(bool isPending) const
|
|||||||
}
|
}
|
||||||
return previousDisplayName;
|
return previousDisplayName;
|
||||||
} else {
|
} else {
|
||||||
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
const auto author = isPending ? m_room->localMember() : m_room->member(m_event->senderId());
|
||||||
return m_room->htmlSafeMemberName(author->id());
|
return author.htmlSafeDisplayName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,8 +110,8 @@ QString EventHandler::singleLineAuthorDisplayname(bool isPending) const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
const auto author = isPending ? m_room->localMember() : m_room->member(m_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(" "));
|
||||||
@@ -220,7 +218,7 @@ bool EventHandler::isHidden()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_room->connection()->isIgnored(m_room->user(m_event->senderId()))) {
|
if (m_room->connection()->isIgnored(m_event->senderId())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,19 +241,21 @@ 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();
|
||||||
}
|
}
|
||||||
@@ -293,7 +293,10 @@ QString EventHandler::getMarkdownBody() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto roomMessageEvent = eventCast<const RoomMessageEvent>(m_event);
|
const auto roomMessageEvent = eventCast<const RoomMessageEvent>(m_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 Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines) const
|
||||||
@@ -315,15 +318,19 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
|||||||
},
|
},
|
||||||
[this, prettyPrint](const RoomMemberEvent &e) {
|
[this, 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 = m_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(), m_room->member(e.userId()).color().name(), subjectName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The below code assumes senderName output in AuthorRole
|
// The below code assumes senderName output in AuthorRole
|
||||||
@@ -437,7 +444,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) {
|
||||||
@@ -476,7 +483,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();
|
||||||
}
|
}
|
||||||
@@ -606,7 +613,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) {
|
||||||
@@ -655,23 +662,30 @@ QVariantMap EventHandler::getMediaInfoForEvent(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(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(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 EventContent::FileInfo *fileInfo, const QString &eventId, bool isThumbnail, bool isSticker) const
|
||||||
@@ -797,25 +811,21 @@ MessageComponentType::Type EventHandler::replyMessageComponentType() const
|
|||||||
return MessageComponentType::typeForEvent(*replyEvent);
|
return MessageComponentType::typeForEvent(*replyEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap EventHandler::getReplyAuthor() const
|
Quotient::RoomMember EventHandler::getReplyAuthor() const
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (m_room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getReplyAuthor called with m_room set to 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 (m_event == nullptr) {
|
if (m_event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getReplyAuthor called with m_event set to nullptr. Returning empty user.";
|
qCWarning(EventHandling) << "getReplyAuthor called with m_event set to nullptr. Returning empty user.";
|
||||||
return m_room->getUser(nullptr);
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto replyPtr = m_room->getReplyForEvent(*m_event);
|
if (auto replyPtr = m_room->getReplyForEvent(*m_event)) {
|
||||||
|
return m_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 m_room->member(QString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -951,97 +961,4 @@ QString EventHandler::getLocationAssetType() const
|
|||||||
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);
|
|
||||||
readMarkersString += user->displayname(m_room) + i18nc("list separator", ", ");
|
|
||||||
}
|
|
||||||
readMarkersString.chop(2);
|
|
||||||
return readMarkersString;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_eventhandler.cpp"
|
#include "moc_eventhandler.cpp"
|
||||||
|
|||||||
@@ -13,6 +13,11 @@
|
|||||||
|
|
||||||
#include "enums/messagecomponenttype.h"
|
#include "enums/messagecomponenttype.h"
|
||||||
|
|
||||||
|
namespace Quotient
|
||||||
|
{
|
||||||
|
class RoomMember;
|
||||||
|
}
|
||||||
|
|
||||||
class LinkPreviewer;
|
class LinkPreviewer;
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
class ReactionModel;
|
class ReactionModel;
|
||||||
@@ -51,30 +56,17 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Get the author of the event in context of the room.
|
* @brief Get the author of the event 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
|
|
||||||
* 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
|
* @param isPending if the event is pending, i.e. has not been confirmed by
|
||||||
* the server.
|
* the server.
|
||||||
*
|
*
|
||||||
* @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 getAuthor(bool isPending = false) const;
|
Quotient::RoomMember getAuthor(bool isPending = false) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the display name of the event author.
|
* @brief Get the display name of the event author.
|
||||||
@@ -251,27 +243,17 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @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;
|
Quotient::RoomMember getReplyAuthor() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Output a string for the message content of the event replied to ready
|
* @brief Output a string for the message content of the event replied to ready
|
||||||
@@ -360,43 +342,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
QString getLocationAssetType() const;
|
QString getLocationAssetType() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @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;
|
const NeoChatRoom *m_room = nullptr;
|
||||||
const Quotient::RoomEvent *m_event = nullptr;
|
const Quotient::RoomEvent *m_event = nullptr;
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -14,12 +14,15 @@ Q_SCRIPTABLE RemoteActions FakeRunner::Actions()
|
|||||||
|
|
||||||
Q_SCRIPTABLE RemoteMatches FakeRunner::Match(const QString &searchTerm)
|
Q_SCRIPTABLE RemoteMatches FakeRunner::Match(const QString &searchTerm)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(searchTerm);
|
||||||
QCoreApplication::quit();
|
QCoreApplication::quit();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_SCRIPTABLE void FakeRunner::Run(const QString &id, const QString &actionId)
|
Q_SCRIPTABLE void FakeRunner::Run(const QString &id, const QString &actionId)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(id);
|
||||||
|
Q_UNUSED(actionId);
|
||||||
QCoreApplication::quit();
|
QCoreApplication::quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,9 @@
|
|||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
||||||
#include <Quotient/accountregistry.h>
|
#include <Quotient/accountregistry.h>
|
||||||
#include <Quotient/keyverificationsession.h>
|
|
||||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
|
||||||
#include <Quotient/e2ee/sssshandler.h>
|
#include <Quotient/e2ee/sssshandler.h>
|
||||||
#endif
|
#include <Quotient/keyverificationsession.h>
|
||||||
|
#include <Quotient/roommember.h>
|
||||||
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
@@ -47,10 +46,14 @@ struct ForeignKeyVerificationSession {
|
|||||||
QML_UNCREATABLE("")
|
QML_UNCREATABLE("")
|
||||||
};
|
};
|
||||||
|
|
||||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
|
||||||
struct ForeignSSSSHandler {
|
struct ForeignSSSSHandler {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
QML_FOREIGN(Quotient::SSSSHandler)
|
QML_FOREIGN(Quotient::SSSSHandler)
|
||||||
QML_NAMED_ELEMENT(SSSSHandler)
|
QML_NAMED_ELEMENT(SSSSHandler)
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
struct RoomMemberForeign {
|
||||||
|
Q_GADGET
|
||||||
|
QML_FOREIGN(Quotient::RoomMember)
|
||||||
|
QML_NAMED_ELEMENT(RoomMember)
|
||||||
|
};
|
||||||
|
|||||||
119
src/identityserverhelper.cpp
Normal file
119
src/identityserverhelper.cpp
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
// 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 "identityserverhelper.h"
|
||||||
|
|
||||||
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
|
#include <Quotient/networkaccessmanager.h>
|
||||||
|
|
||||||
|
#include "neochatconnection.h"
|
||||||
|
|
||||||
|
IdentityServerHelper::IdentityServerHelper(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NeoChatConnection *IdentityServerHelper::connection() const
|
||||||
|
{
|
||||||
|
return m_connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdentityServerHelper::setConnection(NeoChatConnection *connection)
|
||||||
|
{
|
||||||
|
if (m_connection == connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_connection != nullptr) {
|
||||||
|
m_connection->disconnect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_connection = connection;
|
||||||
|
Q_EMIT connectionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IdentityServerHelper::url() const
|
||||||
|
{
|
||||||
|
return m_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdentityServerHelper::setUrl(const QString &url)
|
||||||
|
{
|
||||||
|
if (url == m_url) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_url = url;
|
||||||
|
Q_EMIT urlChanged();
|
||||||
|
|
||||||
|
checkUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentityServerHelper::IdServerStatus IdentityServerHelper::status() const
|
||||||
|
{
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdentityServerHelper::checkUrl()
|
||||||
|
{
|
||||||
|
if (m_idServerCheckRequest != nullptr) {
|
||||||
|
m_idServerCheckRequest->abort();
|
||||||
|
m_idServerCheckRequest.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_url == m_connection->identityServer().toString()) {
|
||||||
|
m_status = Match;
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_url.isEmpty()) {
|
||||||
|
m_status = Valid;
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto requestUrl = QUrl(m_url + QStringLiteral("/_matrix/identity/v2"));
|
||||||
|
if (!(requestUrl.scheme() == QStringLiteral("https") || requestUrl.scheme() == QStringLiteral("http"))) {
|
||||||
|
m_status = Invalid;
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkRequest request(requestUrl);
|
||||||
|
m_idServerCheckRequest = Quotient::NetworkAccessManager::instance()->get(request);
|
||||||
|
connect(m_idServerCheckRequest, &QNetworkReply::finished, this, [this]() {
|
||||||
|
if (m_idServerCheckRequest->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200) {
|
||||||
|
m_status = Valid;
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
} else {
|
||||||
|
m_status = Invalid;
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdentityServerHelper::setIdentityServer()
|
||||||
|
{
|
||||||
|
if (m_url == m_connection->identityServer().toString()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_connection->setAccountData(QLatin1String("m.identity_server"), {{QLatin1String("base_url"), m_url}});
|
||||||
|
m_status = Ready;
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdentityServerHelper::clearIdentityServer()
|
||||||
|
{
|
||||||
|
if (m_connection->identityServer().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_connection->setAccountData(QLatin1String("m.identity_server"), {{QLatin1String("base_url"), QString()}});
|
||||||
|
m_status = Ready;
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_identityserverhelper.cpp"
|
||||||
88
src/identityserverhelper.h
Normal file
88
src/identityserverhelper.h
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
// 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 <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
|
||||||
|
class NeoChatConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class IdentityServerHelper
|
||||||
|
*
|
||||||
|
* This class is designed to help the process of setting an identity server for the account.
|
||||||
|
* It will manage the various stages of verification and authentication.
|
||||||
|
*/
|
||||||
|
class IdentityServerHelper : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The connection to add a 3PID to.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The URL for the desired server.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The current status.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(IdServerStatus status READ status NOTIFY statusChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief The current status for adding an identity server
|
||||||
|
*/
|
||||||
|
enum IdServerStatus {
|
||||||
|
Ready, /**< The process is ready to start. I.e. there is no ongoing attempt to set a new server. */
|
||||||
|
Valid, /**< The server URL is valid. */
|
||||||
|
Invalid, /**< The server URL is invalid. */
|
||||||
|
Match, /**< The server URL is the one that is already configured. */
|
||||||
|
Other, /**< An unknown problem occurred. */
|
||||||
|
};
|
||||||
|
Q_ENUM(IdServerStatus)
|
||||||
|
|
||||||
|
explicit IdentityServerHelper(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
[[nodiscard]] NeoChatConnection *connection() const;
|
||||||
|
void setConnection(NeoChatConnection *connection);
|
||||||
|
|
||||||
|
[[nodiscard]] QString url() const;
|
||||||
|
void setUrl(const QString &url);
|
||||||
|
|
||||||
|
[[nodiscard]] IdServerStatus status() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the current URL as the user's identity server.
|
||||||
|
*
|
||||||
|
* Will do nothing if the URL isn't a valid identity server.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void setIdentityServer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear the user's identity server.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void clearIdentityServer();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void connectionChanged();
|
||||||
|
void urlChanged();
|
||||||
|
void statusChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<NeoChatConnection> m_connection;
|
||||||
|
|
||||||
|
IdServerStatus m_status = Ready;
|
||||||
|
QString m_url;
|
||||||
|
|
||||||
|
QPointer<QNetworkReply> m_idServerCheckRequest;
|
||||||
|
|
||||||
|
void checkUrl();
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user