Compare commits
125 Commits
work/tobia
...
release/24
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e75739cda | ||
|
|
8935e339c3 | ||
|
|
1967247333 | ||
|
|
c68ce91b87 | ||
|
|
1890dfbdac | ||
|
|
1d23264b1f | ||
|
|
2915339b41 | ||
|
|
767cda8c77 | ||
|
|
a0fb6e2e42 | ||
|
|
23b5fb554a | ||
|
|
c00debf1c3 | ||
|
|
8446bd22f0 | ||
|
|
f1e7fa74c2 | ||
|
|
913f8ae91a | ||
|
|
5b250c73ec | ||
|
|
4991c5f771 | ||
|
|
95cb745536 | ||
|
|
d09f597886 | ||
|
|
1efebfb6a4 | ||
|
|
7c65d2653a | ||
|
|
8be3921ba6 | ||
|
|
7b3fa17020 | ||
|
|
8e2d0523c3 | ||
|
|
098966f2f6 | ||
|
|
e0496e73d9 | ||
|
|
a58236647b | ||
|
|
03db319a24 | ||
|
|
cd9ce10fb0 | ||
|
|
c5c47d7b67 | ||
|
|
2af04d5b00 | ||
|
|
45743bc9bc | ||
|
|
af83db6503 | ||
|
|
06b2861e21 | ||
|
|
e54fef7476 | ||
|
|
a96e3d00fc | ||
|
|
67f5c0b1ed | ||
|
|
b097f1c0ec | ||
|
|
1467e43956 | ||
|
|
c8c26a0b23 | ||
|
|
f344a8d690 | ||
|
|
696ce3af5e | ||
|
|
5c220f3c53 | ||
|
|
e7fe65bf57 | ||
|
|
321bc293f3 | ||
|
|
bd984f84ea | ||
|
|
f36bc88745 | ||
|
|
5f9402c1be | ||
|
|
155ca582f8 | ||
|
|
d9eadca3a2 | ||
|
|
da186fd57f | ||
|
|
d04946b471 | ||
|
|
cc823eff64 | ||
|
|
6f36aa3929 | ||
|
|
196344ad49 | ||
|
|
fbe5f1ff6d | ||
|
|
09c016fa8a | ||
|
|
e1448a5478 | ||
|
|
8c8140533b | ||
|
|
409579b287 | ||
|
|
a6a4008944 | ||
|
|
6bc3d55144 | ||
|
|
32400358f6 | ||
|
|
13846d485b | ||
|
|
c8d53b9e79 | ||
|
|
f8ff0dd3ce | ||
|
|
e577af65d3 | ||
|
|
6057e9a34f | ||
|
|
99fdbc1882 | ||
|
|
925d522da7 | ||
|
|
283aa1dc72 | ||
|
|
c66c035dbb | ||
|
|
cce9b967b9 | ||
|
|
7b751a4e6e | ||
|
|
3b0cc5f4fc | ||
|
|
5a15c013ff | ||
|
|
2351d76466 | ||
|
|
f477ae0d5e | ||
|
|
f8d7a969ac | ||
|
|
c4f79ea73a | ||
|
|
9c132f2a7a | ||
|
|
ba2698585f | ||
|
|
c31b716846 | ||
|
|
49df3b2b2f | ||
|
|
8ef41b9c90 | ||
|
|
2398d917f0 | ||
|
|
3aefdb4aed | ||
|
|
9a2c3e1deb | ||
|
|
110d90bb51 | ||
|
|
0a0cde77e6 | ||
|
|
18d92ec475 | ||
|
|
fd69439927 | ||
|
|
ad97af20b7 | ||
|
|
ca85b99fe9 | ||
|
|
0cde5d6168 | ||
|
|
eeddf99ca5 | ||
|
|
09a35b1a7e | ||
|
|
533182ec55 | ||
|
|
70a8842f00 | ||
|
|
ab33d1ca88 | ||
|
|
9e45f22e09 | ||
|
|
6a627dfff0 | ||
|
|
a9f05a7f63 | ||
|
|
4dfd4b68eb | ||
|
|
3786710d81 | ||
|
|
3967b27352 | ||
|
|
714ea8413c | ||
|
|
4097addae9 | ||
|
|
e9ac9deb40 | ||
|
|
3b858ab7d5 | ||
|
|
08807797a5 | ||
|
|
923839d6c7 | ||
|
|
3d4a1d22b0 | ||
|
|
5aa7f499c0 | ||
|
|
40c3519737 | ||
|
|
6ec9cc2475 | ||
|
|
eba34b19ad | ||
|
|
8517636485 | ||
|
|
4a96dae57d | ||
|
|
09f433be45 | ||
|
|
b9901a9167 | ||
|
|
8b27d99d82 | ||
|
|
6b53c4d7b1 | ||
|
|
bd28a7f66d | ||
|
|
0d1c09696d | ||
|
|
aeb4013d26 |
@@ -2,7 +2,7 @@
|
|||||||
"id": "org.kde.neochat",
|
"id": "org.kde.neochat",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"runtime": "org.kde.Platform",
|
"runtime": "org.kde.Platform",
|
||||||
"runtime-version": "6.7",
|
"runtime-version": "6.6",
|
||||||
"sdk": "org.kde.Sdk",
|
"sdk": "org.kde.Sdk",
|
||||||
"command": "neochat",
|
"command": "neochat",
|
||||||
"tags": [
|
"tags": [
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ include:
|
|||||||
- project: sysadmin/ci-utilities
|
- project: sysadmin/ci-utilities
|
||||||
file:
|
file:
|
||||||
- /gitlab-templates/reuse-lint.yml
|
- /gitlab-templates/reuse-lint.yml
|
||||||
# - /gitlab-templates/android-qt6.yml
|
- /gitlab-templates/android-qt6.yml
|
||||||
# - /gitlab-templates/linux-qt6.yml
|
- /gitlab-templates/linux-qt6.yml
|
||||||
# - /gitlab-templates/windows-qt6.yml
|
- /gitlab-templates/windows-qt6.yml
|
||||||
# - /gitlab-templates/freebsd-qt6.yml
|
- /gitlab-templates/freebsd-qt6.yml
|
||||||
- /gitlab-templates/flatpak.yml
|
- /gitlab-templates/flatpak.yml
|
||||||
# - /gitlab-templates/craft-android-qt6-apks.yml
|
- /gitlab-templates/craft-android-qt6-apks.yml
|
||||||
# - /gitlab-templates/craft-appimage-qt6.yml
|
- /gitlab-templates/craft-appimage-qt6.yml
|
||||||
# - /gitlab-templates/craft-windows-x86-64-qt6.yml
|
- /gitlab-templates/craft-windows-x86-64-qt6.yml
|
||||||
|
|||||||
@@ -40,4 +40,4 @@ Dependencies:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
per-test-timeout: 90
|
per-test-timeout: 90
|
||||||
require-passing-tests-on: [ '@all' ]
|
require-passing-tests-on: [ 'Linux', 'Android', 'FreeBSD' ]
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ cmake_minimum_required(VERSION 3.16)
|
|||||||
|
|
||||||
# KDE Applications version, managed by release script.
|
# KDE Applications version, managed by release script.
|
||||||
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||||
set(RELEASE_SERVICE_VERSION_MINOR "07")
|
set(RELEASE_SERVICE_VERSION_MINOR "05")
|
||||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
set(RELEASE_SERVICE_VERSION_MICRO "2")
|
||||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||||
|
|
||||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
# SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import unittest
|
|
||||||
import time
|
|
||||||
|
|
||||||
from appium import webdriver
|
|
||||||
from appium.options.common.base import AppiumOptions
|
|
||||||
from appium.webdriver.common.appiumby import AppiumBy
|
|
||||||
|
|
||||||
|
|
||||||
class CreateRoomTest(unittest.TestCase):
|
|
||||||
|
|
||||||
mockServerProcess: subprocess.Popen
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(cls):
|
|
||||||
cls.mockServerProcess = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), "login-server.py")])
|
|
||||||
options = AppiumOptions()
|
|
||||||
options.set_capability("app", "neochat --ignore-ssl-errors --test")
|
|
||||||
cls.driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', options=options)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
if not self._outcome.result.wasSuccessful():
|
|
||||||
self.driver.get_screenshot_as_file("failed_test_shot_{}.png".format(self.id()))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def tearDownClass(self):
|
|
||||||
self.mockServerProcess.terminate()
|
|
||||||
self.driver.quit()
|
|
||||||
|
|
||||||
def test_create_room(self):
|
|
||||||
self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click()
|
|
||||||
self.driver.find_element(by=AppiumBy.NAME, value="Show Menu").click()
|
|
||||||
self.driver.find_element(by=AppiumBy.NAME, value="Create a Room").click()
|
|
||||||
self.driver.find_element(by=AppiumBy.NAME, value="Name:").send_keys("Super awesome room name")#
|
|
||||||
time.sleep(0.1) # without this, the second half of the text is sent to the topic field?!
|
|
||||||
self.driver.find_element(by=AppiumBy.NAME, value="Topic:").send_keys("There are not enough raccoons here")
|
|
||||||
time.sleep(0.1)
|
|
||||||
self.driver.find_element(by=AppiumBy.NAME, value="Create Room").click()
|
|
||||||
time.sleep(0.1)
|
|
||||||
self.driver.find_element(by=AppiumBy.NAME, value="Super awesome room name").click()
|
|
||||||
self.driver.find_element(by=AppiumBy.NAME, value="Show Room Information").click()
|
|
||||||
self.driver.find_element(by=AppiumBy.NAME, value="There are not enough raccoons here")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
{
|
|
||||||
"next_batch": "batch1234",
|
|
||||||
"rooms": {
|
|
||||||
"join": {
|
|
||||||
"!newroom123321:localhost:1234": {
|
|
||||||
"state": {
|
|
||||||
"events": [
|
|
||||||
{
|
|
||||||
"type": "m.room.member",
|
|
||||||
"state_key": "@user:localhost:1234",
|
|
||||||
"sender": "@user:localhost:1234",
|
|
||||||
"origin_server_ts": 1432735824653,
|
|
||||||
"event_id": "$event_id_1234_0:localhost:1234",
|
|
||||||
"room_id": "!newroom123321:localhost:1234",
|
|
||||||
"content": {
|
|
||||||
"avatar_url": "",
|
|
||||||
"displayname": "A Display Name",
|
|
||||||
"membership": "join",
|
|
||||||
"reason": "Nothing"
|
|
||||||
},
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "m.room.name",
|
|
||||||
"state_key": "",
|
|
||||||
"sender": "@user:localhost:1234",
|
|
||||||
"origin_server_ts": 1432735824653,
|
|
||||||
"event_id": "$event_id_1234_1:localhost:1234",
|
|
||||||
"room_id": "!newroom123321:localhost:1234",
|
|
||||||
"content": {
|
|
||||||
"name": "Super awesome room name"
|
|
||||||
},
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "m.room.topic",
|
|
||||||
"state_key": "",
|
|
||||||
"sender": "@user:localhost:1234",
|
|
||||||
"origin_server_ts": 1432735824653,
|
|
||||||
"event_id": "$event_id_1234_2:localhost:1234",
|
|
||||||
"room_id": "!newroom123321:localhost:1234",
|
|
||||||
"content": {
|
|
||||||
"topic": "There are not enough raccoons here"
|
|
||||||
},
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"timeline": {
|
|
||||||
"events": [
|
|
||||||
{
|
|
||||||
"type": "m.room.message",
|
|
||||||
"sender": "@user:localhost:1234",
|
|
||||||
"origin_server_ts": 1432735824653,
|
|
||||||
"event_id": "$event_id_1234_1:localhost:1234",
|
|
||||||
"room_id": "!newroom123321:localhost:1234",
|
|
||||||
"content": {
|
|
||||||
"body": "This is a message",
|
|
||||||
"format": "org.matrix.custom.html",
|
|
||||||
"formatted_body": "<a href=\"https://matrix.to/#/@user:localhost:1234\">User</a>:",
|
|
||||||
"msgtype": "m.text"
|
|
||||||
},
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,8 +6,6 @@ from flask import Flask, request, abort
|
|||||||
import os
|
import os
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
next_sync_payload = ""
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/_matrix/client/v3/login", methods=["GET"])
|
@app.route("/_matrix/client/v3/login", methods=["GET"])
|
||||||
def login_get():
|
def login_get():
|
||||||
@@ -44,13 +42,8 @@ def load_json(name):
|
|||||||
|
|
||||||
@app.route("/_matrix/client/r0/sync")
|
@app.route("/_matrix/client/r0/sync")
|
||||||
def sync():
|
def sync():
|
||||||
global next_sync_payload
|
|
||||||
result = dict()
|
result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
|
||||||
if len(next_sync_payload) > 0:
|
|
||||||
result = load_json(next_sync_payload)
|
|
||||||
next_sync_payload = ""
|
|
||||||
else:
|
|
||||||
result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms")
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@app.route("/.well-known/matrix/client")
|
@app.route("/.well-known/matrix/client")
|
||||||
@@ -72,18 +65,6 @@ def upload_keys():
|
|||||||
reply = dict()
|
reply = dict()
|
||||||
return reply
|
return reply
|
||||||
|
|
||||||
@app.route("/_matrix/client/v3/createRoom", methods=["POST"])
|
|
||||||
def create_room():
|
|
||||||
global next_sync_payload
|
|
||||||
data = request.get_json()
|
|
||||||
if data["name"] != "Super awesome room name" or data["topic"] != "There are not enough raccoons here":
|
|
||||||
return dict(), 400
|
|
||||||
response = dict()
|
|
||||||
response["room_id"] = "!newroom123321:localhost:1234"
|
|
||||||
next_sync_payload = "sync_response_new_room"
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(ssl_context='adhoc', port=1234)
|
app.run(ssl_context='adhoc', port=1234)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
|
||||||
#include <Quotient/roommember.h>
|
|
||||||
#include <Quotient/syncdata.h>
|
#include <Quotient/syncdata.h>
|
||||||
#include <qtestcase.h>
|
#include <qtestcase.h>
|
||||||
|
|
||||||
@@ -51,7 +50,7 @@ void ChatBarCacheTest::empty()
|
|||||||
QCOMPARE(chatBarCache->replyId(), QString());
|
QCOMPARE(chatBarCache->replyId(), QString());
|
||||||
QCOMPARE(chatBarCache->isEditing(), false);
|
QCOMPARE(chatBarCache->isEditing(), false);
|
||||||
QCOMPARE(chatBarCache->editId(), QString());
|
QCOMPARE(chatBarCache->editId(), QString());
|
||||||
QCOMPARE(chatBarCache->relationUser(), room->member(QString()));
|
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||||
}
|
}
|
||||||
@@ -65,7 +64,7 @@ void ChatBarCacheTest::noRoom()
|
|||||||
// ChatBarCache has no parent.
|
// ChatBarCache has no parent.
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
|
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
|
||||||
QCOMPARE(chatBarCache->relationUser(), Quotient::RoomMember());
|
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
|
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||||
@@ -81,7 +80,7 @@ void ChatBarCacheTest::badParent()
|
|||||||
// ChatBarCache has no parent.
|
// ChatBarCache has no parent.
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
|
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
|
||||||
QCOMPARE(chatBarCache->relationUser(), Quotient::RoomMember());
|
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
|
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||||
@@ -99,7 +98,7 @@ void ChatBarCacheTest::reply()
|
|||||||
QCOMPARE(chatBarCache->replyId(), QLatin1String("$153456789:example.org"));
|
QCOMPARE(chatBarCache->replyId(), QLatin1String("$153456789:example.org"));
|
||||||
QCOMPARE(chatBarCache->isEditing(), false);
|
QCOMPARE(chatBarCache->isEditing(), false);
|
||||||
QCOMPARE(chatBarCache->editId(), QString());
|
QCOMPARE(chatBarCache->editId(), QString());
|
||||||
QCOMPARE(chatBarCache->relationUser(), room->member(QLatin1String("@example:example.org")));
|
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||||
}
|
}
|
||||||
@@ -116,7 +115,7 @@ void ChatBarCacheTest::edit()
|
|||||||
QCOMPARE(chatBarCache->replyId(), QString());
|
QCOMPARE(chatBarCache->replyId(), QString());
|
||||||
QCOMPARE(chatBarCache->isEditing(), true);
|
QCOMPARE(chatBarCache->isEditing(), true);
|
||||||
QCOMPARE(chatBarCache->editId(), QLatin1String("$153456789:example.org"));
|
QCOMPARE(chatBarCache->editId(), QLatin1String("$153456789:example.org"));
|
||||||
QCOMPARE(chatBarCache->relationUser(), room->member(QLatin1String("@example:example.org")));
|
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||||
}
|
}
|
||||||
@@ -133,7 +132,7 @@ void ChatBarCacheTest::attachment()
|
|||||||
QCOMPARE(chatBarCache->replyId(), QString());
|
QCOMPARE(chatBarCache->replyId(), QString());
|
||||||
QCOMPARE(chatBarCache->isEditing(), false);
|
QCOMPARE(chatBarCache->isEditing(), false);
|
||||||
QCOMPARE(chatBarCache->editId(), QString());
|
QCOMPARE(chatBarCache->editId(), QString());
|
||||||
QCOMPARE(chatBarCache->relationUser(), room->member(QString()));
|
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
|
QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"$153456789:example.org": {
|
"$153456789:example.org": {
|
||||||
"m.read": {
|
"m.read": {
|
||||||
"@alice:example.org": {
|
"@alice:matrix.org": {
|
||||||
"ts": 1436451550453
|
"ts": 1436451550453
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
autotests/data/test-invalidmatrixtolink-event.json
Normal file
14
autotests/data/test-invalidmatrixtolink-event.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "https://matrix.to/#/@alice:example.org",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$validlink1:example.org",
|
||||||
|
"origin_server_ts": 1432735824654,
|
||||||
|
"room_id": "!test:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
14
autotests/data/test-invalidmxclink-event.json
Normal file
14
autotests/data/test-invalidmxclink-event.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$validlink1:example.org",
|
||||||
|
"origin_server_ts": 1432735824654,
|
||||||
|
"room_id": "!test:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
14
autotests/data/test-invalidnospacelink-event.json
Normal file
14
autotests/data/test-invalidnospacelink-event.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "testhttps://kde.org",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$validlink1:example.org",
|
||||||
|
"origin_server_ts": 1432735824654,
|
||||||
|
"room_id": "!test:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,14 +37,16 @@
|
|||||||
"events": [
|
"events": [
|
||||||
{
|
{
|
||||||
"content": {
|
"content": {
|
||||||
"displayname": "Example",
|
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||||
"membership": "join"
|
"displayname": "Alice Margatroid",
|
||||||
|
"membership": "join",
|
||||||
|
"reason": "Looking for support"
|
||||||
},
|
},
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
"event_id": "$143273582443PhrSn:example.org",
|
||||||
"origin_server_ts": 1432735824653,
|
"origin_server_ts": 1432735824653,
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
"sender": "@example:example.org",
|
"sender": "@example:example.org",
|
||||||
"state_key": "@example:example.org",
|
"state_key": "@alice:example.org",
|
||||||
"type": "m.room.member",
|
"type": "m.room.member",
|
||||||
"unsigned": {
|
"unsigned": {
|
||||||
"age": 1234
|
"age": 1234
|
||||||
|
|||||||
@@ -51,21 +51,6 @@
|
|||||||
"unsigned": {
|
"unsigned": {
|
||||||
"age": 1234
|
"age": 1234
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"displayname": "Example",
|
|
||||||
"membership": "join"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1432735824653,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "@example:example.org",
|
|
||||||
"state_key": "@example:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
14
autotests/data/test-validplainlink-event.json
Normal file
14
autotests/data/test-validplainlink-event.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "https://kde.org",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$validlink1:example.org",
|
||||||
|
"origin_server_ts": 1432735824654,
|
||||||
|
"room_id": "!test:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
14
autotests/data/test-validplainwwwlink-event.json
Normal file
14
autotests/data/test-validplainwwwlink-event.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "www.example.org",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$validlink1:example.org",
|
||||||
|
"origin_server_ts": 1432735824654,
|
||||||
|
"room_id": "!test:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
16
autotests/data/test-validrichlink-event.json
Normal file
16
autotests/data/test-validrichlink-event.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "[Rich Link](https://kde.org)",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<a href=\"https://kde.org\">Rich Link</a>",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$validlink1:example.org",
|
||||||
|
"origin_server_ts": 1432735824654,
|
||||||
|
"room_id": "!test:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,7 +56,6 @@ private Q_SLOTS:
|
|||||||
void genericBody();
|
void genericBody();
|
||||||
void nullGenericBody();
|
void nullGenericBody();
|
||||||
void markdownBody();
|
void markdownBody();
|
||||||
void markdownBodyReply();
|
|
||||||
void subtitle();
|
void subtitle();
|
||||||
void nullSubtitle();
|
void nullSubtitle();
|
||||||
void mediaInfo();
|
void mediaInfo();
|
||||||
@@ -101,27 +100,28 @@ void EventHandlerTest::nullEventId()
|
|||||||
void EventHandlerTest::author()
|
void EventHandlerTest::author()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(0).get();
|
auto event = room->messageEvents().at(0).get();
|
||||||
auto author = room->member(event->senderId());
|
auto author = room->user(event->senderId());
|
||||||
EventHandler eventHandler(room, event);
|
EventHandler eventHandler(room, event);
|
||||||
|
|
||||||
auto eventHandlerAuthor = eventHandler.getAuthor();
|
auto eventHandlerAuthor = eventHandler.getAuthor();
|
||||||
|
|
||||||
QCOMPARE(eventHandlerAuthor.isLocalMember(), author.id() == room->localMember().id());
|
QCOMPARE(eventHandlerAuthor["isLocalUser"_ls], author->id() == room->localUser()->id());
|
||||||
QCOMPARE(eventHandlerAuthor.id(), author.id());
|
QCOMPARE(eventHandlerAuthor["id"_ls], author->id());
|
||||||
QCOMPARE(eventHandlerAuthor.displayName(), author.displayName());
|
QCOMPARE(eventHandlerAuthor["displayName"_ls], author->displayname(room));
|
||||||
QCOMPARE(eventHandlerAuthor.avatarUrl(), author.avatarUrl());
|
QCOMPARE(eventHandlerAuthor["avatarSource"_ls], room->avatarForMember(author));
|
||||||
QCOMPARE(eventHandlerAuthor.avatarMediaId(), author.avatarMediaId());
|
QCOMPARE(eventHandlerAuthor["avatarMediaId"_ls], author->avatarMediaId(room));
|
||||||
QCOMPARE(eventHandlerAuthor.color(), author.color());
|
QCOMPARE(eventHandlerAuthor["color"_ls], Utils::getUserColor(author->hueF()));
|
||||||
|
QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(author));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullAuthor()
|
void EventHandlerTest::nullAuthor()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getAuthor(), RoomMember());
|
QCOMPARE(emptyHandler.getAuthor(), QVariantMap());
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
EventHandler noEventHandler(room, nullptr);
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
|
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
|
||||||
QCOMPARE(noEventHandler.getAuthor(), RoomMember());
|
QCOMPARE(noEventHandler.getAuthor(), room->getUser(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::authorDisplayName()
|
void EventHandlerTest::authorDisplayName()
|
||||||
@@ -301,13 +301,6 @@ void EventHandlerTest::markdownBody()
|
|||||||
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("This is an example\ntext message"));
|
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("This is an example\ntext message"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::markdownBodyReply()
|
|
||||||
{
|
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(5).get());
|
|
||||||
|
|
||||||
QCOMPARE(eventHandler.getMarkdownBody(), QStringLiteral("reply"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void EventHandlerTest::subtitle()
|
void EventHandlerTest::subtitle()
|
||||||
{
|
{
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
EventHandler eventHandler(room, room->messageEvents().at(0).get());
|
||||||
@@ -392,30 +385,31 @@ void EventHandlerTest::nullReplyId()
|
|||||||
void EventHandlerTest::replyAuthor()
|
void EventHandlerTest::replyAuthor()
|
||||||
{
|
{
|
||||||
auto replyEvent = room->messageEvents().at(0).get();
|
auto replyEvent = room->messageEvents().at(0).get();
|
||||||
auto replyAuthor = room->member(replyEvent->senderId());
|
auto replyAuthor = room->user(replyEvent->senderId());
|
||||||
EventHandler eventHandler(room, room->messageEvents().at(5).get());
|
EventHandler eventHandler(room, room->messageEvents().at(5).get());
|
||||||
|
|
||||||
auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
|
auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
|
||||||
|
|
||||||
QCOMPARE(eventHandlerReplyAuthor.isLocalMember(), replyAuthor.id() == room->localMember().id());
|
QCOMPARE(eventHandlerReplyAuthor["isLocalUser"_ls], replyAuthor->id() == room->localUser()->id());
|
||||||
QCOMPARE(eventHandlerReplyAuthor.id(), replyAuthor.id());
|
QCOMPARE(eventHandlerReplyAuthor["id"_ls], replyAuthor->id());
|
||||||
QCOMPARE(eventHandlerReplyAuthor.displayName(), replyAuthor.displayName());
|
QCOMPARE(eventHandlerReplyAuthor["displayName"_ls], replyAuthor->displayname(room));
|
||||||
QCOMPARE(eventHandlerReplyAuthor.avatarUrl(), replyAuthor.avatarUrl());
|
QCOMPARE(eventHandlerReplyAuthor["avatarSource"_ls], room->avatarForMember(replyAuthor));
|
||||||
QCOMPARE(eventHandlerReplyAuthor.avatarMediaId(), replyAuthor.avatarMediaId());
|
QCOMPARE(eventHandlerReplyAuthor["avatarMediaId"_ls], replyAuthor->avatarMediaId(room));
|
||||||
QCOMPARE(eventHandlerReplyAuthor.color(), replyAuthor.color());
|
QCOMPARE(eventHandlerReplyAuthor["color"_ls], Utils::getUserColor(replyAuthor->hueF()));
|
||||||
|
QCOMPARE(eventHandlerReplyAuthor["object"_ls], QVariant::fromValue(replyAuthor));
|
||||||
|
|
||||||
EventHandler eventHandlerNoAuthor(room, room->messageEvents().at(0).get());
|
EventHandler eventHandlerNoAuthor(room, room->messageEvents().at(0).get());
|
||||||
QCOMPARE(eventHandlerNoAuthor.getReplyAuthor(), RoomMember());
|
QCOMPARE(eventHandlerNoAuthor.getReplyAuthor(), room->getUser(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::nullReplyAuthor()
|
void EventHandlerTest::nullReplyAuthor()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getReplyAuthor(), RoomMember());
|
QCOMPARE(emptyHandler.getReplyAuthor(), QVariantMap());
|
||||||
|
|
||||||
EventHandler noEventHandler(room, nullptr);
|
EventHandler noEventHandler(room, nullptr);
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_event set to nullptr. Returning empty user.");
|
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_event set to nullptr. Returning empty user.");
|
||||||
QCOMPARE(noEventHandler.getReplyAuthor(), RoomMember());
|
QCOMPARE(noEventHandler.getReplyAuthor(), room->getUser(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::replyBody()
|
void EventHandlerTest::replyBody()
|
||||||
@@ -529,10 +523,10 @@ void EventHandlerTest::readMarkers()
|
|||||||
auto readMarkers = eventHandler.getReadMarkers();
|
auto readMarkers = eventHandler.getReadMarkers();
|
||||||
|
|
||||||
QCOMPARE(readMarkers.size(), 1);
|
QCOMPARE(readMarkers.size(), 1);
|
||||||
QCOMPARE(readMarkers[0].id(), QStringLiteral("@alice:example.org"));
|
QCOMPARE(readMarkers[0].toMap()["id"_ls], QStringLiteral("@alice:matrix.org"));
|
||||||
|
|
||||||
QCOMPARE(eventHandler.getNumberExcessReadMarkers(), QString());
|
QCOMPARE(eventHandler.getNumberExcessReadMarkers(), QString());
|
||||||
QCOMPARE(eventHandler.getReadMarkersString(), QStringLiteral("1 user: Alice Margatroid"));
|
QCOMPARE(eventHandler.getReadMarkersString(), QStringLiteral("1 user: @alice:matrix.org"));
|
||||||
|
|
||||||
EventHandler eventHandler2(room, room->messageEvents().at(2).get());
|
EventHandler eventHandler2(room, room->messageEvents().at(2).get());
|
||||||
QCOMPARE(eventHandler2.hasReadMarkers(), true);
|
QCOMPARE(eventHandler2.hasReadMarkers(), true);
|
||||||
@@ -552,7 +546,7 @@ void EventHandlerTest::nullReadMarkers()
|
|||||||
QCOMPARE(emptyHandler.hasReadMarkers(), false);
|
QCOMPARE(emptyHandler.hasReadMarkers(), false);
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getReadMarkers(), QList<Quotient::RoomMember>());
|
QCOMPARE(emptyHandler.getReadMarkers(), QVariantList());
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_room set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_room set to nullptr.");
|
||||||
QCOMPARE(emptyHandler.getNumberExcessReadMarkers(), QString());
|
QCOMPARE(emptyHandler.getNumberExcessReadMarkers(), QString());
|
||||||
@@ -566,7 +560,7 @@ void EventHandlerTest::nullReadMarkers()
|
|||||||
QCOMPARE(noEventHandler.hasReadMarkers(), false);
|
QCOMPARE(noEventHandler.hasReadMarkers(), false);
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_event set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_event set to nullptr.");
|
||||||
QCOMPARE(noEventHandler.getReadMarkers(), QList<Quotient::RoomMember>());
|
QCOMPARE(noEventHandler.getReadMarkers(), QVariantList());
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_event set to nullptr.");
|
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_event set to nullptr.");
|
||||||
QCOMPARE(noEventHandler.getNumberExcessReadMarkers(), QString());
|
QCOMPARE(noEventHandler.getNumberExcessReadMarkers(), QString());
|
||||||
|
|||||||
@@ -6,11 +6,12 @@
|
|||||||
|
|
||||||
#include "linkpreviewer.h"
|
#include "linkpreviewer.h"
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include <Quotient/events/roommessageevent.h>
|
#include <Quotient/events/roommessageevent.h>
|
||||||
#include <Quotient/quotient_common.h>
|
#include <Quotient/quotient_common.h>
|
||||||
#include <Quotient/syncdata.h>
|
#include <Quotient/syncdata.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include "testutils.h"
|
#include "testutils.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -29,9 +30,6 @@ private Q_SLOTS:
|
|||||||
void linkPreviewsMatch_data();
|
void linkPreviewsMatch_data();
|
||||||
void linkPreviewsMatch();
|
void linkPreviewsMatch();
|
||||||
|
|
||||||
void multipleLinkPreviewsMatch_data();
|
|
||||||
void multipleLinkPreviewsMatch();
|
|
||||||
|
|
||||||
void linkPreviewsReject_data();
|
void linkPreviewsReject_data();
|
||||||
void linkPreviewsReject();
|
void linkPreviewsReject();
|
||||||
};
|
};
|
||||||
@@ -44,59 +42,45 @@ void LinkPreviewerTest::initTestCase()
|
|||||||
|
|
||||||
void LinkPreviewerTest::linkPreviewsMatch_data()
|
void LinkPreviewerTest::linkPreviewsMatch_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("inputString");
|
QTest::addColumn<QString>("eventSource");
|
||||||
QTest::addColumn<QUrl>("testOutputLink");
|
QTest::addColumn<QUrl>("testOutputLink");
|
||||||
|
|
||||||
QTest::newRow("plainHttps") << QStringLiteral("https://kde.org") << QUrl("https://kde.org"_ls);
|
QTest::newRow("plainHttps") << QStringLiteral("test-validplainlink-event.json") << QUrl("https://kde.org"_ls);
|
||||||
QTest::newRow("richHttps") << QStringLiteral("<a href=\"https://kde.org\">Rich Link</a>") << QUrl("https://kde.org"_ls);
|
QTest::newRow("richHttps") << QStringLiteral("test-validrichlink-event.json") << QUrl("https://kde.org"_ls);
|
||||||
QTest::newRow("richHttpsLinkDescription") << QStringLiteral("<a href=\"https://kde.org\">https://kde.org</a>") << 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkPreviewerTest::linkPreviewsMatch()
|
void LinkPreviewerTest::linkPreviewsMatch()
|
||||||
{
|
{
|
||||||
QFETCH(QString, inputString);
|
QFETCH(QString, eventSource);
|
||||||
QFETCH(QUrl, testOutputLink);
|
QFETCH(QUrl, testOutputLink);
|
||||||
|
|
||||||
auto link = LinkPreviewer::linkPreviews(inputString)[0];
|
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
||||||
|
auto linkPreviewer = LinkPreviewer(LinkPreviewer::linkPreview(event.get()), connection);
|
||||||
|
|
||||||
QCOMPARE(link, testOutputLink);
|
QCOMPARE(linkPreviewer.empty(), false);
|
||||||
}
|
QCOMPARE(linkPreviewer.url(), testOutputLink);
|
||||||
|
|
||||||
void LinkPreviewerTest::multipleLinkPreviewsMatch_data()
|
|
||||||
{
|
|
||||||
QTest::addColumn<QString>("inputString");
|
|
||||||
QTest::addColumn<QList<QUrl>>("testOutputLinks");
|
|
||||||
|
|
||||||
QTest::newRow("multipleHttps") << QStringLiteral("www.example.org https://kde.org") << QList{QUrl("www.example.org"_ls), QUrl("https://kde.org"_ls)};
|
|
||||||
QTest::newRow("multipleHttps1Invalid") << QStringLiteral("www.example.org mxc://example.org/SEsfnsuifSDFSSEF") << QList{QUrl("www.example.org"_ls)};
|
|
||||||
}
|
|
||||||
|
|
||||||
void LinkPreviewerTest::multipleLinkPreviewsMatch()
|
|
||||||
{
|
|
||||||
QFETCH(QString, inputString);
|
|
||||||
QFETCH(QList<QUrl>, testOutputLinks);
|
|
||||||
|
|
||||||
auto links = LinkPreviewer::linkPreviews(inputString);
|
|
||||||
|
|
||||||
QCOMPARE(links, testOutputLinks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkPreviewerTest::linkPreviewsReject_data()
|
void LinkPreviewerTest::linkPreviewsReject_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("inputString");
|
QTest::addColumn<QString>("eventSource");
|
||||||
|
|
||||||
QTest::newRow("mxc") << QStringLiteral("mxc://example.org/SEsfnsuifSDFSSEF");
|
QTest::newRow("mxc") << QStringLiteral("test-invalidmxclink-event.json");
|
||||||
QTest::newRow("matrixTo") << QStringLiteral("https://matrix.to/#/@alice:example.org");
|
QTest::newRow("matrixTo") << QStringLiteral("test-invalidmatrixtolink-event.json");
|
||||||
QTest::newRow("noSpace") << QStringLiteral("testhttps://kde.org");
|
QTest::newRow("noSpace") << QStringLiteral("test-invalidnospacelink-event.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkPreviewerTest::linkPreviewsReject()
|
void LinkPreviewerTest::linkPreviewsReject()
|
||||||
{
|
{
|
||||||
QFETCH(QString, inputString);
|
QFETCH(QString, eventSource);
|
||||||
|
|
||||||
auto links = LinkPreviewer::linkPreviews(inputString);
|
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
||||||
|
auto linkPreviewer = LinkPreviewer(LinkPreviewer::linkPreview(event.get()), connection);
|
||||||
|
|
||||||
QCOMPARE(links.empty(), true);
|
QCOMPARE(linkPreviewer.empty(), true);
|
||||||
|
QCOMPARE(linkPreviewer.url(), QUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(LinkPreviewerTest)
|
QTEST_MAIN(LinkPreviewerTest)
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ void ReactionModelTest::basicReaction()
|
|||||||
QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), QStringLiteral("👍"));
|
QCOMPARE(model.data(model.index(0), ReactionModel::ReactionRole), QStringLiteral("👍"));
|
||||||
QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole),
|
QCOMPARE(model.data(model.index(0), ReactionModel::ToolTipRole),
|
||||||
QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
QStringLiteral("@alice:matrix.org reacted with <span style=\"font-family: 'emoji';\">👍</span>"));
|
||||||
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalMember), false);
|
auto authorList = QVariantList{room->getUser(room->user(QStringLiteral("@alice:matrix.org")))};
|
||||||
|
QCOMPARE(model.data(model.index(0), ReactionModel::AuthorsRole), authorList);
|
||||||
|
QCOMPARE(model.data(model.index(0), ReactionModel::HasLocalUser), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReactionModelTest::newReaction()
|
void ReactionModelTest::newReaction()
|
||||||
|
|||||||
@@ -95,8 +95,10 @@
|
|||||||
<p xml:lang="ka">NeoChat ჩატის აპია, რომელიც საშუალება გაძლევთ, Matrix-ის ქსელის საშუალებები ბოლომდე გამოიყენოთ. ის გაძლევთ უსაფრთხო გზას, გააგზავნოთ ტექსტური შეტყობინებები, ვიდეოებ და აუდიოფაილები თქვენს ოჯახთან, კოლეგებთან და მეგობრებთან.</p>
|
<p xml:lang="ka">NeoChat ჩატის აპია, რომელიც საშუალება გაძლევთ, Matrix-ის ქსელის საშუალებები ბოლომდე გამოიყენოთ. ის გაძლევთ უსაფრთხო გზას, გააგზავნოთ ტექსტური შეტყობინებები, ვიდეოებ და აუდიოფაილები თქვენს ოჯახთან, კოლეგებთან და მეგობრებთან.</p>
|
||||||
<p xml:lang="lv">„NeoChat“ ir tērzēšanas programma, kas ļauj pilnvērtīgi izmantot „Matrix“ tīklu. Tā sniedz drošu veidu teksta ziņu, video un audio sūtīšanai ģimenes locekļiem, kolēģiem un draugiem.</p>
|
<p xml:lang="lv">„NeoChat“ ir tērzēšanas programma, kas ļauj pilnvērtīgi izmantot „Matrix“ tīklu. Tā sniedz drošu veidu teksta ziņu, video un audio sūtīšanai ģimenes locekļiem, kolēģiem un draugiem.</p>
|
||||||
<p xml:lang="nl">NeoChat is een chat-toepassing die u het volledige voordeel van het Matrix-netwerk laat genieten. Het levert u op een veilige manier tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden te verzenden.</p>
|
<p xml:lang="nl">NeoChat is een chat-toepassing die u het volledige voordeel van het Matrix-netwerk laat genieten. Het levert u op een veilige manier tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden te verzenden.</p>
|
||||||
|
<p xml:lang="nn">NeoChat er ein prateapp som lèt deg bruka all funksjonalitet i Matrix-nettverket. Du kan utveksla tekst, lyd og videoar med vennar, familie og kollegaar på ein trygg måte.</p>
|
||||||
<p xml:lang="pl">NoeChat to aplikacja do rozmów, która umożliwia wykorzystanie wszystkich możliwości Matriksa. Umożliwia wysyłanie wiadomości tekstowych, filmów i dźwięków w bezpieczny sposób do twojej rodziny, kolegów i przyjaciół.</p>
|
<p xml:lang="pl">NoeChat to aplikacja do rozmów, która umożliwia wykorzystanie wszystkich możliwości Matriksa. Umożliwia wysyłanie wiadomości tekstowych, filmów i dźwięków w bezpieczny sposób do twojej rodziny, kolegów i przyjaciół.</p>
|
||||||
<p xml:lang="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p>
|
<p xml:lang="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p>
|
||||||
|
<p xml:lang="sv">NeoChat är ett chattprogram som låter dig dra full nytta av Matrix-nätverket. Det ger dig ett säkert sätt att skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner.</p>
|
||||||
<p xml:lang="tr">NeoChat, Matrix ağının tüm özelliklerini kullanan bir sohbet uygulamasıdır. Ailenize, arkadaşlarınıza ve iş arkadaşlarınıza metin iletileri, ses ve video dosyaları göndermenin kolay bir yolunu sunar.</p>
|
<p xml:lang="tr">NeoChat, Matrix ağının tüm özelliklerini kullanan bir sohbet uygulamasıdır. Ailenize, arkadaşlarınıza ve iş arkadaşlarınıza metin iletileri, ses ve video dosyaları göndermenin kolay bir yolunu sunar.</p>
|
||||||
<p xml:lang="uk">NeoChat є програмою для спілкування, за допомогою якої ви можете скористатися усіма перевагами мережі Matrix. За її допомогою ви можете безпечно надсилати текстові повідомлення, відео та звукові файли вашим родичам, колегам та друзям.</p>
|
<p xml:lang="uk">NeoChat є програмою для спілкування, за допомогою якої ви можете скористатися усіма перевагами мережі Matrix. За її допомогою ви можете безпечно надсилати текстові повідомлення, відео та звукові файли вашим родичам, колегам та друзям.</p>
|
||||||
<p xml:lang="x-test">xxNeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.xx</p>
|
<p xml:lang="x-test">xxNeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.xx</p>
|
||||||
@@ -212,7 +214,7 @@
|
|||||||
<li xml:lang="sl">Sticker Packs - MSC2545</li>
|
<li xml:lang="sl">Sticker Packs - MSC2545</li>
|
||||||
<li xml:lang="sv">Sticker Packs - MSC2545</li>
|
<li xml:lang="sv">Sticker Packs - MSC2545</li>
|
||||||
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
|
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
|
||||||
<li xml:lang="tr">Yapışkan Paketleri — MSC2545</li>
|
<li xml:lang="tr">Çıkartma Paketleri — MSC2545</li>
|
||||||
<li xml:lang="uk">Пакунки наліпок - MSC2545</li>
|
<li xml:lang="uk">Пакунки наліпок - MSC2545</li>
|
||||||
<li xml:lang="x-test">xxSticker Packs - MSC2545xx</li>
|
<li xml:lang="x-test">xxSticker Packs - MSC2545xx</li>
|
||||||
<li xml:lang="zh-TW">貼圖包 - MSC2545</li>
|
<li xml:lang="zh-TW">貼圖包 - MSC2545</li>
|
||||||
@@ -327,8 +329,10 @@
|
|||||||
<caption xml:lang="ka">აღმოაჩინეთ ახალი საზოგადოებები Matrix Spaces-თან ერთად</caption>
|
<caption xml:lang="ka">აღმოაჩინეთ ახალი საზოგადოებები Matrix Spaces-თან ერთად</caption>
|
||||||
<caption xml:lang="lv">Atklājiet jaunas kopienas ar „Matrix“ telpām</caption>
|
<caption xml:lang="lv">Atklājiet jaunas kopienas ar „Matrix“ telpām</caption>
|
||||||
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption>
|
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption>
|
||||||
|
<caption xml:lang="nn">Oppdag nye fellesskap med Matrix Spaces</caption>
|
||||||
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
|
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
|
||||||
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
|
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
|
||||||
|
<caption xml:lang="sv">Upptäck nya gemenskaper med Matrix Spaces</caption>
|
||||||
<caption xml:lang="tr">Matrix Alanlar ile yeni topluluklar keşfedin</caption>
|
<caption xml:lang="tr">Matrix Alanlar ile yeni topluluklar keşfedin</caption>
|
||||||
<caption xml:lang="uk">Пошук нових спільнот за допомогою Matrix Spaces</caption>
|
<caption xml:lang="uk">Пошук нових спільнот за допомогою Matrix Spaces</caption>
|
||||||
<caption xml:lang="x-test">xxDiscover new communities with Matrix Spacesxx</caption>
|
<caption xml:lang="x-test">xxDiscover new communities with Matrix Spacesxx</caption>
|
||||||
@@ -411,6 +415,8 @@
|
|||||||
<content_attribute id="social-chat">intense</content_attribute>
|
<content_attribute id="social-chat">intense</content_attribute>
|
||||||
</content_rating>
|
</content_rating>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="24.05.2" date="2024-07-04"/>
|
||||||
|
<release version="24.05.1" date="2024-06-13"/>
|
||||||
<release version="24.05.0" date="2024-05-23"/>
|
<release version="24.05.0" date="2024-05-23"/>
|
||||||
<release version="24.02.2" date="2024-04-11"/>
|
<release version="24.02.2" date="2024-04-11"/>
|
||||||
<release version="24.02.1" date="2024-03-21"/>
|
<release version="24.02.1" date="2024-03-21"/>
|
||||||
|
|||||||
1304
po/ar/neochat.po
1304
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
1227
po/ast/neochat.po
1227
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
1403
po/az/neochat.po
1403
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -77,7 +77,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
|||||||
></term>
|
></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para
|
<para
|
||||||
>L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:exemple.org o matrix:r/root:exemple.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para>
|
>L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:example.org o matrix:r/root:example.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|||||||
1337
po/ca/neochat.po
1337
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1306
po/cs/neochat.po
1306
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1320
po/da/neochat.po
1320
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1392
po/de/neochat.po
1392
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1412
po/el/neochat.po
1412
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1299
po/en_GB/neochat.po
1299
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1282
po/eo/neochat.po
1282
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
1295
po/es/neochat.po
1295
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1434
po/eu/neochat.po
1434
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1388
po/fi/neochat.po
1388
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1304
po/fr/neochat.po
1304
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1395
po/hu/neochat.po
1395
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1299
po/ia/neochat.po
1299
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1399
po/id/neochat.po
1399
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1351
po/ie/neochat.po
1351
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1297
po/it/neochat.po
1297
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1227
po/ja/neochat.po
1227
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1293
po/ka/neochat.po
1293
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1382
po/ko/neochat.po
1382
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1227
po/lt/neochat.po
1227
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
1377
po/lv/neochat.po
1377
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
1330
po/nl/neochat.po
1330
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
2300
po/nn/neochat.po
2300
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1386
po/pa/neochat.po
1386
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
1311
po/pl/neochat.po
1311
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1386
po/pt/neochat.po
1386
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
1403
po/pt_BR/neochat.po
1403
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
1396
po/ru/neochat.po
1396
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1396
po/sk/neochat.po
1396
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
1278
po/sl/neochat.po
1278
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
2248
po/sv/neochat.po
2248
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1360
po/ta/neochat.po
1360
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1305
po/tok/neochat.po
1305
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
1352
po/tr/neochat.po
1352
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
1311
po/uk/neochat.po
1311
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
1249
po/zh_CN/neochat.po
1249
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
1265
po/zh_TW/neochat.po
1265
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,8 @@ add_library(neochat STATIC
|
|||||||
models/customemojimodel.h
|
models/customemojimodel.h
|
||||||
clipboard.cpp
|
clipboard.cpp
|
||||||
clipboard.h
|
clipboard.h
|
||||||
|
matriximageprovider.cpp
|
||||||
|
matriximageprovider.h
|
||||||
models/messageeventmodel.cpp
|
models/messageeventmodel.cpp
|
||||||
models/messageeventmodel.h
|
models/messageeventmodel.h
|
||||||
models/messagefiltermodel.cpp
|
models/messagefiltermodel.cpp
|
||||||
@@ -156,6 +158,7 @@ add_library(neochat STATIC
|
|||||||
models/linemodel.cpp
|
models/linemodel.cpp
|
||||||
models/linemodel.h
|
models/linemodel.h
|
||||||
events/locationbeaconevent.h
|
events/locationbeaconevent.h
|
||||||
|
events/serveraclevent.h
|
||||||
events/widgetevent.h
|
events/widgetevent.h
|
||||||
enums/messagecomponenttype.h
|
enums/messagecomponenttype.h
|
||||||
models/messagecontentmodel.cpp
|
models/messagecontentmodel.cpp
|
||||||
@@ -174,18 +177,6 @@ add_library(neochat STATIC
|
|||||||
foreigntypes.h
|
foreigntypes.h
|
||||||
models/threepidmodel.cpp
|
models/threepidmodel.cpp
|
||||||
models/threepidmodel.h
|
models/threepidmodel.h
|
||||||
threepidaddhelper.cpp
|
|
||||||
threepidaddhelper.h
|
|
||||||
jobs/neochatadd3pidjob.cpp
|
|
||||||
jobs/neochatadd3pidjob.h
|
|
||||||
identityserverhelper.cpp
|
|
||||||
identityserverhelper.h
|
|
||||||
enums/powerlevel.cpp
|
|
||||||
enums/powerlevel.h
|
|
||||||
models/permissionsmodel.cpp
|
|
||||||
models/permissionsmodel.h
|
|
||||||
threepidbindhelper.cpp
|
|
||||||
threepidbindhelper.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||||
@@ -216,10 +207,16 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/TypingPane.qml
|
qml/TypingPane.qml
|
||||||
qml/QuickSwitcher.qml
|
qml/QuickSwitcher.qml
|
||||||
qml/HoverActions.qml
|
qml/HoverActions.qml
|
||||||
|
qml/ChatBar.qml
|
||||||
qml/AttachmentPane.qml
|
qml/AttachmentPane.qml
|
||||||
|
qml/ReplyPane.qml
|
||||||
|
qml/CompletionMenu.qml
|
||||||
|
qml/PieProgressBar.qml
|
||||||
qml/QuickFormatBar.qml
|
qml/QuickFormatBar.qml
|
||||||
|
qml/EmojiPicker.qml
|
||||||
qml/UserDetailDialog.qml
|
qml/UserDetailDialog.qml
|
||||||
qml/CreateRoomDialog.qml
|
qml/CreateRoomDialog.qml
|
||||||
|
qml/EmojiDialog.qml
|
||||||
qml/OpenFileDialog.qml
|
qml/OpenFileDialog.qml
|
||||||
qml/KeyVerificationDialog.qml
|
qml/KeyVerificationDialog.qml
|
||||||
qml/ConfirmLogoutDialog.qml
|
qml/ConfirmLogoutDialog.qml
|
||||||
@@ -239,6 +236,9 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/ConfirmEncryptionDialog.qml
|
qml/ConfirmEncryptionDialog.qml
|
||||||
qml/RemoveSheet.qml
|
qml/RemoveSheet.qml
|
||||||
qml/BanSheet.qml
|
qml/BanSheet.qml
|
||||||
|
qml/EmojiTonesPicker.qml
|
||||||
|
qml/EmojiDelegate.qml
|
||||||
|
qml/EmojiGrid.qml
|
||||||
qml/RoomSearchPage.qml
|
qml/RoomSearchPage.qml
|
||||||
qml/LocationChooser.qml
|
qml/LocationChooser.qml
|
||||||
qml/TimelineView.qml
|
qml/TimelineView.qml
|
||||||
@@ -262,6 +262,7 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/SelectParentDialog.qml
|
qml/SelectParentDialog.qml
|
||||||
qml/QrCodeMaximizeComponent.qml
|
qml/QrCodeMaximizeComponent.qml
|
||||||
qml/SelectSpacesDialog.qml
|
qml/SelectSpacesDialog.qml
|
||||||
|
qml/AttachDialog.qml
|
||||||
qml/NotificationsView.qml
|
qml/NotificationsView.qml
|
||||||
qml/SearchPage.qml
|
qml/SearchPage.qml
|
||||||
qml/ServerComboBox.qml
|
qml/ServerComboBox.qml
|
||||||
@@ -279,26 +280,12 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/ConfirmLeaveDialog.qml
|
qml/ConfirmLeaveDialog.qml
|
||||||
qml/CodeMaximizeComponent.qml
|
qml/CodeMaximizeComponent.qml
|
||||||
qml/EditStateDialog.qml
|
qml/EditStateDialog.qml
|
||||||
qml/ConsentDialog.qml
|
|
||||||
qml/AskDirectChatConfirmation.qml
|
|
||||||
qml/HoverLinkIndicator.qml
|
|
||||||
qml/CrossSigningSetupDialog.qml
|
|
||||||
DEPENDENCIES
|
|
||||||
QtCore
|
|
||||||
QtQuick
|
|
||||||
IMPORTS
|
|
||||||
org.kde.neochat.timeline
|
|
||||||
org.kde.neochat.settings
|
|
||||||
org.kde.neochat.devtools
|
|
||||||
org.kde.neochat.login
|
|
||||||
org.kde.neochat.chatbar
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(settings)
|
add_subdirectory(settings)
|
||||||
add_subdirectory(timeline)
|
add_subdirectory(timeline)
|
||||||
add_subdirectory(devtools)
|
add_subdirectory(devtools)
|
||||||
add_subdirectory(login)
|
add_subdirectory(login)
|
||||||
add_subdirectory(chatbar)
|
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
qt_target_qml_sources(neochat QML_FILES qml/ShareAction.qml)
|
qt_target_qml_sources(neochat QML_FILES qml/ShareAction.qml)
|
||||||
@@ -392,7 +379,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
|
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
|
||||||
target_link_libraries(neochat PRIVATE settingsplugin timelineplugin devtoolsplugin loginplugin chatbarplugin)
|
target_link_libraries(neochat PRIVATE settingsplugin timelineplugin devtoolsplugin loginplugin)
|
||||||
target_link_libraries(neochat PUBLIC
|
target_link_libraries(neochat PUBLIC
|
||||||
Qt::Core
|
Qt::Core
|
||||||
Qt::Quick
|
Qt::Quick
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
|
|||||||
|
|
||||||
for (auto it = m_room->messageEvents().crbegin(); it != m_room->messageEvents().crend(); it++) {
|
for (auto it = m_room->messageEvents().crbegin(); it != m_room->messageEvents().crend(); it++) {
|
||||||
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
|
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
|
||||||
if (event->senderId() == m_room->localMember().id() && event->hasTextContent()) {
|
if (event->senderId() == m_room->localUser()->id() && event->hasTextContent()) {
|
||||||
QString originalString;
|
QString originalString;
|
||||||
if (event->content()) {
|
if (event->content()) {
|
||||||
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
|
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
# 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
|
|
||||||
)
|
|
||||||
@@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#include "chatbarcache.h"
|
#include "chatbarcache.h"
|
||||||
|
|
||||||
#include <Quotient/roommember.h>
|
|
||||||
|
|
||||||
#include "chatdocumenthandler.h"
|
#include "chatdocumenthandler.h"
|
||||||
#include "eventhandler.h"
|
#include "eventhandler.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
@@ -86,7 +84,7 @@ void ChatBarCache::setEditId(const QString &editId)
|
|||||||
Q_EMIT attachmentPathChanged();
|
Q_EMIT attachmentPathChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Quotient::RoomMember ChatBarCache::relationUser() const
|
QVariantMap ChatBarCache::relationUser() const
|
||||||
{
|
{
|
||||||
if (parent() == nullptr) {
|
if (parent() == nullptr) {
|
||||||
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
|
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
|
||||||
@@ -98,9 +96,9 @@ Quotient::RoomMember ChatBarCache::relationUser() const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (m_relationId.isEmpty()) {
|
if (m_relationId.isEmpty()) {
|
||||||
return room->member(QString());
|
return room->getUser(nullptr);
|
||||||
}
|
}
|
||||||
return room->member((*room->findInTimeline(m_relationId))->senderId());
|
return room->getUser(room->user((*room->findInTimeline(m_relationId))->senderId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ChatBarCache::relationMessage() const
|
QString ChatBarCache::relationMessage() const
|
||||||
|
|||||||
@@ -10,12 +10,6 @@
|
|||||||
|
|
||||||
class ChatDocumentHandler;
|
class ChatDocumentHandler;
|
||||||
|
|
||||||
namespace Quotient
|
|
||||||
{
|
|
||||||
class RoomMember;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Defines a user mention in the current chat or edit text.
|
* @brief Defines a user mention in the current chat or edit text.
|
||||||
*/
|
*/
|
||||||
@@ -94,13 +88,26 @@ class ChatBarCache : public QObject
|
|||||||
Q_PROPERTY(QString editId READ editId WRITE setEditId NOTIFY relationIdChanged)
|
Q_PROPERTY(QString editId READ editId WRITE setEditId NOTIFY relationIdChanged)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the RoomMember object for the message being replied to.
|
* @brief Get the user for the message being replied to.
|
||||||
*
|
*
|
||||||
* Returns an empty RoomMember if not replying to a message.
|
* 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.
|
||||||
*
|
*
|
||||||
* @sa Quotient::RoomMember
|
* 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
|
||||||
*/
|
*/
|
||||||
Q_PROPERTY(Quotient::RoomMember relationUser READ relationUser NOTIFY relationIdChanged)
|
Q_PROPERTY(QVariantMap relationUser READ relationUser NOTIFY relationIdChanged)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The content of the related message.
|
* @brief The content of the related message.
|
||||||
@@ -154,7 +161,7 @@ public:
|
|||||||
QString editId() const;
|
QString editId() const;
|
||||||
void setEditId(const QString &editId);
|
void setEditId(const QString &editId);
|
||||||
|
|
||||||
Quotient::RoomMember relationUser() const;
|
QVariantMap relationUser() const;
|
||||||
|
|
||||||
QString relationMessage() const;
|
QString relationMessage() const;
|
||||||
|
|
||||||
|
|||||||
@@ -9,20 +9,27 @@
|
|||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
#include <QNetworkProxy>
|
||||||
|
#include <QQuickTextDocument>
|
||||||
|
#include <QQuickWindow>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QStringBuilder>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include <Quotient/accountregistry.h>
|
#include <Quotient/accountregistry.h>
|
||||||
|
#include <Quotient/csapi/logout.h>
|
||||||
#include <Quotient/csapi/notifications.h>
|
#include <Quotient/csapi/notifications.h>
|
||||||
|
#include <Quotient/eventstats.h>
|
||||||
#include <Quotient/qt_connection_util.h>
|
#include <Quotient/qt_connection_util.h>
|
||||||
#include <Quotient/settings.h>
|
|
||||||
|
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
#include "neochatconnection.h"
|
#include "neochatconnection.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "notificationsmanager.h"
|
#include "notificationsmanager.h"
|
||||||
#include "proxycontroller.h"
|
#include "proxycontroller.h"
|
||||||
|
#include "roommanager.h"
|
||||||
|
|
||||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||||
#include "trayicon.h"
|
#include "trayicon.h"
|
||||||
@@ -38,10 +45,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_KUNIFIEDPUSH
|
|
||||||
#include <kunifiedpush/connector.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool testMode = false;
|
bool testMode = false;
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -186,7 +189,7 @@ void Controller::invokeLogin()
|
|||||||
m_accountsLoading += accountId;
|
m_accountsLoading += accountId;
|
||||||
Q_EMIT accountsLoadingChanged();
|
Q_EMIT accountsLoadingChanged();
|
||||||
if (!account.homeserver().isEmpty()) {
|
if (!account.homeserver().isEmpty()) {
|
||||||
auto accessTokenLoadingJob = loadAccessTokenFromKeyChain(account.userId());
|
auto accessTokenLoadingJob = loadAccessTokenFromKeyChain(account);
|
||||||
connect(accessTokenLoadingJob, &QKeychain::Job::finished, this, [accountId, this, accessTokenLoadingJob](QKeychain::Job *) {
|
connect(accessTokenLoadingJob, &QKeychain::Job::finished, this, [accountId, this, accessTokenLoadingJob](QKeychain::Job *) {
|
||||||
AccountSettings account{accountId};
|
AccountSettings account{accountId};
|
||||||
QString accessToken;
|
QString accessToken;
|
||||||
@@ -214,11 +217,11 @@ void Controller::invokeLogin()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const QString &userId)
|
QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const AccountSettings &account)
|
||||||
{
|
{
|
||||||
qDebug() << "Reading access token from the keychain for" << userId;
|
qDebug() << "Reading access token from the keychain for" << account.userId();
|
||||||
auto job = new QKeychain::ReadPasswordJob(qAppName(), this);
|
auto job = new QKeychain::ReadPasswordJob(qAppName(), this);
|
||||||
job->setKey(userId);
|
job->setKey(account.userId());
|
||||||
|
|
||||||
// Handling of errors
|
// Handling of errors
|
||||||
connect(job, &QKeychain::Job::finished, this, [this, job]() {
|
connect(job, &QKeychain::Job::finished, this, [this, job]() {
|
||||||
@@ -249,12 +252,12 @@ QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const QStrin
|
|||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::saveAccessTokenToKeyChain(const QString &userId, const QByteArray &accessToken)
|
bool Controller::saveAccessTokenToKeyChain(const AccountSettings &account, const QByteArray &accessToken)
|
||||||
{
|
{
|
||||||
qDebug() << "Save the access token to the keychain for " << userId;
|
qDebug() << "Save the access token to the keychain for " << account.userId();
|
||||||
QKeychain::WritePasswordJob job(qAppName());
|
QKeychain::WritePasswordJob job(qAppName());
|
||||||
job.setAutoDelete(false);
|
job.setAutoDelete(false);
|
||||||
job.setKey(userId);
|
job.setKey(account.userId());
|
||||||
job.setBinaryData(accessToken);
|
job.setBinaryData(accessToken);
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
QKeychain::WritePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
|
QKeychain::WritePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
|
||||||
@@ -406,3 +409,12 @@ void Controller::removeConnection(const QString &userId)
|
|||||||
SettingsGroup("Accounts"_ls).remove(userId);
|
SettingsGroup("Accounts"_ls).remove(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Controller::ssssSupported() const
|
||||||
|
{
|
||||||
|
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,9 +5,15 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
#include <QQuickItem>
|
||||||
|
|
||||||
#include "neochatconnection.h"
|
#include "neochatconnection.h"
|
||||||
#include <Quotient/accountregistry.h>
|
#include <Quotient/accountregistry.h>
|
||||||
|
#include <Quotient/settings.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_KUNIFIEDPUSH
|
||||||
|
#include <kunifiedpush/connector.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
class TrayIcon;
|
class TrayIcon;
|
||||||
class QQuickTextDocument;
|
class QQuickTextDocument;
|
||||||
@@ -50,6 +56,8 @@ class Controller : public QObject
|
|||||||
|
|
||||||
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
|
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(bool ssssSupported READ ssssSupported CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Controller &instance();
|
static Controller &instance();
|
||||||
static Controller *create(QQmlEngine *engine, QJSEngine *)
|
static Controller *create(QQmlEngine *engine, QJSEngine *)
|
||||||
@@ -74,7 +82,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Save an access token to the keychain for the given account.
|
* @brief Save an access token to the keychain for the given account.
|
||||||
*/
|
*/
|
||||||
bool saveAccessTokenToKeyChain(const QString &userId, const QByteArray &accessToken);
|
bool saveAccessTokenToKeyChain(const Quotient::AccountSettings &account, const QByteArray &accessToken);
|
||||||
|
|
||||||
[[nodiscard]] bool supportSystemTray() const;
|
[[nodiscard]] bool supportSystemTray() const;
|
||||||
|
|
||||||
@@ -94,13 +102,15 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE void removeConnection(const QString &userId);
|
Q_INVOKABLE void removeConnection(const QString &userId);
|
||||||
|
|
||||||
|
bool ssssSupported() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Controller(QObject *parent = nullptr);
|
explicit Controller(QObject *parent = nullptr);
|
||||||
|
|
||||||
QPointer<NeoChatConnection> m_connection;
|
QPointer<NeoChatConnection> m_connection;
|
||||||
TrayIcon *m_trayIcon = nullptr;
|
TrayIcon *m_trayIcon = nullptr;
|
||||||
|
|
||||||
QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const QString &account);
|
QKeychain::ReadPasswordJob *loadAccessTokenFromKeyChain(const Quotient::AccountSettings &account);
|
||||||
|
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void saveSettings() const;
|
void saveSettings() const;
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ FormCard.FormCardPage {
|
|||||||
implicitWidth: tabBar.tabWidth
|
implicitWidth: tabBar.tabWidth
|
||||||
}
|
}
|
||||||
QQC2.TabButton {
|
QQC2.TabButton {
|
||||||
text: i18nc("@title:tab", "Room Data")
|
text: qsTr("Room Data")
|
||||||
|
|
||||||
implicitWidth: tabBar.tabWidth
|
implicitWidth: tabBar.tabWidth
|
||||||
}
|
}
|
||||||
QQC2.TabButton {
|
QQC2.TabButton {
|
||||||
text: i18nc("@title:tab", "Server Info")
|
text: qsTr("Server Info")
|
||||||
|
|
||||||
implicitWidth: tabBar.tabWidth
|
implicitWidth: tabBar.tabWidth
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,14 +28,5 @@ FormCard.FormCardPage {
|
|||||||
|
|
||||||
onToggled: Config.secretBackup = checked
|
onToggled: Config.secretBackup = checked
|
||||||
}
|
}
|
||||||
FormCard.FormCheckDelegate {
|
|
||||||
text: i18nc("@option:check Enable the matrix feature to add a phone number as a third party ID", "Add phone numbers as 3PIDs")
|
|
||||||
checked: Config.phone3PId
|
|
||||||
|
|
||||||
onToggled: {
|
|
||||||
Config.phone3PId = checked
|
|
||||||
Config.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,11 +47,11 @@ public:
|
|||||||
LiveLocation, /**< The initial event of a shared live location (i.e., the place where this is supposed to be shown in the timeline). */
|
LiveLocation, /**< The initial event of a shared live location (i.e., the place where this is supposed to be shown in the timeline). */
|
||||||
Encrypted, /**< An encrypted message that cannot be decrypted. */
|
Encrypted, /**< An encrypted message that cannot be decrypted. */
|
||||||
Reply, /**< A component to show a replied-to message. */
|
Reply, /**< A component to show a replied-to message. */
|
||||||
|
ReplyLoad, /**< A loading dialog for a reply. */
|
||||||
LinkPreview, /**< A preview of a URL in the message. */
|
LinkPreview, /**< A preview of a URL in the message. */
|
||||||
LinkPreviewLoad, /**< A loading dialog for a link preview. */
|
LinkPreviewLoad, /**< A loading dialog for a link preview. */
|
||||||
Edit, /**< A text edit for editing a message. */
|
Edit, /**< A text edit for editing a message. */
|
||||||
Verification, /**< A user verification session start message. */
|
Verification, /**< A user verification session start message. */
|
||||||
Loading, /**< The component is loading. */
|
|
||||||
Other, /**< Anything that cannot be classified as another type. */
|
Other, /**< Anything that cannot be classified as another type. */
|
||||||
};
|
};
|
||||||
Q_ENUM(Type);
|
Q_ENUM(Type);
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#include "powerlevel.h"
|
|
||||||
|
|
||||||
QString PowerLevel::nameForLevel(Level level)
|
|
||||||
{
|
|
||||||
switch (level) {
|
|
||||||
case PowerLevel::Member:
|
|
||||||
return i18n("Member");
|
|
||||||
case PowerLevel::Moderator:
|
|
||||||
return i18n("Moderator");
|
|
||||||
case PowerLevel::Admin:
|
|
||||||
return i18n("Admin");
|
|
||||||
case PowerLevel::Mute:
|
|
||||||
return i18n("Mute");
|
|
||||||
case PowerLevel::Custom:
|
|
||||||
return i18n("Custom");
|
|
||||||
default:
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int PowerLevel::valueForLevel(Level level)
|
|
||||||
{
|
|
||||||
switch (level) {
|
|
||||||
case PowerLevel::Member:
|
|
||||||
return 0;
|
|
||||||
case PowerLevel::Moderator:
|
|
||||||
return 50;
|
|
||||||
case PowerLevel::Admin:
|
|
||||||
return 100;
|
|
||||||
case PowerLevel::Mute:
|
|
||||||
return -1;
|
|
||||||
default:
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PowerLevel::Level PowerLevel::levelForValue(int value)
|
|
||||||
{
|
|
||||||
switch (value) {
|
|
||||||
case 0:
|
|
||||||
return PowerLevel::Member;
|
|
||||||
case 50:
|
|
||||||
return PowerLevel::Moderator;
|
|
||||||
case 100:
|
|
||||||
return PowerLevel::Admin;
|
|
||||||
case -1:
|
|
||||||
return PowerLevel::Mute;
|
|
||||||
default:
|
|
||||||
return PowerLevel::Custom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PowerLevelModel::PowerLevelModel(QObject *parent)
|
|
||||||
: QAbstractListModel(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PowerLevelModel::showMute() const
|
|
||||||
{
|
|
||||||
return m_showMute;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PowerLevelModel::setShowMute(bool showMute)
|
|
||||||
{
|
|
||||||
if (showMute == m_showMute) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_showMute = showMute;
|
|
||||||
Q_EMIT showMuteChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant PowerLevelModel::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (index.row() >= rowCount()) {
|
|
||||||
qDebug() << "PowerLevelModel, something's wrong: index.row() >= m_rules.count()";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto level = static_cast<PowerLevel::Level>(index.row());
|
|
||||||
if (role == NameRole) {
|
|
||||||
return i18nc("%1 is the name of the power level, e.g. admin and %2 is the value that represents.",
|
|
||||||
"%1 (%2)",
|
|
||||||
PowerLevel::nameForLevel(level),
|
|
||||||
PowerLevel::valueForLevel(level));
|
|
||||||
}
|
|
||||||
if (role == ValueRole) {
|
|
||||||
return PowerLevel::valueForLevel(level);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
int PowerLevelModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(parent)
|
|
||||||
return PowerLevel::NUMLevels - (m_showMute ? 0 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> PowerLevelModel::roleNames() const
|
|
||||||
{
|
|
||||||
return {{NameRole, "name"}, {ValueRole, "value"}};
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_powerlevel.cpp"
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QQmlEngine>
|
|
||||||
|
|
||||||
#include <KLocalizedString>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class PowerLevel
|
|
||||||
*
|
|
||||||
* This class is designed to define the PowerLevel enumeration.
|
|
||||||
*/
|
|
||||||
class PowerLevel : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
QML_ELEMENT
|
|
||||||
QML_UNCREATABLE("")
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief The type of delegate that is needed for the event.
|
|
||||||
*
|
|
||||||
* @note While similar this is not the matrix event or message type. This is
|
|
||||||
* to tell a QML ListView what delegate to show for each event. So while
|
|
||||||
* similar to the spec it is not the same.
|
|
||||||
*/
|
|
||||||
enum Level {
|
|
||||||
Member, /**< A basic member. */
|
|
||||||
Moderator, /**< A moderator with enhanced powers. */
|
|
||||||
Admin, /**< The highest power level in the room. */
|
|
||||||
Mute, /**< The level to remove posting privileges. */
|
|
||||||
NUMLevels,
|
|
||||||
Custom, /**< A non-standard value. Intentionally after NUMLevels so it doesn't appear in the model. */
|
|
||||||
};
|
|
||||||
Q_ENUM(Level);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return a string representation of the enum value.
|
|
||||||
*/
|
|
||||||
static QString nameForLevel(Level level);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the integer representation of the enum value.
|
|
||||||
*/
|
|
||||||
static int valueForLevel(Level level);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the enum value for the given integer power level.
|
|
||||||
*/
|
|
||||||
static Level levelForValue(int value);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class PowerLevelModel
|
|
||||||
*
|
|
||||||
* A model visualize the allowed power levels.
|
|
||||||
*/
|
|
||||||
class PowerLevelModel : public QAbstractListModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
QML_ELEMENT
|
|
||||||
|
|
||||||
Q_PROPERTY(bool showMute READ showMute WRITE setShowMute NOTIFY showMuteChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Defines the model roles.
|
|
||||||
*/
|
|
||||||
enum Roles {
|
|
||||||
NameRole = Qt::DisplayRole, /**< The power level name. */
|
|
||||||
ValueRole, /**< The power level value. */
|
|
||||||
};
|
|
||||||
Q_ENUM(Roles)
|
|
||||||
|
|
||||||
explicit PowerLevelModel(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
[[nodiscard]] bool showMute() const;
|
|
||||||
void setShowMute(bool showMute);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the given role value at the given index.
|
|
||||||
*
|
|
||||||
* @sa QAbstractItemModel::data
|
|
||||||
*/
|
|
||||||
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of rows in the model.
|
|
||||||
*
|
|
||||||
* @sa QAbstractItemModel::rowCount
|
|
||||||
*/
|
|
||||||
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a mapping from Role enum values to role names.
|
|
||||||
*
|
|
||||||
* @sa Roles, QAbstractItemModel::roleNames()
|
|
||||||
*/
|
|
||||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void showMuteChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_showMute = true;
|
|
||||||
};
|
|
||||||
@@ -19,11 +19,11 @@
|
|||||||
#include <Quotient/events/simplestateevents.h>
|
#include <Quotient/events/simplestateevents.h>
|
||||||
#include <Quotient/events/stickerevent.h>
|
#include <Quotient/events/stickerevent.h>
|
||||||
#include <Quotient/quotient_common.h>
|
#include <Quotient/quotient_common.h>
|
||||||
#include <Quotient/roommember.h>
|
|
||||||
|
|
||||||
#include "eventhandler_logging.h"
|
#include "eventhandler_logging.h"
|
||||||
#include "events/locationbeaconevent.h"
|
#include "events/locationbeaconevent.h"
|
||||||
#include "events/pollevent.h"
|
#include "events/pollevent.h"
|
||||||
|
#include "events/serveraclevent.h"
|
||||||
#include "events/widgetevent.h"
|
#include "events/widgetevent.h"
|
||||||
#include "linkpreviewer.h"
|
#include "linkpreviewer.h"
|
||||||
#include "messagecomponenttype.h"
|
#include "messagecomponenttype.h"
|
||||||
@@ -61,18 +61,20 @@ MessageComponentType::Type EventHandler::messageComponentType() const
|
|||||||
return MessageComponentType::typeForEvent(*m_event);
|
return MessageComponentType::typeForEvent(*m_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
Quotient::RoomMember EventHandler::getAuthor(bool isPending) const
|
QVariantMap EventHandler::getAuthor(bool isPending) const
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (m_room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getAuthor called with m_room set to nullptr.";
|
qCWarning(EventHandling) << "getAuthor called with m_room set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
// If we have a room we can return an empty user by handing nullptr to m_room->getUser.
|
||||||
if (m_event == nullptr) {
|
if (m_event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getAuthor called with m_event set to nullptr. Returning empty user.";
|
qCWarning(EventHandling) << "getAuthor called with m_event set to nullptr. Returning empty user.";
|
||||||
return {};
|
return m_room->getUser(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return isPending ? m_room->localMember() : m_room->member(m_event->senderId());
|
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
||||||
|
return m_room->getUser(author);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getAuthorDisplayName(bool isPending) const
|
QString EventHandler::getAuthorDisplayName(bool isPending) const
|
||||||
@@ -94,8 +96,8 @@ QString EventHandler::getAuthorDisplayName(bool isPending) const
|
|||||||
}
|
}
|
||||||
return previousDisplayName;
|
return previousDisplayName;
|
||||||
} else {
|
} else {
|
||||||
const auto author = isPending ? m_room->localMember() : m_room->member(m_event->senderId());
|
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
||||||
return author.htmlSafeDisplayName();
|
return m_room->htmlSafeMemberName(author->id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,8 +112,8 @@ QString EventHandler::singleLineAuthorDisplayname(bool isPending) const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto author = isPending ? m_room->localMember() : m_room->member(m_event->senderId());
|
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
|
||||||
auto displayName = author.displayName();
|
auto displayName = m_room->safeMemberName(author->id());
|
||||||
displayName.replace(QStringLiteral("<br>\n"), QStringLiteral(" "));
|
displayName.replace(QStringLiteral("<br>\n"), QStringLiteral(" "));
|
||||||
displayName.replace(QStringLiteral("<br>"), QStringLiteral(" "));
|
displayName.replace(QStringLiteral("<br>"), QStringLiteral(" "));
|
||||||
displayName.replace(QStringLiteral("<br />\n"), QStringLiteral(" "));
|
displayName.replace(QStringLiteral("<br />\n"), QStringLiteral(" "));
|
||||||
@@ -218,7 +220,7 @@ bool EventHandler::isHidden()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_room->connection()->isIgnored(m_event->senderId())) {
|
if (m_room->connection()->isIgnored(m_room->user(m_event->senderId()))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +255,7 @@ QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
|
|||||||
|
|
||||||
QString body;
|
QString body;
|
||||||
if (event.hasTextContent() && event.content()) {
|
if (event.hasTextContent() && event.content()) {
|
||||||
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
body = static_cast<const MessageEventContent::TextContent *>(event.content())->body;
|
||||||
} else {
|
} else {
|
||||||
body = event.plainBody();
|
body = event.plainBody();
|
||||||
}
|
}
|
||||||
@@ -291,10 +293,7 @@ QString EventHandler::getMarkdownBody() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto roomMessageEvent = eventCast<const RoomMessageEvent>(m_event);
|
const auto roomMessageEvent = eventCast<const RoomMessageEvent>(m_event);
|
||||||
|
return roomMessageEvent->plainBody();
|
||||||
QString plainBody = roomMessageEvent->plainBody();
|
|
||||||
plainBody.remove(TextRegex::removeReply);
|
|
||||||
return plainBody;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines) const
|
QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat format, bool stripNewlines) const
|
||||||
@@ -316,7 +315,7 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
|||||||
},
|
},
|
||||||
[this, prettyPrint](const RoomMemberEvent &e) {
|
[this, prettyPrint](const RoomMemberEvent &e) {
|
||||||
// FIXME: Rewind to the name that was at the time of this event
|
// FIXME: Rewind to the name that was at the time of this event
|
||||||
auto subjectName = m_room->member(e.userId()).htmlSafeDisplayName();
|
auto subjectName = m_room->htmlSafeMemberName(e.userId());
|
||||||
if (e.membership() == Membership::Leave) {
|
if (e.membership() == Membership::Leave) {
|
||||||
if (e.prevContent() && e.prevContent()->displayName) {
|
if (e.prevContent() && e.prevContent()->displayName) {
|
||||||
subjectName = sanitized(*e.prevContent()->displayName).toHtmlEscaped();
|
subjectName = sanitized(*e.prevContent()->displayName).toHtmlEscaped();
|
||||||
@@ -324,8 +323,7 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prettyPrint) {
|
if (prettyPrint) {
|
||||||
subjectName = QStringLiteral("<a href=\"https://matrix.to/#/%1\" style=\"color: %2\">%3</a>")
|
subjectName = QStringLiteral("<a href=\"https://matrix.to/#/%1\">%2</a>").arg(e.userId(), subjectName);
|
||||||
.arg(e.userId(), m_room->member(e.userId()).color().name(), subjectName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The below code assumes senderName output in AuthorRole
|
// The below code assumes senderName output in AuthorRole
|
||||||
@@ -439,7 +437,7 @@ QString EventHandler::getBody(const Quotient::RoomEvent *event, Qt::TextFormat f
|
|||||||
[](const LocationBeaconEvent &e) {
|
[](const LocationBeaconEvent &e) {
|
||||||
return e.contentJson()["description"_ls].toString();
|
return e.contentJson()["description"_ls].toString();
|
||||||
},
|
},
|
||||||
[](const RoomServerAclEvent &) {
|
[](const ServerAclEvent &) {
|
||||||
return i18n("changed the server access control lists for this room");
|
return i18n("changed the server access control lists for this room");
|
||||||
},
|
},
|
||||||
[](const WidgetEvent &e) {
|
[](const WidgetEvent &e) {
|
||||||
@@ -478,7 +476,7 @@ QString EventHandler::getMessageBody(const RoomMessageEvent &event, Qt::TextForm
|
|||||||
|
|
||||||
QString body;
|
QString body;
|
||||||
if (event.hasTextContent() && event.content()) {
|
if (event.hasTextContent() && event.content()) {
|
||||||
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
body = static_cast<const MessageEventContent::TextContent *>(event.content())->body;
|
||||||
} else {
|
} else {
|
||||||
body = event.plainBody();
|
body = event.plainBody();
|
||||||
}
|
}
|
||||||
@@ -608,7 +606,7 @@ QString EventHandler::getGenericBody() const
|
|||||||
[](const LocationBeaconEvent &) {
|
[](const LocationBeaconEvent &) {
|
||||||
return i18n("sent a live location beacon");
|
return i18n("sent a live location beacon");
|
||||||
},
|
},
|
||||||
[](const RoomServerAclEvent &) {
|
[](const ServerAclEvent &) {
|
||||||
return i18n("changed the server access control lists for this room");
|
return i18n("changed the server access control lists for this room");
|
||||||
},
|
},
|
||||||
[](const WidgetEvent &e) {
|
[](const WidgetEvent &e) {
|
||||||
@@ -799,21 +797,25 @@ MessageComponentType::Type EventHandler::replyMessageComponentType() const
|
|||||||
return MessageComponentType::typeForEvent(*replyEvent);
|
return MessageComponentType::typeForEvent(*replyEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Quotient::RoomMember EventHandler::getReplyAuthor() const
|
QVariantMap EventHandler::getReplyAuthor() const
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (m_room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getReplyAuthor called with m_room set to nullptr.";
|
qCWarning(EventHandling) << "getReplyAuthor called with m_room set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
// If we have a room we can return an empty user by handing nullptr to m_room->getUser.
|
||||||
if (m_event == nullptr) {
|
if (m_event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getReplyAuthor called with m_event set to nullptr. Returning empty user.";
|
qCWarning(EventHandling) << "getReplyAuthor called with m_event set to nullptr. Returning empty user.";
|
||||||
return {};
|
return m_room->getUser(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto replyPtr = m_room->getReplyForEvent(*m_event)) {
|
auto replyPtr = m_room->getReplyForEvent(*m_event);
|
||||||
return m_room->member(replyPtr->senderId());
|
|
||||||
|
if (replyPtr) {
|
||||||
|
auto replyUser = m_room->user(replyPtr->senderId());
|
||||||
|
return m_room->getUser(replyUser);
|
||||||
} else {
|
} else {
|
||||||
return m_room->member(QString());
|
return m_room->getUser(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -961,11 +963,11 @@ bool EventHandler::hasReadMarkers() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||||
userIds.remove(m_room->localMember().id());
|
userIds.remove(m_room->localUser()->id());
|
||||||
return userIds.size() > 0;
|
return userIds.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Quotient::RoomMember> EventHandler::getReadMarkers(int maxMarkers) const
|
QVariantList EventHandler::getReadMarkers(int maxMarkers) const
|
||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (m_room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getReadMarkers called with m_room set to nullptr.";
|
qCWarning(EventHandling) << "getReadMarkers called with m_room set to nullptr.";
|
||||||
@@ -977,17 +979,18 @@ QList<Quotient::RoomMember> EventHandler::getReadMarkers(int maxMarkers) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto userIds_temp = m_room->userIdsAtEvent(m_event->id());
|
auto userIds_temp = m_room->userIdsAtEvent(m_event->id());
|
||||||
userIds_temp.remove(m_room->localMember().id());
|
userIds_temp.remove(m_room->localUser()->id());
|
||||||
|
|
||||||
auto userIds = userIds_temp.values();
|
auto userIds = userIds_temp.values();
|
||||||
if (userIds.count() > maxMarkers) {
|
if (userIds.count() > maxMarkers) {
|
||||||
userIds = userIds.mid(0, maxMarkers);
|
userIds = userIds.mid(0, maxMarkers);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Quotient::RoomMember> users;
|
QVariantList users;
|
||||||
users.reserve(userIds.size());
|
users.reserve(userIds.size());
|
||||||
for (const auto &userId : userIds) {
|
for (const auto &userId : userIds) {
|
||||||
users += m_room->member(userId);
|
auto user = m_room->user(userId);
|
||||||
|
users += m_room->getUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
return users;
|
return users;
|
||||||
@@ -1005,7 +1008,7 @@ QString EventHandler::getNumberExcessReadMarkers(int maxMarkers) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||||
userIds.remove(m_room->localMember().id());
|
userIds.remove(m_room->localUser()->id());
|
||||||
|
|
||||||
if (userIds.count() > maxMarkers) {
|
if (userIds.count() > maxMarkers) {
|
||||||
return QStringLiteral("+ ") + QString::number(userIds.count() - maxMarkers);
|
return QStringLiteral("+ ") + QString::number(userIds.count() - maxMarkers);
|
||||||
@@ -1026,7 +1029,7 @@ QString EventHandler::getReadMarkersString() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||||
userIds.remove(m_room->localMember().id());
|
userIds.remove(m_room->localUser()->id());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The string ends up in the form
|
* The string ends up in the form
|
||||||
@@ -1034,12 +1037,10 @@ QString EventHandler::getReadMarkersString() const
|
|||||||
*/
|
*/
|
||||||
QString readMarkersString = i18np("1 user: ", "%1 users: ", userIds.size());
|
QString readMarkersString = i18np("1 user: ", "%1 users: ", userIds.size());
|
||||||
for (const auto &userId : userIds) {
|
for (const auto &userId : userIds) {
|
||||||
auto member = m_room->member(userId);
|
auto user = m_room->user(userId);
|
||||||
QString displayName;
|
auto displayName = user->displayname(m_room);
|
||||||
if (member.isEmpty()) {
|
if (displayName.isEmpty()) {
|
||||||
displayName = i18nc("A member who is not in the room has been requested.", "unknown member");
|
displayName = userId;
|
||||||
} else {
|
|
||||||
displayName = member.displayName();
|
|
||||||
}
|
}
|
||||||
readMarkersString += displayName + i18nc("list separator", ", ");
|
readMarkersString += displayName + i18nc("list separator", ", ");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,6 @@
|
|||||||
|
|
||||||
#include "enums/messagecomponenttype.h"
|
#include "enums/messagecomponenttype.h"
|
||||||
|
|
||||||
namespace Quotient
|
|
||||||
{
|
|
||||||
class RoomMember;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LinkPreviewer;
|
class LinkPreviewer;
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
class ReactionModel;
|
class ReactionModel;
|
||||||
@@ -56,17 +51,30 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Get the author of the event in context of the room.
|
* @brief Get the author of the event in context of the room.
|
||||||
*
|
*
|
||||||
* An empty Quotient::RoomMember will be returned if the EventHandler hasn't had
|
* This is different to getting a Quotient::User object
|
||||||
* the room or event initialised.
|
* as neither of those can provide details like the displayName or avatarMediaId
|
||||||
|
* without the room context as these can vary from room to room. This function
|
||||||
|
* uses the room context and outputs the result as QVariantMap.
|
||||||
|
*
|
||||||
|
* An empty QVariantMap will be returned if the EventHandler hasn't had the room
|
||||||
|
* intialised. An empty user (i.e. a QVariantMap with all the correct keys
|
||||||
|
* but empty values) will be returned if the room has been set but not an event.
|
||||||
*
|
*
|
||||||
* @param isPending if the event is pending, i.e. has not been confirmed by
|
* @param isPending if the event is pending, i.e. has not been confirmed by
|
||||||
* the server.
|
* the server.
|
||||||
*
|
*
|
||||||
* @return a Quotient::RoomMember object for the user.
|
* @return a QVariantMap for the user with the following properties:
|
||||||
|
* - isLocalUser - Whether the user is the local user.
|
||||||
|
* - id - The matrix ID of the user.
|
||||||
|
* - displayName - Display name in the context of this room.
|
||||||
|
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
||||||
|
* - avatarMediaId - Avatar id in the context of this room.
|
||||||
|
* - color - Color for the user.
|
||||||
|
* - object - The Quotient::User object for the user.
|
||||||
*
|
*
|
||||||
* @sa Quotient::RoomMember
|
* @sa Quotient::User
|
||||||
*/
|
*/
|
||||||
Quotient::RoomMember getAuthor(bool isPending = false) const;
|
QVariantMap getAuthor(bool isPending = false) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the display name of the event author.
|
* @brief Get the display name of the event author.
|
||||||
@@ -243,17 +251,27 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Get the author of the event replied to in context of the room.
|
* @brief Get the author of the event replied to in context of the room.
|
||||||
*
|
*
|
||||||
* An empty Quotient::RoomMember will be returned if the EventHandler hasn't had
|
* This is different to getting a Quotient::User object
|
||||||
* the room or event initialised.
|
* 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.
|
||||||
*
|
*
|
||||||
* @param isPending if the event is pending, i.e. has not been confirmed by
|
* An empty QVariantMap will be returned if the EventHandler hasn't had the room
|
||||||
* the server.
|
* 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.
|
||||||
*
|
*
|
||||||
* @return a Quotient::RoomMember object for the user.
|
* @return a QVariantMap for the user with the following properties:
|
||||||
|
* - isLocalUser - Whether the user is the local user.
|
||||||
|
* - id - The matrix ID of the user.
|
||||||
|
* - displayName - Display name in the context of this room.
|
||||||
|
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
||||||
|
* - avatarMediaId - Avatar id in the context of this room.
|
||||||
|
* - color - Color for the user.
|
||||||
|
* - object - The Quotient::User object for the user.
|
||||||
*
|
*
|
||||||
* @sa Quotient::RoomMember
|
* @sa Quotient::User
|
||||||
*/
|
*/
|
||||||
Quotient::RoomMember getReplyAuthor() const;
|
QVariantMap getReplyAuthor() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Output a string for the message content of the event replied to ready
|
* @brief Output a string for the message content of the event replied to ready
|
||||||
@@ -357,7 +375,7 @@ public:
|
|||||||
* the number of users shown plus the excess number will be
|
* the number of users shown plus the excess number will be
|
||||||
* the total number of other user read markers at an event.
|
* the total number of other user read markers at an event.
|
||||||
*/
|
*/
|
||||||
QList<Quotient::RoomMember> getReadMarkers(int maxMarkers = 5) const;
|
QVariantList getReadMarkers(int maxMarkers = 5) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the number of excess user read markers for the event.
|
* @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"))) {
|
if (json.contains(QStringLiteral("pack"))) {
|
||||||
pack = ImagePackEventContent::Pack{
|
pack = ImagePackEventContent::Pack{
|
||||||
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
|
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
|
||||||
fromJson<std::optional<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
|
fromJson<Omittable<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
|
||||||
fromJson<std::optional<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
|
fromJson<Omittable<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
|
||||||
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
pack = std::nullopt;
|
pack = none;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &keys = json["images"_ls].toObject().keys();
|
const auto &keys = json["images"_ls].toObject().keys();
|
||||||
for (const auto &k : keys) {
|
for (const auto &k : keys) {
|
||||||
std::optional<EventContent::ImageInfo> info;
|
Omittable<EventContent::ImageInfo> info;
|
||||||
if (json["images"_ls][k].toObject().contains(QStringLiteral("info"))) {
|
if (json["images"_ls][k].toObject().contains(QStringLiteral("info"))) {
|
||||||
info = EventContent::ImageInfo(QUrl(json["images"_ls][k]["url"_ls].toString()), json["images"_ls][k]["info"_ls].toObject(), k);
|
info = EventContent::ImageInfo(QUrl(json["images"_ls][k]["url"_ls].toString()), json["images"_ls][k]["info"_ls].toObject(), k);
|
||||||
} else {
|
} else {
|
||||||
info = std::nullopt;
|
info = none;
|
||||||
}
|
}
|
||||||
images += ImagePackImage{
|
images += ImagePackImage{
|
||||||
k,
|
k,
|
||||||
fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()),
|
fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()),
|
||||||
fromJson<std::optional<QString>>(json["images"_ls][k]["body"_ls]),
|
fromJson<Omittable<QString>>(json["images"_ls][k]["body"_ls]),
|
||||||
info,
|
info,
|
||||||
fromJson<std::optional<QStringList>>(json["images"_ls][k]["usage"_ls]),
|
fromJson<Omittable<QStringList>>(json["images"_ls][k]["usage"_ls]),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ public:
|
|||||||
* @brief Defines the properties of an image pack.
|
* @brief Defines the properties of an image pack.
|
||||||
*/
|
*/
|
||||||
struct Pack {
|
struct Pack {
|
||||||
std::optional<QString> displayName; /**< The display name of the pack. */
|
Quotient::Omittable<QString> displayName; /**< The display name of the pack. */
|
||||||
std::optional<QUrl> avatarUrl; /**< The source mxc URL for the pack avatar. */
|
Quotient::Omittable<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". */
|
Quotient::Omittable<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). */
|
Quotient::Omittable<QString> attribution; /**< The attribution for the pack author(s). */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,14 +38,14 @@ public:
|
|||||||
struct ImagePackImage {
|
struct ImagePackImage {
|
||||||
QString shortcode; /**< The shortcode for the image. */
|
QString shortcode; /**< The shortcode for the image. */
|
||||||
QUrl url; /**< The mxc URL for this image. */
|
QUrl url; /**< The mxc URL for this image. */
|
||||||
std::optional<QString> body; /**< An optional text body for this image. */
|
Quotient::Omittable<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. */
|
Quotient::Omittable<Quotient::EventContent::ImageInfo> info; /**< The ImageInfo object used for the info block of m.sticker events. */
|
||||||
/**
|
/**
|
||||||
* @brief An array of the usages for this image.
|
* @brief An array of the usages for this image.
|
||||||
*
|
*
|
||||||
* The possible values match those of the usage key of a pack object.
|
* The possible values match those of the usage key of a pack object.
|
||||||
*/
|
*/
|
||||||
std::optional<QStringList> usage;
|
Quotient::Omittable<QStringList> usage;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,7 +53,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @sa Pack
|
* @sa Pack
|
||||||
*/
|
*/
|
||||||
std::optional<Pack> pack;
|
Quotient::Omittable<Pack> pack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a vector of images in the pack.
|
* @brief Return a vector of images in the pack.
|
||||||
|
|||||||
14
src/events/serveraclevent.h
Normal file
14
src/events/serveraclevent.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Quotient/events/simplestateevents.h>
|
||||||
|
|
||||||
|
namespace Quotient
|
||||||
|
{
|
||||||
|
|
||||||
|
// Defined so we can directly switch on type.
|
||||||
|
DEFINE_SIMPLE_STATE_EVENT(ServerAclEvent, "m.room.server_acl", bool, allow_ip_literals, "allow_ip_literals")
|
||||||
|
|
||||||
|
} // namespace Quotient
|
||||||
@@ -14,15 +14,12 @@ Q_SCRIPTABLE RemoteActions FakeRunner::Actions()
|
|||||||
|
|
||||||
Q_SCRIPTABLE RemoteMatches FakeRunner::Match(const QString &searchTerm)
|
Q_SCRIPTABLE RemoteMatches FakeRunner::Match(const QString &searchTerm)
|
||||||
{
|
{
|
||||||
Q_UNUSED(searchTerm);
|
|
||||||
QCoreApplication::quit();
|
QCoreApplication::quit();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_SCRIPTABLE void FakeRunner::Run(const QString &id, const QString &actionId)
|
Q_SCRIPTABLE void FakeRunner::Run(const QString &id, const QString &actionId)
|
||||||
{
|
{
|
||||||
Q_UNUSED(id);
|
|
||||||
Q_UNUSED(actionId);
|
|
||||||
QCoreApplication::quit();
|
QCoreApplication::quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,4 +33,4 @@ FakeRunner::FakeRunner()
|
|||||||
qDBusRegisterMetaType<RemoteImage>();
|
qDBusRegisterMetaType<RemoteImage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_fakerunner.cpp"
|
#include "moc_fakerunner.cpp"
|
||||||
@@ -6,8 +6,10 @@
|
|||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
||||||
#include <Quotient/accountregistry.h>
|
#include <Quotient/accountregistry.h>
|
||||||
#include <Quotient/e2ee/sssshandler.h>
|
|
||||||
#include <Quotient/keyverificationsession.h>
|
#include <Quotient/keyverificationsession.h>
|
||||||
|
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||||
|
#include <Quotient/e2ee/sssshandler.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
@@ -45,8 +47,10 @@ struct ForeignKeyVerificationSession {
|
|||||||
QML_UNCREATABLE("")
|
QML_UNCREATABLE("")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||||
struct ForeignSSSSHandler {
|
struct ForeignSSSSHandler {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
QML_FOREIGN(Quotient::SSSSHandler)
|
QML_FOREIGN(Quotient::SSSSHandler)
|
||||||
QML_NAMED_ELEMENT(SSSSHandler)
|
QML_NAMED_ELEMENT(SSSSHandler)
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#include "identityserverhelper.h"
|
|
||||||
|
|
||||||
#include <QNetworkReply>
|
|
||||||
|
|
||||||
#include <KLocalizedString>
|
|
||||||
|
|
||||||
#include <Quotient/networkaccessmanager.h>
|
|
||||||
|
|
||||||
#include "neochatconnection.h"
|
|
||||||
|
|
||||||
IdentityServerHelper::IdentityServerHelper(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NeoChatConnection *IdentityServerHelper::connection() const
|
|
||||||
{
|
|
||||||
return m_connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IdentityServerHelper::setConnection(NeoChatConnection *connection)
|
|
||||||
{
|
|
||||||
if (m_connection == connection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_connection != nullptr) {
|
|
||||||
m_connection->disconnect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_connection = connection;
|
|
||||||
Q_EMIT connectionChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString IdentityServerHelper::url() const
|
|
||||||
{
|
|
||||||
return m_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IdentityServerHelper::setUrl(const QString &url)
|
|
||||||
{
|
|
||||||
if (url == m_url) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_url = url;
|
|
||||||
Q_EMIT urlChanged();
|
|
||||||
|
|
||||||
checkUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
IdentityServerHelper::IdServerStatus IdentityServerHelper::status() const
|
|
||||||
{
|
|
||||||
return m_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IdentityServerHelper::checkUrl()
|
|
||||||
{
|
|
||||||
if (m_idServerCheckRequest != nullptr) {
|
|
||||||
m_idServerCheckRequest->abort();
|
|
||||||
m_idServerCheckRequest.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_url == m_connection->identityServer().toString()) {
|
|
||||||
m_status = Match;
|
|
||||||
Q_EMIT statusChanged();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_url.isEmpty()) {
|
|
||||||
m_status = Valid;
|
|
||||||
Q_EMIT statusChanged();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto requestUrl = QUrl(m_url + QStringLiteral("/_matrix/identity/v2"));
|
|
||||||
if (!(requestUrl.scheme() == QStringLiteral("https") || requestUrl.scheme() == QStringLiteral("http"))) {
|
|
||||||
m_status = Invalid;
|
|
||||||
Q_EMIT statusChanged();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QNetworkRequest request(requestUrl);
|
|
||||||
m_idServerCheckRequest = Quotient::NetworkAccessManager::instance()->get(request);
|
|
||||||
connect(m_idServerCheckRequest, &QNetworkReply::finished, this, [this]() {
|
|
||||||
if (m_idServerCheckRequest->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200) {
|
|
||||||
m_status = Valid;
|
|
||||||
Q_EMIT statusChanged();
|
|
||||||
} else {
|
|
||||||
m_status = Invalid;
|
|
||||||
Q_EMIT statusChanged();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void IdentityServerHelper::setIdentityServer()
|
|
||||||
{
|
|
||||||
if (m_url == m_connection->identityServer().toString()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_connection->setAccountData(QLatin1String("m.identity_server"), {{QLatin1String("base_url"), m_url}});
|
|
||||||
m_status = Ready;
|
|
||||||
Q_EMIT statusChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IdentityServerHelper::clearIdentityServer()
|
|
||||||
{
|
|
||||||
if (m_connection->identityServer().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_connection->setAccountData(QLatin1String("m.identity_server"), {{QLatin1String("base_url"), QString()}});
|
|
||||||
m_status = Ready;
|
|
||||||
Q_EMIT statusChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_identityserverhelper.cpp"
|
|
||||||
@@ -1,88 +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 <QObject>
|
|
||||||
#include <QQmlEngine>
|
|
||||||
|
|
||||||
#include <Quotient/jobs/basejob.h>
|
|
||||||
|
|
||||||
class NeoChatConnection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class IdentityServerHelper
|
|
||||||
*
|
|
||||||
* This class is designed to help the process of setting an identity server for the account.
|
|
||||||
* It will manage the various stages of verification and authentication.
|
|
||||||
*/
|
|
||||||
class IdentityServerHelper : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
QML_ELEMENT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The connection to add a 3PID to.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The URL for the desired server.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The current status.
|
|
||||||
*/
|
|
||||||
Q_PROPERTY(IdServerStatus status READ status NOTIFY statusChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief The current status for adding an identity server
|
|
||||||
*/
|
|
||||||
enum IdServerStatus {
|
|
||||||
Ready, /**< The process is ready to start. I.e. there is no ongoing attempt to set a new server. */
|
|
||||||
Valid, /**< The server URL is valid. */
|
|
||||||
Invalid, /**< The server URL is invalid. */
|
|
||||||
Match, /**< The server URL is the one that is already configured. */
|
|
||||||
Other, /**< An unknown problem occurred. */
|
|
||||||
};
|
|
||||||
Q_ENUM(IdServerStatus)
|
|
||||||
|
|
||||||
explicit IdentityServerHelper(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
[[nodiscard]] NeoChatConnection *connection() const;
|
|
||||||
void setConnection(NeoChatConnection *connection);
|
|
||||||
|
|
||||||
[[nodiscard]] QString url() const;
|
|
||||||
void setUrl(const QString &url);
|
|
||||||
|
|
||||||
[[nodiscard]] IdServerStatus status() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the current URL as the user's identity server.
|
|
||||||
*
|
|
||||||
* Will do nothing if the URL isn't a valid identity server.
|
|
||||||
*/
|
|
||||||
Q_INVOKABLE void setIdentityServer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Clear the user's identity server.
|
|
||||||
*/
|
|
||||||
Q_INVOKABLE void clearIdentityServer();
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void connectionChanged();
|
|
||||||
void urlChanged();
|
|
||||||
void statusChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QPointer<NeoChatConnection> m_connection;
|
|
||||||
|
|
||||||
IdServerStatus m_status = Ready;
|
|
||||||
QString m_url;
|
|
||||||
|
|
||||||
QPointer<QNetworkReply> m_idServerCheckRequest;
|
|
||||||
|
|
||||||
void checkUrl();
|
|
||||||
};
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#include "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});
|
|
||||||
}
|
|
||||||
@@ -1,13 +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/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;
|
using namespace Quotient;
|
||||||
|
|
||||||
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth)
|
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Omittable<QJsonObject> &auth)
|
||||||
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), "/_matrix/client/r0/account/password")
|
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), "/_matrix/client/r0/account/password")
|
||||||
{
|
{
|
||||||
QJsonObject _data;
|
QJsonObject _data;
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
class NeochatChangePasswordJob : public Quotient::BaseJob
|
class NeochatChangePasswordJob : public Quotient::BaseJob
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth = std::nullopt);
|
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth)
|
NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const Omittable<QJsonObject> &auth)
|
||||||
: BaseJob(HttpVerb::Post, QStringLiteral("DisableDeviceJob"), "_matrix/client/v3/account/deactivate")
|
: BaseJob(HttpVerb::Post, QStringLiteral("DisableDeviceJob"), "_matrix/client/v3/account/deactivate")
|
||||||
{
|
{
|
||||||
QJsonObject data;
|
QJsonObject data;
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
class NeoChatDeactivateAccountJob : public Quotient::BaseJob
|
class NeoChatDeactivateAccountJob : public Quotient::BaseJob
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth = std::nullopt);
|
explicit NeoChatDeactivateAccountJob(const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth)
|
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Omittable<QJsonObject> &auth)
|
||||||
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId).toLatin1())
|
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId).toLatin1())
|
||||||
{
|
{
|
||||||
QJsonObject _data;
|
QJsonObject _data;
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
class NeochatDeleteDeviceJob : public Quotient::BaseJob
|
class NeochatDeleteDeviceJob : public Quotient::BaseJob
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth = std::nullopt);
|
explicit NeochatDeleteDeviceJob(const QString &deviceId, const Quotient::Omittable<QJsonObject> &auth = Quotient::none);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -89,23 +89,38 @@ bool LinkPreviewer::empty() const
|
|||||||
return m_url.isEmpty();
|
return m_url.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QUrl> LinkPreviewer::linkPreviews(QString string)
|
QUrl LinkPreviewer::linkPreview(const Quotient::RoomMessageEvent *event)
|
||||||
{
|
{
|
||||||
auto data = string.remove(TextRegex::removeRichReply);
|
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 linksMatch = TextRegex::url.globalMatch(data);
|
auto linksMatch = TextRegex::url.globalMatch(data);
|
||||||
QList<QUrl> links;
|
|
||||||
while (linksMatch.hasNext()) {
|
while (linksMatch.hasNext()) {
|
||||||
auto link = linksMatch.next().captured();
|
auto link = linksMatch.next().captured();
|
||||||
if (!link.contains(QStringLiteral("matrix.to")) && !links.contains(QUrl(link))) {
|
if (!link.contains(QStringLiteral("matrix.to"))) {
|
||||||
links += QUrl(link);
|
return QUrl(link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return links;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinkPreviewer::hasPreviewableLinks(const QString &string)
|
bool LinkPreviewer::hasPreviewableLinks(const Quotient::RoomMessageEvent *event)
|
||||||
{
|
{
|
||||||
return !linkPreviews(string).isEmpty();
|
return !linkPreview(event).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_linkpreviewer.cpp"
|
#include "moc_linkpreviewer.cpp"
|
||||||
|
|||||||
@@ -7,6 +7,11 @@
|
|||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
|
namespace Quotient
|
||||||
|
{
|
||||||
|
class RoomMessageEvent;
|
||||||
|
}
|
||||||
|
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,19 +71,19 @@ public:
|
|||||||
[[nodiscard]] bool empty() const;
|
[[nodiscard]] bool empty() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the given string has at least 1 pre-viewable link.
|
* @brief Whether the given event has at least 1 pre-viewable link.
|
||||||
*
|
*
|
||||||
* A link is only pre-viewable if it is http, https or something starting with www.
|
* A link is only pre-viewable if it is http, https or something starting with www.
|
||||||
*/
|
*/
|
||||||
static bool hasPreviewableLinks(const QString &string);
|
static bool hasPreviewableLinks(const Quotient::RoomMessageEvent *event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return previewable links from the given string.
|
* @brief Return the link to be previewed from the given event.
|
||||||
*
|
*
|
||||||
* This function is designed to give only links that should be previewed so
|
* 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.
|
* http, https or something starting with www. The first valid link is returned.
|
||||||
*/
|
*/
|
||||||
static QList<QUrl> linkPreviews(QString string);
|
static QUrl linkPreview(const Quotient::RoomMessageEvent *event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_loaded;
|
bool m_loaded;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include <Quotient/accountregistry.h>
|
#include <Quotient/accountregistry.h>
|
||||||
#include <Quotient/qt_connection_util.h>
|
#include <Quotient/qt_connection_util.h>
|
||||||
#include <Quotient/settings.h>
|
|
||||||
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
|
|
||||||
@@ -73,7 +72,7 @@ void LoginHelper::init()
|
|||||||
account.setHomeserver(m_connection->homeserver());
|
account.setHomeserver(m_connection->homeserver());
|
||||||
account.setDeviceId(m_connection->deviceId());
|
account.setDeviceId(m_connection->deviceId());
|
||||||
account.setDeviceName(m_deviceName);
|
account.setDeviceName(m_deviceName);
|
||||||
if (!Controller::instance().saveAccessTokenToKeyChain(account.userId(), m_connection->accessToken())) {
|
if (!Controller::instance().saveAccessTokenToKeyChain(account, m_connection->accessToken())) {
|
||||||
qWarning() << "Couldn't save access token";
|
qWarning() << "Couldn't save access token";
|
||||||
}
|
}
|
||||||
account.sync();
|
account.sync();
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QNetworkDiskCache>
|
#include <QNetworkDiskCache>
|
||||||
#include <QNetworkProxyFactory>
|
#include <QNetworkProxyFactory>
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
#include <QQuickStyle>
|
#include <QQuickStyle>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
#include <QtQml/QQmlExtensionPlugin>
|
#include <QtQml/QQmlExtensionPlugin>
|
||||||
#include <Quotient/connection.h>
|
|
||||||
|
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
@@ -48,10 +46,11 @@
|
|||||||
#include "colorschemer.h"
|
#include "colorschemer.h"
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include "matriximageprovider.h"
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
#include "roommanager.h"
|
#include "roommanager.h"
|
||||||
#include "sharehandler.h"
|
|
||||||
#include "windowcontroller.h"
|
#include "windowcontroller.h"
|
||||||
|
#include "sharehandler.h"
|
||||||
|
|
||||||
#ifdef HAVE_RUNNER
|
#ifdef HAVE_RUNNER
|
||||||
#include "runner.h"
|
#include "runner.h"
|
||||||
@@ -175,7 +174,6 @@ int main(int argc, char *argv[])
|
|||||||
initLogging();
|
initLogging();
|
||||||
|
|
||||||
Connection::setEncryptionDefault(true);
|
Connection::setEncryptionDefault(true);
|
||||||
Connection::setDirectChatEncryptionDefault(true);
|
|
||||||
|
|
||||||
#ifdef NEOCHAT_FLATPAK
|
#ifdef NEOCHAT_FLATPAK
|
||||||
// Copy over the included FontConfig configuration to the
|
// Copy over the included FontConfig configuration to the
|
||||||
@@ -238,7 +236,6 @@ int main(int argc, char *argv[])
|
|||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_timelinePlugin)
|
Q_IMPORT_QML_PLUGIN(org_kde_neochat_timelinePlugin)
|
||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_devtoolsPlugin)
|
Q_IMPORT_QML_PLUGIN(org_kde_neochat_devtoolsPlugin)
|
||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_loginPlugin)
|
Q_IMPORT_QML_PLUGIN(org_kde_neochat_loginPlugin)
|
||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_chatbarPlugin)
|
|
||||||
|
|
||||||
qml_register_types_org_kde_neochat();
|
qml_register_types_org_kde_neochat();
|
||||||
|
|
||||||
@@ -288,6 +285,7 @@ int main(int argc, char *argv[])
|
|||||||
ShareHandler::instance().setText(parser.value(shareOption));
|
ShareHandler::instance().setText(parser.value(shareOption));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
engine.addImageProvider(QLatin1String("mxc"), MatrixImageProvider::create(&engine, &engine));
|
||||||
engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider);
|
engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider);
|
||||||
|
|
||||||
engine.loadFromModule("org.kde.neochat", "Main");
|
engine.loadFromModule("org.kde.neochat", "Main");
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ QVariant AccountEmoticonModel::data(const QModelIndex &index, int role) const
|
|||||||
const auto &row = index.row();
|
const auto &row = index.row();
|
||||||
const auto &image = m_images->images[row];
|
const auto &image = m_images->images[row];
|
||||||
if (role == UrlRole) {
|
if (role == UrlRole) {
|
||||||
return m_connection->makeMediaUrl(image.url).toString();
|
return m_connection->makeMediaUrl(image.url);
|
||||||
}
|
}
|
||||||
if (role == BodyRole) {
|
if (role == BodyRole) {
|
||||||
if (image.body) {
|
if (image.body) {
|
||||||
@@ -163,11 +163,7 @@ void AccountEmoticonModel::setEmoticonImage(int index, const QUrl &source)
|
|||||||
QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl source)
|
QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl source)
|
||||||
{
|
{
|
||||||
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||||
#if Quotient_VERSION_MINOR > 8
|
|
||||||
co_await qCoro(job.get(), &BaseJob::finished);
|
|
||||||
#else
|
|
||||||
co_await qCoro(job, &BaseJob::finished);
|
co_await qCoro(job, &BaseJob::finished);
|
||||||
#endif
|
|
||||||
if (job->error() != BaseJob::NoError) {
|
if (job->error() != BaseJob::NoError) {
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
@@ -189,11 +185,7 @@ QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl sourc
|
|||||||
QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString shortcode, QString description, QString type)
|
QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString shortcode, QString description, QString type)
|
||||||
{
|
{
|
||||||
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||||
#if Quotient_VERSION_MINOR > 8
|
|
||||||
co_await qCoro(job.get(), &BaseJob::finished);
|
|
||||||
#else
|
|
||||||
co_await qCoro(job, &BaseJob::finished);
|
co_await qCoro(job, &BaseJob::finished);
|
||||||
#endif
|
|
||||||
if (job->error() != BaseJob::NoError) {
|
if (job->error() != BaseJob::NoError) {
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "roommanager.h"
|
#include "roommanager.h"
|
||||||
#include <Quotient/events/roommemberevent.h>
|
#include <Quotient/events/roommemberevent.h>
|
||||||
#include <Quotient/events/roompowerlevelsevent.h>
|
#include <Quotient/events/roompowerlevelsevent.h>
|
||||||
#include <Quotient/user.h>
|
|
||||||
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
@@ -203,11 +202,11 @@ QList<ActionsModel::Action> actions{
|
|||||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is banned from this room.", "%1 is banned from this room.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is banned from this room.", "%1 is banned from this room.", text));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (room->localMember().id() == text) {
|
if (room->localUser()->id() == text) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18n("You are already in this room."));
|
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18n("You are already in this room."));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (room->members().contains(room->member(text))) {
|
if (room->users().contains(room->user(text))) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already in this room.", "%1 is already in this room.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already in this room.", "%1 is already in this room.", text));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@@ -360,7 +359,7 @@ QList<ActionsModel::Action> actions{
|
|||||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<username> is already ignored.", "%1 is already ignored.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<username> is already ignored.", "%1 is already ignored.", text));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
room->connection()->addToIgnoredUsers(text);
|
room->connection()->addToIgnoredUsers(room->connection()->user(text));
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> is now ignored", "%1 is now ignored.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> is now ignored", "%1 is now ignored.", text));
|
||||||
return QString();
|
return QString();
|
||||||
},
|
},
|
||||||
@@ -383,7 +382,7 @@ QList<ActionsModel::Action> actions{
|
|||||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<username> is not ignored.", "%1 is not ignored.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<username> is not ignored.", "%1 is not ignored.", text));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
room->connection()->removeFromIgnoredUsers(text);
|
room->connection()->removeFromIgnoredUsers(room->connection()->user(text));
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> is no longer ignored.", "%1 is no longer ignored.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> is no longer ignored.", "%1 is no longer ignored.", text));
|
||||||
return QString();
|
return QString();
|
||||||
},
|
},
|
||||||
@@ -432,11 +431,11 @@ QList<ActionsModel::Action> actions{
|
|||||||
if (!plEvent) {
|
if (!plEvent) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (plEvent->ban() > plEvent->powerLevelForUser(room->localMember().id())) {
|
if (plEvent->ban() > plEvent->powerLevelForUser(room->localUser()->id())) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to ban users from this room."));
|
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to ban users from this room."));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (plEvent->powerLevelForUser(room->localMember().id()) <= plEvent->powerLevelForUser(parts[0])) {
|
if (plEvent->powerLevelForUser(room->localUser()->id()) <= plEvent->powerLevelForUser(parts[0])) {
|
||||||
Q_EMIT room->showMessage(
|
Q_EMIT room->showMessage(
|
||||||
NeoChatRoom::Error,
|
NeoChatRoom::Error,
|
||||||
i18nc("You are not allowed to ban <username> from this room.", "You are not allowed to ban %1 from this room.", parts[0]));
|
i18nc("You are not allowed to ban <username> from this room.", "You are not allowed to ban %1 from this room.", parts[0]));
|
||||||
@@ -465,7 +464,7 @@ QList<ActionsModel::Action> actions{
|
|||||||
if (!plEvent) {
|
if (!plEvent) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (plEvent->ban() > plEvent->powerLevelForUser(room->localMember().id())) {
|
if (plEvent->ban() > plEvent->powerLevelForUser(room->localUser()->id())) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to unban users from this room."));
|
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to unban users from this room."));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@@ -496,7 +495,7 @@ QList<ActionsModel::Action> actions{
|
|||||||
i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", parts[0]));
|
i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", parts[0]));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (parts[0] == room->localMember().id()) {
|
if (parts[0] == room->localUser()->id()) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You cannot kick yourself from the room."));
|
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You cannot kick yourself from the room."));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@@ -509,11 +508,11 @@ QList<ActionsModel::Action> actions{
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
auto kick = plEvent->kick();
|
auto kick = plEvent->kick();
|
||||||
if (plEvent->powerLevelForUser(room->localMember().id()) < kick) {
|
if (plEvent->powerLevelForUser(room->localUser()->id()) < kick) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to kick users from this room."));
|
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to kick users from this room."));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (plEvent->powerLevelForUser(room->localMember().id()) <= plEvent->powerLevelForUser(parts[0])) {
|
if (plEvent->powerLevelForUser(room->localUser()->id()) <= plEvent->powerLevelForUser(parts[0])) {
|
||||||
Q_EMIT room->showMessage(
|
Q_EMIT room->showMessage(
|
||||||
NeoChatRoom::Error,
|
NeoChatRoom::Error,
|
||||||
i18nc("You are not allowed to kick <username> from this room", "You are not allowed to kick %1 from this room.", parts[0]));
|
i18nc("You are not allowed to kick <username> from this room", "You are not allowed to kick %1 from this room.", parts[0]));
|
||||||
|
|||||||
@@ -153,13 +153,13 @@ QVariant CustomEmojiModel::data(const QModelIndex &idx, int role) const
|
|||||||
|
|
||||||
switch (Roles(role)) {
|
switch (Roles(role)) {
|
||||||
case Roles::ModelData:
|
case Roles::ModelData:
|
||||||
return QVariant::fromValue(Emoji(m_connection->makeMediaUrl(QUrl(data.url)).toString(), data.name, true));
|
return QVariant::fromValue(Emoji(QStringLiteral("image://mxc/") + data.url.mid(6), data.name, true));
|
||||||
case Roles::Name:
|
case Roles::Name:
|
||||||
case Roles::DisplayRole:
|
case Roles::DisplayRole:
|
||||||
case Roles::ReplacedTextRole:
|
case Roles::ReplacedTextRole:
|
||||||
return data.name;
|
return data.name;
|
||||||
case Roles::ImageURL:
|
case Roles::ImageURL:
|
||||||
return m_connection->makeMediaUrl(QUrl(data.url));
|
return QUrl(QStringLiteral("image://mxc/") + data.url.mid(6));
|
||||||
case Roles::MxcUrl:
|
case Roles::MxcUrl:
|
||||||
return m_connection->makeMediaUrl(QUrl(data.url));
|
return m_connection->makeMediaUrl(QUrl(data.url));
|
||||||
default:
|
default:
|
||||||
@@ -205,7 +205,7 @@ QVariantList CustomEmojiModel::filterModel(const QString &filter)
|
|||||||
if (!emoji.name.contains(filter, Qt::CaseInsensitive))
|
if (!emoji.name.contains(filter, Qt::CaseInsensitive))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
results << QVariant::fromValue(Emoji(m_connection->makeMediaUrl(QUrl(emoji.url)).toString(), emoji.name, true));
|
results << QVariant::fromValue(Emoji(QStringLiteral("image://mxc/") + emoji.url.mid(6), emoji.name, true));
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,12 +128,8 @@ void DevicesModel::logout(const QString &deviceId, const QString &password)
|
|||||||
authData["type"_ls] = "m.login.password"_ls;
|
authData["type"_ls] = "m.login.password"_ls;
|
||||||
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, m_connection->user()->id()}};
|
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, m_connection->user()->id()}};
|
||||||
authData["identifier"_ls] = identifier;
|
authData["identifier"_ls] = identifier;
|
||||||
auto innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
auto *innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
||||||
#if Quotient_VERSION_MINOR > 8
|
|
||||||
connect(innerJob.get(), &BaseJob::success, this, onSuccess);
|
|
||||||
#else
|
|
||||||
connect(innerJob, &BaseJob::success, this, onSuccess);
|
connect(innerJob, &BaseJob::success, this, onSuccess);
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
onSuccess();
|
onSuccess();
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user