Compare commits
137 Commits
v24.04.90
...
work/tobia
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27f4dfbf8e | ||
|
|
1235e46575 | ||
|
|
31dd981104 | ||
|
|
645438525f | ||
|
|
a29d3790c8 | ||
|
|
a47cbeca81 | ||
|
|
ab06d24f66 | ||
|
|
6f4a52024b | ||
|
|
83d21634c3 | ||
|
|
8d6340f84c | ||
|
|
a9713b1f1c | ||
|
|
9e05f17cb7 | ||
|
|
15b7c04834 | ||
|
|
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 |
@@ -5,11 +5,11 @@ include:
|
||||
- project: sysadmin/ci-utilities
|
||||
file:
|
||||
- /gitlab-templates/reuse-lint.yml
|
||||
- /gitlab-templates/android-qt6.yml
|
||||
- /gitlab-templates/linux-qt6.yml
|
||||
- /gitlab-templates/windows-qt6.yml
|
||||
- /gitlab-templates/freebsd-qt6.yml
|
||||
# - /gitlab-templates/android-qt6.yml
|
||||
# - /gitlab-templates/linux-qt6.yml
|
||||
# - /gitlab-templates/windows-qt6.yml
|
||||
# - /gitlab-templates/freebsd-qt6.yml
|
||||
- /gitlab-templates/flatpak.yml
|
||||
- /gitlab-templates/craft-android-qt6-apks.yml
|
||||
- /gitlab-templates/craft-appimage-qt6.yml
|
||||
- /gitlab-templates/craft-windows-x86-64-qt6.yml
|
||||
# - /gitlab-templates/craft-android-qt6-apks.yml
|
||||
# - /gitlab-templates/craft-appimage-qt6.yml
|
||||
# - /gitlab-templates/craft-windows-x86-64-qt6.yml
|
||||
|
||||
@@ -8,8 +8,8 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "04")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "90")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "07")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
|
||||
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
|
||||
app = Flask(__name__)
|
||||
|
||||
next_sync_payload = ""
|
||||
|
||||
|
||||
@app.route("/_matrix/client/v3/login", methods=["GET"])
|
||||
def login_get():
|
||||
@@ -42,8 +44,13 @@ def load_json(name):
|
||||
|
||||
@app.route("/_matrix/client/r0/sync")
|
||||
def sync():
|
||||
|
||||
result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
|
||||
global next_sync_payload
|
||||
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
|
||||
|
||||
@app.route("/.well-known/matrix/client")
|
||||
@@ -65,6 +72,18 @@ def upload_keys():
|
||||
reply = dict()
|
||||
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__":
|
||||
app.run(ssl_context='adhoc', port=1234)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QObject>
|
||||
#include <QTest>
|
||||
|
||||
#include <Quotient/roommember.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
#include <qtestcase.h>
|
||||
|
||||
@@ -50,7 +51,7 @@ void ChatBarCacheTest::empty()
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
QCOMPARE(chatBarCache->editId(), QString());
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
|
||||
QCOMPARE(chatBarCache->relationUser(), room->member(QString()));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||
}
|
||||
@@ -64,7 +65,7 @@ void ChatBarCacheTest::noRoom()
|
||||
// ChatBarCache has no parent.
|
||||
|
||||
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.");
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
@@ -80,7 +81,7 @@ void ChatBarCacheTest::badParent()
|
||||
// ChatBarCache has no parent.
|
||||
|
||||
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.");
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
@@ -98,7 +99,7 @@ void ChatBarCacheTest::reply()
|
||||
QCOMPARE(chatBarCache->replyId(), QLatin1String("$153456789:example.org"));
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
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->attachmentPath(), QString());
|
||||
}
|
||||
@@ -115,7 +116,7 @@ void ChatBarCacheTest::edit()
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), true);
|
||||
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->attachmentPath(), QString());
|
||||
}
|
||||
@@ -132,7 +133,7 @@ void ChatBarCacheTest::attachment()
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
QCOMPARE(chatBarCache->editId(), QString());
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
|
||||
QCOMPARE(chatBarCache->relationUser(), room->member(QString()));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"content": {
|
||||
"$153456789:example.org": {
|
||||
"m.read": {
|
||||
"@alice:matrix.org": {
|
||||
"@alice:example.org": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": [
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice Margatroid",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support"
|
||||
"displayname": "Example",
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"state_key": "@example:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
|
||||
@@ -51,6 +51,21 @@
|
||||
"unsigned": {
|
||||
"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 nullGenericBody();
|
||||
void markdownBody();
|
||||
void markdownBodyReply();
|
||||
void subtitle();
|
||||
void nullSubtitle();
|
||||
void mediaInfo();
|
||||
@@ -100,28 +101,27 @@ void EventHandlerTest::nullEventId()
|
||||
void EventHandlerTest::author()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
auto author = room->user(event->senderId());
|
||||
auto author = room->member(event->senderId());
|
||||
EventHandler eventHandler(room, event);
|
||||
|
||||
auto eventHandlerAuthor = eventHandler.getAuthor();
|
||||
|
||||
QCOMPARE(eventHandlerAuthor["isLocalUser"_ls], author->id() == room->localUser()->id());
|
||||
QCOMPARE(eventHandlerAuthor["id"_ls], author->id());
|
||||
QCOMPARE(eventHandlerAuthor["displayName"_ls], author->displayname(room));
|
||||
QCOMPARE(eventHandlerAuthor["avatarSource"_ls], room->avatarForMember(author));
|
||||
QCOMPARE(eventHandlerAuthor["avatarMediaId"_ls], author->avatarMediaId(room));
|
||||
QCOMPARE(eventHandlerAuthor["color"_ls], Utils::getUserColor(author->hueF()));
|
||||
QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(author));
|
||||
QCOMPARE(eventHandlerAuthor.isLocalMember(), author.id() == room->localMember().id());
|
||||
QCOMPARE(eventHandlerAuthor.id(), author.id());
|
||||
QCOMPARE(eventHandlerAuthor.displayName(), author.displayName());
|
||||
QCOMPARE(eventHandlerAuthor.avatarUrl(), author.avatarUrl());
|
||||
QCOMPARE(eventHandlerAuthor.avatarMediaId(), author.avatarMediaId());
|
||||
QCOMPARE(eventHandlerAuthor.color(), author.color());
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullAuthor()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getAuthor(), QVariantMap());
|
||||
QCOMPARE(emptyHandler.getAuthor(), RoomMember());
|
||||
|
||||
EventHandler noEventHandler(room, nullptr);
|
||||
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()
|
||||
@@ -301,6 +301,13 @@ void EventHandlerTest::markdownBody()
|
||||
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()
|
||||
{
|
||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
||||
@@ -385,31 +392,30 @@ void EventHandlerTest::nullReplyId()
|
||||
void EventHandlerTest::replyAuthor()
|
||||
{
|
||||
auto replyEvent = room->messageEvents().at(0).get();
|
||||
auto replyAuthor = room->user(replyEvent->senderId());
|
||||
auto replyAuthor = room->member(replyEvent->senderId());
|
||||
EventHandler eventHandler(room, room->messageEvents().at(5).get());
|
||||
|
||||
auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
|
||||
|
||||
QCOMPARE(eventHandlerReplyAuthor["isLocalUser"_ls], replyAuthor->id() == room->localUser()->id());
|
||||
QCOMPARE(eventHandlerReplyAuthor["id"_ls], replyAuthor->id());
|
||||
QCOMPARE(eventHandlerReplyAuthor["displayName"_ls], replyAuthor->displayname(room));
|
||||
QCOMPARE(eventHandlerReplyAuthor["avatarSource"_ls], room->avatarForMember(replyAuthor));
|
||||
QCOMPARE(eventHandlerReplyAuthor["avatarMediaId"_ls], replyAuthor->avatarMediaId(room));
|
||||
QCOMPARE(eventHandlerReplyAuthor["color"_ls], Utils::getUserColor(replyAuthor->hueF()));
|
||||
QCOMPARE(eventHandlerReplyAuthor["object"_ls], QVariant::fromValue(replyAuthor));
|
||||
QCOMPARE(eventHandlerReplyAuthor.isLocalMember(), replyAuthor.id() == room->localMember().id());
|
||||
QCOMPARE(eventHandlerReplyAuthor.id(), replyAuthor.id());
|
||||
QCOMPARE(eventHandlerReplyAuthor.displayName(), replyAuthor.displayName());
|
||||
QCOMPARE(eventHandlerReplyAuthor.avatarUrl(), replyAuthor.avatarUrl());
|
||||
QCOMPARE(eventHandlerReplyAuthor.avatarMediaId(), replyAuthor.avatarMediaId());
|
||||
QCOMPARE(eventHandlerReplyAuthor.color(), replyAuthor.color());
|
||||
|
||||
EventHandler eventHandlerNoAuthor(room, room->messageEvents().at(0).get());
|
||||
QCOMPARE(eventHandlerNoAuthor.getReplyAuthor(), room->getUser(nullptr));
|
||||
QCOMPARE(eventHandlerNoAuthor.getReplyAuthor(), RoomMember());
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyAuthor()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReplyAuthor(), QVariantMap());
|
||||
QCOMPARE(emptyHandler.getReplyAuthor(), RoomMember());
|
||||
|
||||
EventHandler noEventHandler(room, nullptr);
|
||||
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()
|
||||
@@ -523,10 +529,10 @@ void EventHandlerTest::readMarkers()
|
||||
auto readMarkers = eventHandler.getReadMarkers();
|
||||
|
||||
QCOMPARE(readMarkers.size(), 1);
|
||||
QCOMPARE(readMarkers[0].toMap()["id"_ls], QStringLiteral("@alice:matrix.org"));
|
||||
QCOMPARE(readMarkers[0].id(), QStringLiteral("@alice:example.org"));
|
||||
|
||||
QCOMPARE(eventHandler.getNumberExcessReadMarkers(), QString());
|
||||
QCOMPARE(eventHandler.getReadMarkersString(), QStringLiteral("1 user: @alice:matrix.org"));
|
||||
QCOMPARE(eventHandler.getReadMarkersString(), QStringLiteral("1 user: Alice Margatroid"));
|
||||
|
||||
EventHandler eventHandler2(room, room->messageEvents().at(2).get());
|
||||
QCOMPARE(eventHandler2.hasReadMarkers(), true);
|
||||
@@ -546,7 +552,7 @@ void EventHandlerTest::nullReadMarkers()
|
||||
QCOMPARE(emptyHandler.hasReadMarkers(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReadMarkers(), QVariantList());
|
||||
QCOMPARE(emptyHandler.getReadMarkers(), QList<Quotient::RoomMember>());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getNumberExcessReadMarkers(), QString());
|
||||
@@ -560,7 +566,7 @@ void EventHandlerTest::nullReadMarkers()
|
||||
QCOMPARE(noEventHandler.hasReadMarkers(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReadMarkers(), QVariantList());
|
||||
QCOMPARE(noEventHandler.getReadMarkers(), QList<Quotient::RoomMember>());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getNumberExcessReadMarkers(), QString());
|
||||
|
||||
@@ -6,12 +6,11 @@
|
||||
|
||||
#include "linkpreviewer.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <Quotient/quotient_common.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
@@ -30,6 +29,9 @@ private Q_SLOTS:
|
||||
void linkPreviewsMatch_data();
|
||||
void linkPreviewsMatch();
|
||||
|
||||
void multipleLinkPreviewsMatch_data();
|
||||
void multipleLinkPreviewsMatch();
|
||||
|
||||
void linkPreviewsReject_data();
|
||||
void linkPreviewsReject();
|
||||
};
|
||||
@@ -42,45 +44,59 @@ void LinkPreviewerTest::initTestCase()
|
||||
|
||||
void LinkPreviewerTest::linkPreviewsMatch_data()
|
||||
{
|
||||
QTest::addColumn<QString>("eventSource");
|
||||
QTest::addColumn<QString>("inputString");
|
||||
QTest::addColumn<QUrl>("testOutputLink");
|
||||
|
||||
QTest::newRow("plainHttps") << QStringLiteral("test-validplainlink-event.json") << QUrl("https://kde.org"_ls);
|
||||
QTest::newRow("richHttps") << QStringLiteral("test-validrichlink-event.json") << QUrl("https://kde.org"_ls);
|
||||
QTest::newRow("plainWww") << QStringLiteral("test-validplainwwwlink-event.json") << QUrl("www.example.org"_ls);
|
||||
QTest::newRow("multipleHttps") << QStringLiteral("test-multiplelink-event.json") << QUrl("www.example.org"_ls);
|
||||
QTest::newRow("plainHttps") << QStringLiteral("https://kde.org") << QUrl("https://kde.org"_ls);
|
||||
QTest::newRow("richHttps") << QStringLiteral("<a href=\"https://kde.org\">Rich Link</a>") << QUrl("https://kde.org"_ls);
|
||||
QTest::newRow("richHttpsLinkDescription") << QStringLiteral("<a href=\"https://kde.org\">https://kde.org</a>") << QUrl("https://kde.org"_ls);
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::linkPreviewsMatch()
|
||||
{
|
||||
QFETCH(QString, eventSource);
|
||||
QFETCH(QString, inputString);
|
||||
QFETCH(QUrl, testOutputLink);
|
||||
|
||||
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
||||
auto linkPreviewer = LinkPreviewer(LinkPreviewer::linkPreview(event.get()), connection);
|
||||
auto link = LinkPreviewer::linkPreviews(inputString)[0];
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), false);
|
||||
QCOMPARE(linkPreviewer.url(), testOutputLink);
|
||||
QCOMPARE(link, 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()
|
||||
{
|
||||
QTest::addColumn<QString>("eventSource");
|
||||
QTest::addColumn<QString>("inputString");
|
||||
|
||||
QTest::newRow("mxc") << QStringLiteral("test-invalidmxclink-event.json");
|
||||
QTest::newRow("matrixTo") << QStringLiteral("test-invalidmatrixtolink-event.json");
|
||||
QTest::newRow("noSpace") << QStringLiteral("test-invalidnospacelink-event.json");
|
||||
QTest::newRow("mxc") << QStringLiteral("mxc://example.org/SEsfnsuifSDFSSEF");
|
||||
QTest::newRow("matrixTo") << QStringLiteral("https://matrix.to/#/@alice:example.org");
|
||||
QTest::newRow("noSpace") << QStringLiteral("testhttps://kde.org");
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::linkPreviewsReject()
|
||||
{
|
||||
QFETCH(QString, eventSource);
|
||||
QFETCH(QString, inputString);
|
||||
|
||||
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
||||
auto linkPreviewer = LinkPreviewer(LinkPreviewer::linkPreview(event.get()), connection);
|
||||
auto links = LinkPreviewer::linkPreviews(inputString);
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), true);
|
||||
QCOMPARE(linkPreviewer.url(), QUrl());
|
||||
QCOMPARE(links.empty(), true);
|
||||
}
|
||||
|
||||
QTEST_MAIN(LinkPreviewerTest)
|
||||
|
||||
@@ -53,9 +53,7 @@ void ReactionModelTest::basicReaction()
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), QStringLiteral("👍"));
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole),
|
||||
QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
||||
auto authorList = QVariantList{room->getUser(room->user(QStringLiteral("@alice:matrix.org")))};
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::AuthorsRole), authorList);
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalUser), false);
|
||||
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalMember), false);
|
||||
}
|
||||
|
||||
void ReactionModelTest::newReaction()
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
<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="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="es">Charle con sus amigos en matrix</summary>
|
||||
<summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary>
|
||||
@@ -81,10 +82,11 @@
|
||||
<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="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="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="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="fr">NeoChat est une application de discussions vous permettant de profiter pleinement du réseau Matrix. Elle vous offre un moyen sécurisé d’envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos ami(e)s.</p>
|
||||
<p xml:lang="fr">NeoChat est une application de discussions vous permettant de profiter pleinement du réseau Matrix. Elle vous offre un moyen sécurisé d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos ami(e)s.</p>
|
||||
<p xml:lang="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="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>
|
||||
@@ -279,6 +281,7 @@
|
||||
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
||||
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
|
||||
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
|
||||
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
|
||||
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
|
||||
@@ -309,6 +312,7 @@
|
||||
<caption>Discover new communities with Matrix Spaces</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="en-GB">Discover new communities with Matrix Spaces</caption>
|
||||
<caption xml:lang="eo">Malkovru novajn komunumojn per Matrix Spaces</caption>
|
||||
<caption xml:lang="es">Descubra nuevas comunidades con los espacios de Matrix</caption>
|
||||
<caption xml:lang="eu">Ezagutu komunitate berriak Matrixeko Tokiak erabiliz</caption>
|
||||
@@ -339,6 +343,7 @@
|
||||
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
||||
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
|
||||
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
|
||||
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
|
||||
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
|
||||
@@ -371,6 +376,7 @@
|
||||
<caption xml:lang="ca">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="en-GB">Login screen</caption>
|
||||
<caption xml:lang="eo">Ensaluta ekrano</caption>
|
||||
<caption xml:lang="es">Pantalla de inicio de sesión</caption>
|
||||
<caption xml:lang="eu">Saio-hasteko pantaila</caption>
|
||||
@@ -401,6 +407,7 @@
|
||||
<content_attribute id="social-chat">intense</content_attribute>
|
||||
</content_rating>
|
||||
<releases>
|
||||
<release version="24.05.0" date="2024-05-23"/>
|
||||
<release version="24.02.2" date="2024-04-11"/>
|
||||
<release version="24.02.1" date="2024-03-21"/>
|
||||
<release version="24.02.0" date="2024-02-28">
|
||||
|
||||
953
po/ar/neochat.po
953
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
962
po/az/neochat.po
962
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
950
po/ca/neochat.po
950
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
935
po/cs/neochat.po
935
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
924
po/da/neochat.po
924
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
954
po/de/neochat.po
954
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
960
po/el/neochat.po
960
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
2021
po/en_GB/neochat.po
2021
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
915
po/eo/neochat.po
915
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
904
po/es/neochat.po
904
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
957
po/eu/neochat.po
957
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
948
po/fi/neochat.po
948
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
910
po/fr/neochat.po
910
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1175
po/hu/neochat.po
1175
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
914
po/ia/neochat.po
914
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
953
po/id/neochat.po
953
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
933
po/ie/neochat.po
933
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
904
po/it/neochat.po
904
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
862
po/ja/neochat.po
862
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
905
po/ka/neochat.po
905
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
948
po/ko/neochat.po
948
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
862
po/lt/neochat.po
862
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
940
po/lv/neochat.po
940
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
940
po/nl/neochat.po
940
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
928
po/nn/neochat.po
928
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
957
po/pa/neochat.po
957
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
926
po/pl/neochat.po
926
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
946
po/pt/neochat.po
946
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
947
po/ru/neochat.po
947
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
966
po/sk/neochat.po
966
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
901
po/sl/neochat.po
901
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
950
po/sv/neochat.po
950
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
908
po/ta/neochat.po
908
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
933
po/tr/neochat.po
933
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
920
po/uk/neochat.po
920
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -20,8 +20,6 @@ add_library(neochat STATIC
|
||||
models/customemojimodel.h
|
||||
clipboard.cpp
|
||||
clipboard.h
|
||||
matriximageprovider.cpp
|
||||
matriximageprovider.h
|
||||
models/messageeventmodel.cpp
|
||||
models/messageeventmodel.h
|
||||
models/messagefiltermodel.cpp
|
||||
@@ -158,7 +156,6 @@ add_library(neochat STATIC
|
||||
models/linemodel.cpp
|
||||
models/linemodel.h
|
||||
events/locationbeaconevent.h
|
||||
events/serveraclevent.h
|
||||
events/widgetevent.h
|
||||
enums/messagecomponenttype.h
|
||||
models/messagecontentmodel.cpp
|
||||
@@ -177,6 +174,16 @@ add_library(neochat STATIC
|
||||
foreigntypes.h
|
||||
models/threepidmodel.cpp
|
||||
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
|
||||
)
|
||||
|
||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||
@@ -207,16 +214,10 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
qml/TypingPane.qml
|
||||
qml/QuickSwitcher.qml
|
||||
qml/HoverActions.qml
|
||||
qml/ChatBar.qml
|
||||
qml/AttachmentPane.qml
|
||||
qml/ReplyPane.qml
|
||||
qml/CompletionMenu.qml
|
||||
qml/PieProgressBar.qml
|
||||
qml/QuickFormatBar.qml
|
||||
qml/EmojiPicker.qml
|
||||
qml/UserDetailDialog.qml
|
||||
qml/CreateRoomDialog.qml
|
||||
qml/EmojiDialog.qml
|
||||
qml/OpenFileDialog.qml
|
||||
qml/KeyVerificationDialog.qml
|
||||
qml/ConfirmLogoutDialog.qml
|
||||
@@ -236,9 +237,6 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
qml/ConfirmEncryptionDialog.qml
|
||||
qml/RemoveSheet.qml
|
||||
qml/BanSheet.qml
|
||||
qml/EmojiTonesPicker.qml
|
||||
qml/EmojiDelegate.qml
|
||||
qml/EmojiGrid.qml
|
||||
qml/RoomSearchPage.qml
|
||||
qml/LocationChooser.qml
|
||||
qml/TimelineView.qml
|
||||
@@ -262,7 +260,6 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
qml/SelectParentDialog.qml
|
||||
qml/QrCodeMaximizeComponent.qml
|
||||
qml/SelectSpacesDialog.qml
|
||||
qml/AttachDialog.qml
|
||||
qml/NotificationsView.qml
|
||||
qml/SearchPage.qml
|
||||
qml/ServerComboBox.qml
|
||||
@@ -280,12 +277,16 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
qml/ConfirmLeaveDialog.qml
|
||||
qml/CodeMaximizeComponent.qml
|
||||
qml/EditStateDialog.qml
|
||||
qml/ConsentDialog.qml
|
||||
qml/AskDirectChatConfirmation.qml
|
||||
qml/HoverLinkIndicator.qml
|
||||
)
|
||||
|
||||
add_subdirectory(settings)
|
||||
add_subdirectory(timeline)
|
||||
add_subdirectory(devtools)
|
||||
add_subdirectory(login)
|
||||
add_subdirectory(chatbar)
|
||||
|
||||
if(UNIX)
|
||||
qt_target_qml_sources(neochat QML_FILES qml/ShareAction.qml)
|
||||
@@ -368,16 +369,18 @@ endif()
|
||||
|
||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||
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)
|
||||
|
||||
if (TARGET KUnifiedPush)
|
||||
target_sources(neochat PRIVATE fakerunner.cpp)
|
||||
endif()
|
||||
else()
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_X11=0)
|
||||
endif()
|
||||
|
||||
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
|
||||
Qt::Core
|
||||
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++) {
|
||||
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;
|
||||
if (event->content()) {
|
||||
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
|
||||
|
||||
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)
|
||||
qt_add_qml_module(chatbar
|
||||
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
|
||||
)
|
||||
@@ -24,7 +24,7 @@ QQC2.ItemDelegate {
|
||||
contentItem: Item {
|
||||
Kirigami.Heading {
|
||||
anchors.fill: parent
|
||||
visible: !root.emoji.startsWith("image") && !root.isImage
|
||||
visible: !root.emoji.startsWith("mxc") && !root.isImage
|
||||
text: root.emoji
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
@@ -41,7 +41,7 @@ QQC2.ItemDelegate {
|
||||
}
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
visible: root.emoji.startsWith("image") || root.isImage
|
||||
visible: root.emoji.startsWith("mxc") || root.isImage
|
||||
source: visible ? root.emoji : ""
|
||||
}
|
||||
}
|
||||
@@ -38,18 +38,22 @@ QQC2.Popup {
|
||||
}
|
||||
|
||||
background: Kirigami.ShadowedRectangle {
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
radius: Kirigami.Units.cornerRadius
|
||||
shadow {
|
||||
size: Kirigami.Units.largeSpacing
|
||||
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)
|
||||
yOffset: 2
|
||||
}
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
|
||||
border {
|
||||
color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
|
||||
width: 2
|
||||
width: 1
|
||||
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
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "chatbarcache.h"
|
||||
|
||||
#include <Quotient/roommember.h>
|
||||
|
||||
#include "chatdocumenthandler.h"
|
||||
#include "eventhandler.h"
|
||||
#include "neochatroom.h"
|
||||
@@ -84,7 +86,7 @@ void ChatBarCache::setEditId(const QString &editId)
|
||||
Q_EMIT attachmentPathChanged();
|
||||
}
|
||||
|
||||
QVariantMap ChatBarCache::relationUser() const
|
||||
Quotient::RoomMember ChatBarCache::relationUser() const
|
||||
{
|
||||
if (parent() == nullptr) {
|
||||
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 {};
|
||||
}
|
||||
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
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
|
||||
class ChatDocumentHandler;
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
class RoomMember;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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)
|
||||
|
||||
/**
|
||||
* @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
|
||||
* 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 RoomMember if not replying to a message.
|
||||
*
|
||||
* Returns an empty user if not replying to a message.
|
||||
*
|
||||
* 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
|
||||
* @sa Quotient::RoomMember
|
||||
*/
|
||||
Q_PROPERTY(QVariantMap relationUser READ relationUser NOTIFY relationIdChanged)
|
||||
Q_PROPERTY(Quotient::RoomMember relationUser READ relationUser NOTIFY relationIdChanged)
|
||||
|
||||
/**
|
||||
* @brief The content of the related message.
|
||||
@@ -161,7 +154,7 @@ public:
|
||||
QString editId() const;
|
||||
void setEditId(const QString &editId);
|
||||
|
||||
QVariantMap relationUser() const;
|
||||
Quotient::RoomMember relationUser() const;
|
||||
|
||||
QString relationMessage() const;
|
||||
|
||||
|
||||
@@ -9,27 +9,20 @@
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QNetworkProxy>
|
||||
#include <QQuickTextDocument>
|
||||
#include <QQuickWindow>
|
||||
#include <QStandardPaths>
|
||||
#include <QStringBuilder>
|
||||
#include <QTimer>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/csapi/logout.h>
|
||||
#include <Quotient/csapi/notifications.h>
|
||||
#include <Quotient/eventstats.h>
|
||||
#include <Quotient/qt_connection_util.h>
|
||||
#include <Quotient/settings.h>
|
||||
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatconnection.h"
|
||||
#include "neochatroom.h"
|
||||
#include "notificationsmanager.h"
|
||||
#include "proxycontroller.h"
|
||||
#include "roommanager.h"
|
||||
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
#include "trayicon.h"
|
||||
@@ -45,6 +38,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_KUNIFIEDPUSH
|
||||
#include <kunifiedpush/connector.h>
|
||||
#endif
|
||||
|
||||
bool testMode = false;
|
||||
|
||||
using namespace Quotient;
|
||||
@@ -189,7 +186,7 @@ void Controller::invokeLogin()
|
||||
m_accountsLoading += accountId;
|
||||
Q_EMIT accountsLoadingChanged();
|
||||
if (!account.homeserver().isEmpty()) {
|
||||
auto accessTokenLoadingJob = loadAccessTokenFromKeyChain(account);
|
||||
auto accessTokenLoadingJob = loadAccessTokenFromKeyChain(account.userId());
|
||||
connect(accessTokenLoadingJob, &QKeychain::Job::finished, this, [accountId, this, accessTokenLoadingJob](QKeychain::Job *) {
|
||||
AccountSettings account{accountId};
|
||||
QString accessToken;
|
||||
@@ -217,11 +214,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);
|
||||
job->setKey(account.userId());
|
||||
job->setKey(userId);
|
||||
|
||||
// Handling of errors
|
||||
connect(job, &QKeychain::Job::finished, this, [this, job]() {
|
||||
@@ -252,12 +249,12 @@ QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const Accoun
|
||||
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());
|
||||
job.setAutoDelete(false);
|
||||
job.setKey(account.userId());
|
||||
job.setKey(userId);
|
||||
job.setBinaryData(accessToken);
|
||||
QEventLoop loop;
|
||||
QKeychain::WritePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
|
||||
@@ -410,11 +407,11 @@ void Controller::removeConnection(const QString &userId)
|
||||
}
|
||||
}
|
||||
|
||||
bool Controller::ssssSupported() const
|
||||
void Controller::saveFileContent(const QString &path, const QByteArray &data) const
|
||||
{
|
||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
QUrl url(path);
|
||||
QFile file(url.toLocalFile());
|
||||
file.open(QFile::WriteOnly);
|
||||
file.write(data);
|
||||
file.close();
|
||||
}
|
||||
|
||||
@@ -5,15 +5,9 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QQuickItem>
|
||||
|
||||
#include "neochatconnection.h"
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/settings.h>
|
||||
|
||||
#ifdef HAVE_KUNIFIEDPUSH
|
||||
#include <kunifiedpush/connector.h>
|
||||
#endif
|
||||
|
||||
class TrayIcon;
|
||||
class QQuickTextDocument;
|
||||
@@ -56,8 +50,6 @@ class Controller : public QObject
|
||||
|
||||
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
|
||||
|
||||
Q_PROPERTY(bool ssssSupported READ ssssSupported CONSTANT)
|
||||
|
||||
public:
|
||||
static Controller &instance();
|
||||
static Controller *create(QQmlEngine *engine, QJSEngine *)
|
||||
@@ -82,7 +74,7 @@ public:
|
||||
/**
|
||||
* @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;
|
||||
|
||||
@@ -95,6 +87,7 @@ public:
|
||||
static void listenForNotifications();
|
||||
|
||||
Q_INVOKABLE QString loadFileContent(const QString &path) const;
|
||||
Q_INVOKABLE void saveFileContent(const QString &path, const QByteArray &data) const;
|
||||
|
||||
Quotient::AccountRegistry &accounts();
|
||||
|
||||
@@ -102,15 +95,13 @@ public:
|
||||
|
||||
Q_INVOKABLE void removeConnection(const QString &userId);
|
||||
|
||||
bool ssssSupported() const;
|
||||
|
||||
private:
|
||||
explicit Controller(QObject *parent = nullptr);
|
||||
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
TrayIcon *m_trayIcon = nullptr;
|
||||
|
||||
QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const Quotient::AccountSettings &account);
|
||||
QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const QString &account);
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings() const;
|
||||
|
||||
@@ -31,12 +31,12 @@ FormCard.FormCardPage {
|
||||
implicitWidth: tabBar.tabWidth
|
||||
}
|
||||
QQC2.TabButton {
|
||||
text: qsTr("Room Data")
|
||||
text: i18nc("@title:tab", "Room Data")
|
||||
|
||||
implicitWidth: tabBar.tabWidth
|
||||
}
|
||||
QQC2.TabButton {
|
||||
text: qsTr("Server Info")
|
||||
text: i18nc("@title:tab", "Server Info")
|
||||
|
||||
implicitWidth: tabBar.tabWidth
|
||||
}
|
||||
|
||||
@@ -28,5 +28,14 @@ FormCard.FormCardPage {
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
107
src/enums/powerlevel.cpp
Normal file
107
src/enums/powerlevel.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// 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"}};
|
||||
}
|
||||
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/stickerevent.h>
|
||||
#include <Quotient/quotient_common.h>
|
||||
#include <Quotient/roommember.h>
|
||||
|
||||
#include "eventhandler_logging.h"
|
||||
#include "events/locationbeaconevent.h"
|
||||
#include "events/pollevent.h"
|
||||
#include "events/serveraclevent.h"
|
||||
#include "events/widgetevent.h"
|
||||
#include "linkpreviewer.h"
|
||||
#include "messagecomponenttype.h"
|
||||
@@ -61,20 +61,18 @@ MessageComponentType::Type EventHandler::messageComponentType() const
|
||||
return MessageComponentType::typeForEvent(*m_event);
|
||||
}
|
||||
|
||||
QVariantMap EventHandler::getAuthor(bool isPending) const
|
||||
Quotient::RoomMember EventHandler::getAuthor(bool isPending) const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getAuthor called with m_room set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
// If we have a room we can return an empty user by handing nullptr to m_room->getUser.
|
||||
if (m_event == nullptr) {
|
||||
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 m_room->getUser(author);
|
||||
return isPending ? m_room->localMember() : m_room->member(m_event->senderId());
|
||||
}
|
||||
|
||||
QString EventHandler::getAuthorDisplayName(bool isPending) const
|
||||
@@ -96,8 +94,8 @@ QString EventHandler::getAuthorDisplayName(bool isPending) const
|
||||
}
|
||||
return previousDisplayName;
|
||||
} else {
|
||||
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
||||
return m_room->htmlSafeMemberName(author->id());
|
||||
const auto author = isPending ? m_room->localMember() : m_room->member(m_event->senderId());
|
||||
return author.htmlSafeDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +110,8 @@ QString EventHandler::singleLineAuthorDisplayname(bool isPending) const
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
||||
auto displayName = m_room->safeMemberName(author->id());
|
||||
const auto author = isPending ? m_room->localMember() : m_room->member(m_event->senderId());
|
||||
auto displayName = author.displayName();
|
||||
displayName.replace(QStringLiteral("<br>\n"), QStringLiteral(" "));
|
||||
displayName.replace(QStringLiteral("<br>"), 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;
|
||||
}
|
||||
|
||||
@@ -255,7 +253,7 @@ QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
|
||||
|
||||
QString body;
|
||||
if (event.hasTextContent() && event.content()) {
|
||||
body = static_cast<const MessageEventContent::TextContent *>(event.content())->body;
|
||||
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
||||
} else {
|
||||
body = event.plainBody();
|
||||
}
|
||||
@@ -293,7 +291,10 @@ QString EventHandler::getMarkdownBody() const
|
||||
}
|
||||
|
||||
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
|
||||
@@ -315,7 +316,7 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
||||
},
|
||||
[this, prettyPrint](const RoomMemberEvent &e) {
|
||||
// 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.prevContent() && e.prevContent()->displayName) {
|
||||
subjectName = sanitized(*e.prevContent()->displayName).toHtmlEscaped();
|
||||
@@ -323,7 +324,8 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
||||
}
|
||||
|
||||
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
|
||||
@@ -437,7 +439,7 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
||||
[](const LocationBeaconEvent &e) {
|
||||
return e.contentJson()["description"_ls].toString();
|
||||
},
|
||||
[](const ServerAclEvent &) {
|
||||
[](const RoomServerAclEvent &) {
|
||||
return i18n("changed the server access control lists for this room");
|
||||
},
|
||||
[](const WidgetEvent &e) {
|
||||
@@ -476,7 +478,7 @@ QString EventHandler::getMessageBody(const RoomMessageEvent &event, Qt::TextForm
|
||||
|
||||
QString body;
|
||||
if (event.hasTextContent() && event.content()) {
|
||||
body = static_cast<const MessageEventContent::TextContent *>(event.content())->body;
|
||||
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
||||
} else {
|
||||
body = event.plainBody();
|
||||
}
|
||||
@@ -606,7 +608,7 @@ QString EventHandler::getGenericBody() const
|
||||
[](const LocationBeaconEvent &) {
|
||||
return i18n("sent a live location beacon");
|
||||
},
|
||||
[](const ServerAclEvent &) {
|
||||
[](const RoomServerAclEvent &) {
|
||||
return i18n("changed the server access control lists for this room");
|
||||
},
|
||||
[](const WidgetEvent &e) {
|
||||
@@ -797,25 +799,21 @@ MessageComponentType::Type EventHandler::replyMessageComponentType() const
|
||||
return MessageComponentType::typeForEvent(*replyEvent);
|
||||
}
|
||||
|
||||
QVariantMap EventHandler::getReplyAuthor() const
|
||||
Quotient::RoomMember EventHandler::getReplyAuthor() const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getReplyAuthor called with m_room set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
// If we have a room we can return an empty user by handing nullptr to m_room->getUser.
|
||||
if (m_event == nullptr) {
|
||||
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 (replyPtr) {
|
||||
auto replyUser = m_room->user(replyPtr->senderId());
|
||||
return m_room->getUser(replyUser);
|
||||
if (auto replyPtr = m_room->getReplyForEvent(*m_event)) {
|
||||
return m_room->member(replyPtr->senderId());
|
||||
} else {
|
||||
return m_room->getUser(nullptr);
|
||||
return m_room->member(QString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,11 +961,11 @@ bool EventHandler::hasReadMarkers() const
|
||||
}
|
||||
|
||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||
userIds.remove(m_room->localUser()->id());
|
||||
userIds.remove(m_room->localMember().id());
|
||||
return userIds.size() > 0;
|
||||
}
|
||||
|
||||
QVariantList EventHandler::getReadMarkers(int maxMarkers) const
|
||||
QList<Quotient::RoomMember> EventHandler::getReadMarkers(int maxMarkers) const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getReadMarkers called with m_room set to nullptr.";
|
||||
@@ -979,18 +977,17 @@ QVariantList EventHandler::getReadMarkers(int maxMarkers) const
|
||||
}
|
||||
|
||||
auto userIds_temp = m_room->userIdsAtEvent(m_event->id());
|
||||
userIds_temp.remove(m_room->localUser()->id());
|
||||
userIds_temp.remove(m_room->localMember().id());
|
||||
|
||||
auto userIds = userIds_temp.values();
|
||||
if (userIds.count() > maxMarkers) {
|
||||
userIds = userIds.mid(0, maxMarkers);
|
||||
}
|
||||
|
||||
QVariantList users;
|
||||
QList<Quotient::RoomMember> users;
|
||||
users.reserve(userIds.size());
|
||||
for (const auto &userId : userIds) {
|
||||
auto user = m_room->user(userId);
|
||||
users += m_room->getUser(user);
|
||||
users += m_room->member(userId);
|
||||
}
|
||||
|
||||
return users;
|
||||
@@ -1008,7 +1005,7 @@ QString EventHandler::getNumberExcessReadMarkers(int maxMarkers) const
|
||||
}
|
||||
|
||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||
userIds.remove(m_room->localUser()->id());
|
||||
userIds.remove(m_room->localMember().id());
|
||||
|
||||
if (userIds.count() > maxMarkers) {
|
||||
return QStringLiteral("+ ") + QString::number(userIds.count() - maxMarkers);
|
||||
@@ -1029,7 +1026,7 @@ QString EventHandler::getReadMarkersString() const
|
||||
}
|
||||
|
||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||
userIds.remove(m_room->localUser()->id());
|
||||
userIds.remove(m_room->localMember().id());
|
||||
|
||||
/**
|
||||
* The string ends up in the form
|
||||
@@ -1037,10 +1034,12 @@ QString EventHandler::getReadMarkersString() const
|
||||
*/
|
||||
QString readMarkersString = i18np("1 user: ", "%1 users: ", userIds.size());
|
||||
for (const auto &userId : userIds) {
|
||||
auto user = m_room->user(userId);
|
||||
auto displayName = user->displayname(m_room);
|
||||
if (displayName.isEmpty()) {
|
||||
displayName = userId;
|
||||
auto member = m_room->member(userId);
|
||||
QString displayName;
|
||||
if (member.isEmpty()) {
|
||||
displayName = i18nc("A member who is not in the room has been requested.", "unknown member");
|
||||
} else {
|
||||
displayName = member.displayName();
|
||||
}
|
||||
readMarkersString += displayName + i18nc("list separator", ", ");
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
|
||||
#include "enums/messagecomponenttype.h"
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
class RoomMember;
|
||||
}
|
||||
|
||||
class LinkPreviewer;
|
||||
class NeoChatRoom;
|
||||
class ReactionModel;
|
||||
@@ -51,30 +56,17 @@ public:
|
||||
/**
|
||||
* @brief Get the author of the event in context of the room.
|
||||
*
|
||||
* This is different to getting a Quotient::User object
|
||||
* as neither of those can provide details like the displayName or avatarMediaId
|
||||
* without the room context as these can vary from room to room. This function
|
||||
* uses the room context and outputs the result as QVariantMap.
|
||||
*
|
||||
* An empty QVariantMap will be returned if the EventHandler hasn't had the room
|
||||
* intialised. An empty user (i.e. a QVariantMap with all the correct keys
|
||||
* but empty values) will be returned if the room has been set but not an event.
|
||||
* An empty Quotient::RoomMember will be returned if the EventHandler hasn't had
|
||||
* the room or event initialised.
|
||||
*
|
||||
* @param isPending if the event is pending, i.e. has not been confirmed by
|
||||
* the server.
|
||||
*
|
||||
* @return a QVariantMap for the user with the following properties:
|
||||
* - isLocalUser - Whether the user is the local user.
|
||||
* - id - The matrix ID of the user.
|
||||
* - displayName - Display name in the context of this room.
|
||||
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
||||
* - avatarMediaId - Avatar id in the context of this room.
|
||||
* - color - Color for the user.
|
||||
* - object - The Quotient::User object for the user.
|
||||
* @return a Quotient::RoomMember 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.
|
||||
@@ -251,27 +243,17 @@ public:
|
||||
/**
|
||||
* @brief Get the author of the event replied to in context of the room.
|
||||
*
|
||||
* This is different to getting a Quotient::User object
|
||||
* as neither of those can provide details like the displayName or avatarMediaId
|
||||
* without the room context as these can vary from room to room. This function
|
||||
* uses the room context and outputs the result as QVariantMap.
|
||||
* An empty Quotient::RoomMember will be returned if the EventHandler hasn't had
|
||||
* the room or event initialised.
|
||||
*
|
||||
* An empty QVariantMap will be returned if the EventHandler hasn't had the room
|
||||
* intialised. An empty user (i.e. a QVariantMap with all the correct keys
|
||||
* but empty values) will be returned if the room has been set but not an event.
|
||||
* @param isPending if the event is pending, i.e. has not been confirmed by
|
||||
* the server.
|
||||
*
|
||||
* @return a QVariantMap for the user with the following properties:
|
||||
* - isLocalUser - Whether the user is the local user.
|
||||
* - id - The matrix ID of the user.
|
||||
* - displayName - Display name in the context of this room.
|
||||
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
||||
* - avatarMediaId - Avatar id in the context of this room.
|
||||
* - color - Color for the user.
|
||||
* - object - The Quotient::User object for the user.
|
||||
* @return a Quotient::RoomMember 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
|
||||
@@ -375,7 +357,7 @@ public:
|
||||
* 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;
|
||||
QList<Quotient::RoomMember> getReadMarkers(int maxMarkers = 5) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of excess user read markers for the event.
|
||||
|
||||
@@ -10,29 +10,29 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
|
||||
{
|
||||
if (json.contains(QStringLiteral("pack"))) {
|
||||
pack = ImagePackEventContent::Pack{
|
||||
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
|
||||
fromJson<Omittable<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
|
||||
fromJson<Omittable<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
|
||||
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
||||
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
|
||||
fromJson<std::optional<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
|
||||
fromJson<std::optional<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
|
||||
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
||||
};
|
||||
} else {
|
||||
pack = none;
|
||||
pack = std::nullopt;
|
||||
}
|
||||
|
||||
const auto &keys = json["images"_ls].toObject().keys();
|
||||
for (const auto &k : keys) {
|
||||
Omittable<EventContent::ImageInfo> info;
|
||||
std::optional<EventContent::ImageInfo> 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);
|
||||
} else {
|
||||
info = none;
|
||||
info = std::nullopt;
|
||||
}
|
||||
images += ImagePackImage{
|
||||
k,
|
||||
fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()),
|
||||
fromJson<Omittable<QString>>(json["images"_ls][k]["body"_ls]),
|
||||
fromJson<std::optional<QString>>(json["images"_ls][k]["body"_ls]),
|
||||
info,
|
||||
fromJson<Omittable<QStringList>>(json["images"_ls][k]["usage"_ls]),
|
||||
fromJson<std::optional<QStringList>>(json["images"_ls][k]["usage"_ls]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ public:
|
||||
* @brief Defines the properties of an image pack.
|
||||
*/
|
||||
struct Pack {
|
||||
Quotient::Omittable<QString> displayName; /**< The display name of the pack. */
|
||||
Quotient::Omittable<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". */
|
||||
Quotient::Omittable<QString> attribution; /**< The attribution for the pack author(s). */
|
||||
std::optional<QString> displayName; /**< The display name of the pack. */
|
||||
std::optional<QUrl> avatarUrl; /**< The source mxc URL for the pack avatar. */
|
||||
std::optional<QStringList> usage; /**< An array of the usages for this pack. Possible usages are "emoticon" and "sticker". */
|
||||
std::optional<QString> attribution; /**< The attribution for the pack author(s). */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -38,14 +38,14 @@ public:
|
||||
struct ImagePackImage {
|
||||
QString shortcode; /**< The shortcode for the image. */
|
||||
QUrl url; /**< The mxc URL for this image. */
|
||||
Quotient::Omittable<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<QString> body; /**< An optional text body for this image. */
|
||||
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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
Quotient::Omittable<Pack> pack;
|
||||
std::optional<Pack> 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
|
||||
@@ -33,4 +33,4 @@ FakeRunner::FakeRunner()
|
||||
qDBusRegisterMetaType<RemoteImage>();
|
||||
}
|
||||
|
||||
#include "moc_fakerunner.cpp"
|
||||
#include "moc_fakerunner.cpp"
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/keyverificationsession.h>
|
||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||
#include <Quotient/e2ee/sssshandler.h>
|
||||
#endif
|
||||
#include <Quotient/keyimport.h>
|
||||
#include <Quotient/keyverificationsession.h>
|
||||
|
||||
#include "controller.h"
|
||||
#include "neochatconfig.h"
|
||||
@@ -47,10 +46,15 @@ struct ForeignKeyVerificationSession {
|
||||
QML_UNCREATABLE("")
|
||||
};
|
||||
|
||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||
struct ForeignSSSSHandler {
|
||||
Q_GADGET
|
||||
QML_FOREIGN(Quotient::SSSSHandler)
|
||||
QML_NAMED_ELEMENT(SSSSHandler)
|
||||
};
|
||||
#endif
|
||||
|
||||
struct ForeignKeyImport {
|
||||
Q_GADGET
|
||||
QML_FOREIGN(Quotient::KeyImport)
|
||||
QML_NAMED_ELEMENT(KeyImport)
|
||||
QML_SINGLETON
|
||||
};
|
||||
|
||||
154
src/identityserverhelper.cpp
Normal file
154
src/identityserverhelper.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
// 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();
|
||||
Q_EMIT currentServerChanged();
|
||||
|
||||
connect(m_connection, &NeoChatConnection::accountDataChanged, this, [this](const QString &type) {
|
||||
if (type == QLatin1String("m.identity_server")) {
|
||||
Q_EMIT currentServerChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QString IdentityServerHelper::currentServer() const
|
||||
{
|
||||
if (m_connection == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_connection->hasAccountData(QLatin1String("m.identity_server"))) {
|
||||
return i18nc("@info", "No identity server configured");
|
||||
}
|
||||
|
||||
const auto url = m_connection->accountData(QLatin1String("m.identity_server"))->contentPart<QUrl>(QLatin1String("base_url"));
|
||||
if (!url.isEmpty()) {
|
||||
return url.toString();
|
||||
}
|
||||
return i18nc("@info", "No identity server configured");
|
||||
}
|
||||
|
||||
bool IdentityServerHelper::hasCurrentServer() const
|
||||
{
|
||||
if (m_connection == nullptr && !m_connection->hasAccountData(QLatin1String("m.identity_server"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto url = m_connection->accountData(QLatin1String("m.identity_server"))->contentPart<QUrl>(QLatin1String("base_url"));
|
||||
if (!url.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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 == currentServer()) {
|
||||
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 == currentServer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_connection->setAccountData(QLatin1String("m.identity_server"), {{QLatin1String("base_url"), m_url}});
|
||||
m_status = Ready;
|
||||
Q_EMIT statusChanged();
|
||||
}
|
||||
|
||||
void IdentityServerHelper::clearIdentityServer()
|
||||
{
|
||||
if (currentServer().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
m_connection->setAccountData(QLatin1String("m.identity_server"), {{QLatin1String("base_url"), QString()}});
|
||||
m_status = Ready;
|
||||
Q_EMIT statusChanged();
|
||||
}
|
||||
103
src/identityserverhelper.h
Normal file
103
src/identityserverhelper.h
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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 current identity server.
|
||||
*/
|
||||
Q_PROPERTY(QString currentServer READ currentServer NOTIFY currentServerChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether an identity server is currently configured.
|
||||
*/
|
||||
Q_PROPERTY(bool hasCurrentServer READ hasCurrentServer NOTIFY currentServerChanged)
|
||||
|
||||
/**
|
||||
* @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 currentServer() const;
|
||||
|
||||
[[nodiscard]] bool hasCurrentServer() const;
|
||||
|
||||
[[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 currentServerChanged();
|
||||
void urlChanged();
|
||||
void statusChanged();
|
||||
|
||||
private:
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
|
||||
IdServerStatus m_status = Ready;
|
||||
QString m_url;
|
||||
|
||||
QPointer<QNetworkReply> m_idServerCheckRequest;
|
||||
|
||||
void checkUrl();
|
||||
};
|
||||
16
src/jobs/neochatadd3pidjob.cpp
Normal file
16
src/jobs/neochatadd3pidjob.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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 "neochatadd3pidjob.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeochatAdd3PIdJob::NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Omittable<QJsonObject> &auth)
|
||||
: BaseJob(HttpVerb::Post, QStringLiteral("Add3PIDJob"), makePath("/_matrix/client/v3", "/account/3pid/add"))
|
||||
{
|
||||
QJsonObject _dataJson;
|
||||
addParam<IfNotEmpty>(_dataJson, QStringLiteral("auth"), auth);
|
||||
addParam<>(_dataJson, QStringLiteral("client_secret"), clientSecret);
|
||||
addParam<>(_dataJson, QStringLiteral("sid"), sid);
|
||||
setRequestData({_dataJson});
|
||||
}
|
||||
13
src/jobs/neochatadd3pidjob.h
Normal file
13
src/jobs/neochatadd3pidjob.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// 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/jobs/basejob.h>
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
class NeochatAdd3PIdJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Omittable<QJsonObject> &auth)
|
||||
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth)
|
||||
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), "/_matrix/client/r0/account/password")
|
||||
{
|
||||
QJsonObject _data;
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
class NeochatChangePasswordJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
|
||||
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth = std::nullopt);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const Omittable<QJsonObject> &auth)
|
||||
NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth)
|
||||
: BaseJob(HttpVerb::Post, QStringLiteral("DisableDeviceJob"), "_matrix/client/v3/account/deactivate")
|
||||
{
|
||||
QJsonObject data;
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
class NeoChatDeactivateAccountJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeoChatDeactivateAccountJob(const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
|
||||
explicit NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth = std::nullopt);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Omittable<QJsonObject> &auth)
|
||||
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth)
|
||||
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId).toLatin1())
|
||||
{
|
||||
QJsonObject _data;
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
class NeochatDeleteDeviceJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeochatDeleteDeviceJob(const QString &deviceId, const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
|
||||
explicit NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth = std::nullopt);
|
||||
};
|
||||
|
||||
@@ -89,38 +89,23 @@ bool LinkPreviewer::empty() const
|
||||
return m_url.isEmpty();
|
||||
}
|
||||
|
||||
QUrl LinkPreviewer::linkPreview(const Quotient::RoomMessageEvent *event)
|
||||
QList<QUrl> LinkPreviewer::linkPreviews(QString string)
|
||||
{
|
||||
if (event == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QString text;
|
||||
if (event->hasTextContent()) {
|
||||
auto textContent = static_cast<const Quotient::EventContent::TextContent *>(event->content());
|
||||
if (textContent) {
|
||||
text = textContent->body;
|
||||
} else {
|
||||
text = event->plainBody();
|
||||
}
|
||||
} else {
|
||||
text = event->plainBody();
|
||||
}
|
||||
|
||||
auto data = text.remove(TextRegex::removeRichReply);
|
||||
auto data = string.remove(TextRegex::removeRichReply);
|
||||
auto linksMatch = TextRegex::url.globalMatch(data);
|
||||
QList<QUrl> links;
|
||||
while (linksMatch.hasNext()) {
|
||||
auto link = linksMatch.next().captured();
|
||||
if (!link.contains(QStringLiteral("matrix.to"))) {
|
||||
return QUrl(link);
|
||||
if (!link.contains(QStringLiteral("matrix.to")) && !links.contains(QUrl(link))) {
|
||||
links += QUrl(link);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
return links;
|
||||
}
|
||||
|
||||
bool LinkPreviewer::hasPreviewableLinks(const Quotient::RoomMessageEvent *event)
|
||||
bool LinkPreviewer::hasPreviewableLinks(const QString &string)
|
||||
{
|
||||
return !linkPreview(event).isEmpty();
|
||||
return !linkPreviews(string).isEmpty();
|
||||
}
|
||||
|
||||
#include "moc_linkpreviewer.cpp"
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
#include <QQmlEngine>
|
||||
#include <QUrl>
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
class RoomMessageEvent;
|
||||
}
|
||||
|
||||
class NeoChatRoom;
|
||||
|
||||
/**
|
||||
@@ -71,19 +66,19 @@ public:
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
/**
|
||||
* @brief Whether the given event has at least 1 pre-viewable link.
|
||||
* @brief Whether the given string has at least 1 pre-viewable link.
|
||||
*
|
||||
* A link is only pre-viewable if it is http, https or something starting with www.
|
||||
*/
|
||||
static bool hasPreviewableLinks(const Quotient::RoomMessageEvent *event);
|
||||
static bool hasPreviewableLinks(const QString &string);
|
||||
|
||||
/**
|
||||
* @brief Return the link to be previewed from the given event.
|
||||
* @brief Return previewable links from the given string.
|
||||
*
|
||||
* This function is designed to give only links that should be previewed so
|
||||
* http, https or something starting with www. The first valid link is returned.
|
||||
*/
|
||||
static QUrl linkPreview(const Quotient::RoomMessageEvent *event);
|
||||
static QList<QUrl> linkPreviews(QString string);
|
||||
|
||||
private:
|
||||
bool m_loaded;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user