Compare commits
1 Commits
v24.01.75
...
work/fix_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0083199493 |
@@ -19,7 +19,6 @@
|
||||
"--talk-name=org.freedesktop.Notifications",
|
||||
"--talk-name=org.kde.kwalletd5",
|
||||
"--talk-name=org.kde.StatusNotifierWatcher",
|
||||
"--talk-name=org.freedesktop.secrets",
|
||||
"--own-name=org.kde.StatusNotifierItem-2-2"
|
||||
],
|
||||
"modules": [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
include:
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/reuse-lint.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
|
||||
# - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
|
||||
# - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
|
||||
|
||||
@@ -13,10 +13,8 @@ Dependencies:
|
||||
'frameworks/kitemmodels': '@latest-kf6'
|
||||
'frameworks/kquickcharts': '@latest-kf6'
|
||||
'frameworks/knotifications': '@latest-kf6'
|
||||
'frameworks/kcolorscheme': '@latest-kf6'
|
||||
'libraries/kquickimageeditor': '@latest-kf6'
|
||||
'frameworks/sonnet': '@latest-kf6'
|
||||
'frameworks/prison': '@latest-kf6'
|
||||
'libraries/kirigami-addons': '@latest-kf6'
|
||||
'third-party/libquotient': '@latest'
|
||||
'third-party/qtkeychain': '@latest'
|
||||
@@ -27,6 +25,7 @@ Dependencies:
|
||||
'frameworks/qqc2-desktop-style': '@latest-kf6'
|
||||
'frameworks/kio': '@latest-kf6'
|
||||
'frameworks/kwindowsystem': '@latest-kf6'
|
||||
'frameworks/kconfigwidgets': '@latest-kf6'
|
||||
- 'on': ['Linux', 'FreeBSD']
|
||||
'require':
|
||||
'frameworks/kdbusaddons': '@latest-kf6'
|
||||
|
||||
@@ -41,7 +41,3 @@ License: CC0-1.0
|
||||
Files: .flatpak-manifest.json
|
||||
Copyright: 2020-2022 Tobias Fella <tobias.fella@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: autotests/data/*
|
||||
Copyright: none
|
||||
License: CC0-1.0
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "01")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "75")
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "23")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
@@ -37,7 +37,6 @@ include(ECMAddAppIcon)
|
||||
include(KDEGitCommitHooks)
|
||||
include(ECMCheckOutboundLicense)
|
||||
include(ECMQtDeclareLoggingCategory)
|
||||
include(ECMAddAndroidApk)
|
||||
if (NOT ANDROID)
|
||||
include(KDEClangFormat)
|
||||
endif()
|
||||
@@ -58,7 +57,7 @@ set_package_properties(Qt6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
)
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels)
|
||||
set_package_properties(KF6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
@@ -77,7 +76,7 @@ if(ANDROID)
|
||||
)
|
||||
else()
|
||||
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle ConfigWidgets KIO WindowSystem StatusNotifierItem)
|
||||
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
|
||||
TYPE RUNTIME
|
||||
)
|
||||
@@ -102,8 +101,7 @@ set_package_properties(QuotientQt6 PROPERTIES
|
||||
PURPOSE "Talk with matrix server"
|
||||
)
|
||||
|
||||
# The android part is just for CI. We do NOT support any builds without E2EE
|
||||
if (NOT TARGET Olm::Olm AND NOT ANDROID)
|
||||
if (NOT TARGET Olm::Olm)
|
||||
message(FATAL_ERROR "NeoChat requires Quotient with the E2EE feature enabled")
|
||||
endif()
|
||||
|
||||
@@ -119,8 +117,7 @@ set_package_properties(cmark PROPERTIES
|
||||
ecm_find_qmlmodule(org.kde.kquickimageeditor 1.0)
|
||||
ecm_find_qmlmodule(org.kde.kitemmodels 1.0)
|
||||
ecm_find_qmlmodule(org.kde.quickcharts 1.0)
|
||||
ecm_find_qmlmodule(QtLocation)
|
||||
ecm_find_qmlmodule(org.kde.prison)
|
||||
ecm_find_qmlmodule(QtLocation ${QTLOCATION_MODULE_QML_VERSION})
|
||||
|
||||
find_package(KQuickImageEditor COMPONENTS)
|
||||
set_package_properties(KQuickImageEditor PROPERTIES
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
android:versionName="${versionName}"
|
||||
android:versionCode="${versionCode}"
|
||||
android:installLocation="auto">
|
||||
<application android:name="org.qtproject.qt.android.bindings.QtApplication" android:label="NeoChat" android:icon="@drawable/neochat" android:usesCleartextTraffic="true">
|
||||
<application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="NeoChat" android:icon="@drawable/neochat" android:usesCleartextTraffic="true">
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
|
||||
android:name="org.qtproject.qt.android.bindings.QtActivity"
|
||||
android:name="org.qtproject.qt5.android.bindings.QtActivity"
|
||||
android:label="NeoChat"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:launchMode="singleTop"
|
||||
|
||||
@@ -12,7 +12,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||
classpath 'com.android.tools.build:gradle:7.0.2'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ android {
|
||||
* The following variables:
|
||||
* - androidBuildToolsVersion,
|
||||
* - androidCompileSdkVersion
|
||||
* - qtAndroidDir - holds the path to qt android files
|
||||
* - qt5AndroidDir - holds the path to qt android files
|
||||
* needed to build any Qt application
|
||||
* on Android.
|
||||
*
|
||||
@@ -44,20 +44,17 @@ android {
|
||||
* Changing them manually might break the compilation!
|
||||
*******************************************************/
|
||||
|
||||
compileSdkVersion androidCompileSdkVersion
|
||||
compileSdkVersion androidCompileSdkVersion.toInteger()
|
||||
|
||||
buildToolsVersion androidBuildToolsVersion
|
||||
ndkVersion androidNdkVersion
|
||||
|
||||
// Extract native libraries from the APK
|
||||
packagingOptions.jniLibs.useLegacyPackaging true
|
||||
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = [qtAndroidDir + '/src', 'src', 'java']
|
||||
aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl']
|
||||
res.srcDirs = [qtAndroidDir + '/res', 'res']
|
||||
java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
|
||||
aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
|
||||
res.srcDirs = [qt5AndroidDir + '/res', 'res']
|
||||
resources.srcDirs = ['src']
|
||||
renderscript.srcDirs = ['src']
|
||||
assets.srcDirs = ['assets']
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" )
|
||||
|
||||
ecm_add_test(
|
||||
neochatroomtest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
@@ -34,15 +32,3 @@ ecm_add_test(
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME eventhandlertest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
chatbarcachetest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME chatbarcachetest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
chatdocumenthandlertest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME chatdocumenthandlertest
|
||||
)
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
#include <QTest>
|
||||
|
||||
#include <Quotient/syncdata.h>
|
||||
#include <qtestcase.h>
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
class TestRoom : public NeoChatRoom
|
||||
{
|
||||
public:
|
||||
using NeoChatRoom::NeoChatRoom;
|
||||
|
||||
void update(SyncRoomData &&data, bool fromCache = false)
|
||||
{
|
||||
Room::updateData(std::move(data), fromCache);
|
||||
}
|
||||
};
|
||||
|
||||
class ChatBarCacheTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
Connection *connection = nullptr;
|
||||
TestRoom *room = nullptr;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void empty();
|
||||
void noRoom();
|
||||
void badParent();
|
||||
void reply();
|
||||
void edit();
|
||||
void attachment();
|
||||
};
|
||||
|
||||
void ChatBarCacheTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
||||
|
||||
QFile testMinSyncFile;
|
||||
testMinSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-min-sync.json"));
|
||||
testMinSyncFile.open(QIODevice::ReadOnly);
|
||||
const auto testMinSyncJson = QJsonDocument::fromJson(testMinSyncFile.readAll());
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testMinSyncJson.object());
|
||||
room->update(std::move(roomData));
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::empty()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
|
||||
QCOMPARE(chatBarCache->text(), QString());
|
||||
QCOMPARE(chatBarCache->isReplying(), false);
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
QCOMPARE(chatBarCache->editId(), QString());
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::noRoom()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache());
|
||||
chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
|
||||
|
||||
// These should return empty even though a reply ID has been set because the
|
||||
// ChatBarCache has no parent.
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
|
||||
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::badParent()
|
||||
{
|
||||
QScopedPointer<QObject> badParent(new QObject());
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(badParent.get()));
|
||||
chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
|
||||
|
||||
// These should return empty even though a reply ID has been set because the
|
||||
// ChatBarCache has no parent.
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
|
||||
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::reply()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(QLatin1String("some text"));
|
||||
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
|
||||
chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
|
||||
|
||||
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
|
||||
QCOMPARE(chatBarCache->isReplying(), true);
|
||||
QCOMPARE(chatBarCache->replyId(), QLatin1String("$153456789:example.org"));
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
QCOMPARE(chatBarCache->editId(), QString());
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::edit()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(QLatin1String("some text"));
|
||||
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
|
||||
chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
|
||||
|
||||
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
|
||||
QCOMPARE(chatBarCache->isReplying(), false);
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), true);
|
||||
QCOMPARE(chatBarCache->editId(), QLatin1String("$153456789:example.org"));
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||
}
|
||||
|
||||
void ChatBarCacheTest::attachment()
|
||||
{
|
||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
||||
chatBarCache->setText(QLatin1String("some text"));
|
||||
chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
|
||||
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
|
||||
|
||||
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
|
||||
QCOMPARE(chatBarCache->isReplying(), false);
|
||||
QCOMPARE(chatBarCache->replyId(), QString());
|
||||
QCOMPARE(chatBarCache->isEditing(), false);
|
||||
QCOMPARE(chatBarCache->editId(), QString());
|
||||
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
|
||||
QCOMPARE(chatBarCache->relationMessage(), QString());
|
||||
QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(ChatBarCacheTest)
|
||||
#include "chatbarcachetest.moc"
|
||||
@@ -1,36 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QObject>
|
||||
#include <QTest>
|
||||
|
||||
#include "chatdocumenthandler.h"
|
||||
#include "neochatconfig.h"
|
||||
|
||||
class ChatDocumentHandlerTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ChatDocumentHandler emptyHandler;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void nullComplete();
|
||||
};
|
||||
|
||||
void ChatDocumentHandlerTest::initTestCase()
|
||||
{
|
||||
// HACK: this is to stop KStatusNotifierItem SEGFAULTING on cleanup.
|
||||
NeoChatConfig::self()->setSystemTray(false);
|
||||
}
|
||||
|
||||
void ChatDocumentHandlerTest::nullComplete()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "complete called with m_document set to nullptr.");
|
||||
emptyHandler.complete(0);
|
||||
}
|
||||
|
||||
QTEST_MAIN(ChatDocumentHandlerTest)
|
||||
#include "chatdocumenthandlertest.moc"
|
||||
@@ -1,381 +0,0 @@
|
||||
{
|
||||
"account_data": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"tags": {
|
||||
"u.work": {
|
||||
"order": 0.9
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.tag"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"custom_config_key": "custom_config_value"
|
||||
},
|
||||
"type": "org.example.custom.room.config"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ephemeral": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"user_ids": [
|
||||
"@alice:matrix.org",
|
||||
"@bob:example.com"
|
||||
]
|
||||
},
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"type": "m.typing"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$153456789:example.org": {
|
||||
"m.read": {
|
||||
"@alice:matrix.org": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@bob:example.com": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@tim:example.com": {
|
||||
"ts": 1436451550454
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@jeff:example.com": {
|
||||
"ts": 1436451550455
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@tina:example.com": {
|
||||
"ts": 1436451550456
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@sally:example.com": {
|
||||
"ts": 1436451550457
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@fred:example.com": {
|
||||
"ts": 1436451550458
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice Margatroid",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"m.heroes": [
|
||||
"@alice:example.com",
|
||||
"@bob:example.com"
|
||||
],
|
||||
"m.invited_member_count": 0,
|
||||
"m.joined_member_count": 2
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"body": "This is an example\ntext message",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<b>This is an example<br>text message</b>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$153456789:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1232
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://kde.org/123456",
|
||||
"displayname": "after",
|
||||
"membership": "join"
|
||||
},
|
||||
"origin_server_ts": 1690651134736,
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@example:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"replaces_state": "$1234567890:example.org",
|
||||
"prev_content": {
|
||||
"avatar_url": "mxc://kde.org/12345",
|
||||
"displayname": "before",
|
||||
"membership": "join"
|
||||
},
|
||||
"prev_sender": "@example:example.orgg",
|
||||
"age": 1234
|
||||
},
|
||||
"event_id": "$143273583553PhrSn:example.org",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "This is a highlight @bob:kde.org and this is a link https://kde.org",
|
||||
"format": "org.matrix.custom.html",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$1532735824654:example.org",
|
||||
"origin_server_ts": 1532735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1233
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"m.relates_to": {
|
||||
"event_id": "$153456789:example.org",
|
||||
"key": "👍",
|
||||
"rel_type": "m.annotation"
|
||||
}
|
||||
},
|
||||
"origin_server_ts": 1690322545182,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@alice:matrix.org",
|
||||
"type": "m.reaction",
|
||||
"unsigned": {
|
||||
"age": 390159120
|
||||
},
|
||||
"event_id": "$163456789:example.org",
|
||||
"age": 390159120
|
||||
},
|
||||
{
|
||||
"age": 4926305285,
|
||||
"content": {
|
||||
"body": "video caption",
|
||||
"filename": "video.mp4",
|
||||
"info": {
|
||||
"duration": 10,
|
||||
"h": 1080,
|
||||
"mimetype": "video/mp4",
|
||||
"size": 62650636,
|
||||
"w": 1920,
|
||||
"thumbnail_info": {
|
||||
"h": 450,
|
||||
"mimetype": "image/jpeg",
|
||||
"size": 382249,
|
||||
"w": 800
|
||||
},
|
||||
"thumbnail_url": "mxc://kde.org/2234567"
|
||||
},
|
||||
"msgtype": "m.video",
|
||||
"url": "mxc://kde.org/1234567"
|
||||
},
|
||||
"event_id": "$263456789:example.org",
|
||||
"origin_server_ts": 1685793783330,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 4926305285
|
||||
},
|
||||
"user_id": "@example:example.org"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "> <@example:example.org> This is an example\ntext message\n\nreply",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!jEsUZKDJdhlrceRyVU:example.org/$153456789:example.org?via=kde.org&via=matrix.org\">In reply to</a> <a href=\"https://matrix.to/#/@example:example.org\">@example:example.org</a><br><b>This is an example<br>text message</b></blockquote></mx-reply>reply",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$153456789:example.org"
|
||||
}
|
||||
},
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"origin_server_ts": 1690725965572,
|
||||
"sender": "@alice:matrix.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 98
|
||||
},
|
||||
"event_id": "$154456789:example.org",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "> <@example:example.org> video caption\n\nreply",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$263456789:example.org"
|
||||
}
|
||||
},
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"origin_server_ts": 1690725965573,
|
||||
"sender": "@alice:matrix.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 98
|
||||
},
|
||||
"event_id": "$154456799:example.org",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
|
||||
},
|
||||
{
|
||||
"age": 96845207,
|
||||
"content": {
|
||||
"body": "Lat: 51.7035, Lon: -1.14394",
|
||||
"geo_uri": "geo:51.7035,-1.14394",
|
||||
"msgtype": "m.location",
|
||||
"org.matrix.msc1767.text": "Lat: 51.7035, Lon: -1.14394",
|
||||
"org.matrix.msc3488.asset": {
|
||||
"type": "m.pin"
|
||||
},
|
||||
"org.matrix.msc3488.location": {
|
||||
"uri": "geo:51.7035,-1.14394"
|
||||
}
|
||||
},
|
||||
"event_id": "$1544567999:example.org",
|
||||
"origin_server_ts": 1690821582876,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 96845207
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "Thread root",
|
||||
"format": "org.matrix.custom.html",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$threadroot:example.org",
|
||||
"origin_server_ts": 1690821582879,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1232
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "Thread message 1",
|
||||
"msgtype": "m.text",
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.thread",
|
||||
"event_id": "$threadroot:example.org",
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$threadroot:example.org"
|
||||
},
|
||||
"is_falling_back": true
|
||||
}
|
||||
},
|
||||
"event_id": "$threadmessage1:example.org",
|
||||
"origin_server_ts": 1690821582890,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1238
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "Thread message 2",
|
||||
"msgtype": "m.text",
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.thread",
|
||||
"event_id": "$threadroot:example.org",
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$threadmessage1:example.org"
|
||||
},
|
||||
"is_falling_back": true
|
||||
}
|
||||
},
|
||||
"event_id": "$threadmessage2:example.org",
|
||||
"origin_server_ts": 1690821582890,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1238
|
||||
}
|
||||
}
|
||||
],
|
||||
"limited": true,
|
||||
"prev_batch": "t34-23535_0_0"
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
{
|
||||
"account_data": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"tags": {
|
||||
"u.work": {
|
||||
"order": 0.9
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.tag"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"custom_config_key": "custom_config_value"
|
||||
},
|
||||
"type": "org.example.custom.room.config"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ephemeral": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"user_ids": [
|
||||
"@alice:matrix.org",
|
||||
"@bob:example.com"
|
||||
]
|
||||
},
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"type": "m.typing"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice Margatroid",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"m.heroes": [
|
||||
"@alice:example.com",
|
||||
"@bob:example.com"
|
||||
],
|
||||
"m.invited_member_count": 0,
|
||||
"m.joined_member_count": 2
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"body": "This is an example\ntext message",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<b>This is an example<br>text message</b>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$153456789:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1232
|
||||
}
|
||||
}
|
||||
],
|
||||
"limited": true,
|
||||
"prev_batch": "t34-23535_0_0"
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
{
|
||||
"account_data": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"tags": {
|
||||
"u.work": {
|
||||
"order": 0.9
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.tag"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"custom_config_key": "custom_config_value"
|
||||
},
|
||||
"type": "org.example.custom.room.config"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ephemeral": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"user_ids": [
|
||||
"@alice:matrix.org",
|
||||
"@bob:example.com"
|
||||
]
|
||||
},
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"type": "m.typing"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice Margatroid",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"m.heroes": [
|
||||
"@alice:example.com",
|
||||
"@bob:example.com"
|
||||
],
|
||||
"m.invited_member_count": 0,
|
||||
"m.joined_member_count": 2
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"body": "This is an **example** text message",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<b>This is an example text message</b>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1232
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "/me This is an emote.",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "This is an emote.",
|
||||
"msgtype": "m.emote"
|
||||
},
|
||||
"event_id": "$153273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1532735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1231
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "tested",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$zrCiBxBnqqTn0Z5FY78qSZAszno_w8nJJXzfBULG-3E",
|
||||
"origin_server_ts": 1680948575928,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1747776,
|
||||
"m.relations": {
|
||||
"m.replace": {
|
||||
"event_id": "$UX0PlpyI7vYO32iHMuuYEP7ECMh4sX3XLGiB2SwM4mQ",
|
||||
"origin_server_ts": 1680948580992,
|
||||
"sender": "@example:example.org"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"limited": true,
|
||||
"prev_batch": "t34-23535_0_0"
|
||||
}
|
||||
}
|
||||
@@ -39,61 +39,33 @@ private:
|
||||
Connection *connection = nullptr;
|
||||
TestRoom *room = nullptr;
|
||||
EventHandler eventHandler;
|
||||
EventHandler emptyHandler;
|
||||
EventHandler noEventHandler;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void nullSetEvent();
|
||||
void eventId();
|
||||
void nullEventId();
|
||||
void delegateType_data();
|
||||
void delegateType();
|
||||
void nullDelegateType();
|
||||
void author();
|
||||
void nullAuthor();
|
||||
void authorDisplayName();
|
||||
void nullAuthorDisplayName();
|
||||
void time();
|
||||
void nullTime();
|
||||
void timeString();
|
||||
void nullTimeString();
|
||||
void highlighted();
|
||||
void nullHighlighted();
|
||||
void hidden();
|
||||
void nullHidden();
|
||||
void body();
|
||||
void nullBody();
|
||||
void genericBody_data();
|
||||
void genericBody();
|
||||
void nullGenericBody();
|
||||
void mediaInfo();
|
||||
void nullMediaInfo();
|
||||
void linkPreviewer();
|
||||
void nullLinkPreviewer();
|
||||
void reactions();
|
||||
void nullReactions();
|
||||
void hasReply();
|
||||
void nullHasReply();
|
||||
void replyId();
|
||||
void nullReplyId();
|
||||
void replyDelegateType();
|
||||
void nullReplyDelegateType();
|
||||
void replyAuthor();
|
||||
void nullReplyAuthor();
|
||||
void replyBody();
|
||||
void nullReplyBody();
|
||||
void replyMediaInfo();
|
||||
void nullReplyMediaInfo();
|
||||
void thread();
|
||||
void nullThread();
|
||||
void location();
|
||||
void nullLocation();
|
||||
void readMarkers();
|
||||
void nullReadMarkers();
|
||||
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
void EventHandlerTest::initTestCase()
|
||||
@@ -101,21 +73,332 @@ void EventHandlerTest::initTestCase()
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
||||
|
||||
QFile testEventHandlerSyncFile;
|
||||
testEventHandlerSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-eventhandler-sync.json"));
|
||||
testEventHandlerSyncFile.open(QIODevice::ReadOnly);
|
||||
const auto testEventHandlerSyncJson = QJsonDocument::fromJson(testEventHandlerSyncFile.readAll());
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testEventHandlerSyncJson.object());
|
||||
const auto json = QJsonDocument::fromJson(R"EVENT({
|
||||
"account_data": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"tags": {
|
||||
"u.work": {
|
||||
"order": 0.9
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.tag"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"custom_config_key": "custom_config_value"
|
||||
},
|
||||
"type": "org.example.custom.room.config"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ephemeral": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"user_ids": [
|
||||
"@alice:matrix.org",
|
||||
"@bob:example.com"
|
||||
]
|
||||
},
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"type": "m.typing"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$153456789:example.org": {
|
||||
"m.read": {
|
||||
"@alice:matrix.org": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@bob:example.com": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@tim:example.com": {
|
||||
"ts": 1436451550454
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@jeff:example.com": {
|
||||
"ts": 1436451550455
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@tina:example.com": {
|
||||
"ts": 1436451550456
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@sally:example.com": {
|
||||
"ts": 1436451550457
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"$1532735824654:example.org": {
|
||||
"m.read": {
|
||||
"@fred:example.com": {
|
||||
"ts": 1436451550458
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.receipt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice Margatroid",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"m.heroes": [
|
||||
"@alice:example.com",
|
||||
"@bob:example.com"
|
||||
],
|
||||
"m.invited_member_count": 0,
|
||||
"m.joined_member_count": 2
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"body": "This is an example\ntext message",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<b>This is an example<br>text message</b>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$153456789:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1232
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://kde.org/123456",
|
||||
"displayname": "after",
|
||||
"membership": "join"
|
||||
},
|
||||
"origin_server_ts": 1690651134736,
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@example:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"replaces_state": "$1234567890:example.org",
|
||||
"prev_content": {
|
||||
"avatar_url": "mxc://kde.org/12345",
|
||||
"displayname": "before",
|
||||
"membership": "join"
|
||||
},
|
||||
"prev_sender": "@example:example.orgg",
|
||||
"age": 1234
|
||||
},
|
||||
"event_id": "$143273583553PhrSn:example.org",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "This is a highlight @bob:kde.org and this is a link https://kde.org",
|
||||
"format": "org.matrix.custom.html",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$1532735824654:example.org",
|
||||
"origin_server_ts": 1532735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1233
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"m.relates_to": {
|
||||
"event_id": "$153456789:example.org",
|
||||
"key": "👍",
|
||||
"rel_type": "m.annotation"
|
||||
}
|
||||
},
|
||||
"origin_server_ts": 1690322545182,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@alice:matrix.org",
|
||||
"type": "m.reaction",
|
||||
"unsigned": {
|
||||
"age": 390159120
|
||||
},
|
||||
"event_id": "$163456789:example.org",
|
||||
"age": 390159120
|
||||
},
|
||||
{
|
||||
"age": 4926305285,
|
||||
"content": {
|
||||
"body": "video caption",
|
||||
"filename": "video.mp4",
|
||||
"info": {
|
||||
"duration": 10,
|
||||
"h": 1080,
|
||||
"mimetype": "video/mp4",
|
||||
"size": 62650636,
|
||||
"w": 1920,
|
||||
"thumbnail_info": {
|
||||
"h": 450,
|
||||
"mimetype": "image/jpeg",
|
||||
"size": 382249,
|
||||
"w": 800
|
||||
},
|
||||
"thumbnail_url": "mxc://kde.org/2234567"
|
||||
},
|
||||
"msgtype": "m.video",
|
||||
"url": "mxc://kde.org/1234567"
|
||||
},
|
||||
"event_id": "$263456789:example.org",
|
||||
"origin_server_ts": 1685793783330,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 4926305285
|
||||
},
|
||||
"user_id": "@example:example.org"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "> <@example:example.org> This is an example\ntext message\n\nreply",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!jEsUZKDJdhlrceRyVU:example.org/$153456789:example.org?via=kde.org&via=matrix.org\">In reply to</a> <a href=\"https://matrix.to/#/@example:example.org\">@example:example.org</a><br><b>This is an example<br>text message</b></blockquote></mx-reply>reply",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$153456789:example.org"
|
||||
}
|
||||
},
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"origin_server_ts": 1690725965572,
|
||||
"sender": "@alice:matrix.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 98
|
||||
},
|
||||
"event_id": "$154456789:example.org",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "> <@example:example.org> video caption\n\nreply",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$263456789:example.org"
|
||||
}
|
||||
},
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"origin_server_ts": 1690725965573,
|
||||
"sender": "@alice:matrix.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 98
|
||||
},
|
||||
"event_id": "$154456799:example.org",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
|
||||
},
|
||||
{
|
||||
"age": 96845207,
|
||||
"content": {
|
||||
"body": "Lat: 51.7035, Lon: -1.14394",
|
||||
"geo_uri": "geo:51.7035,-1.14394",
|
||||
"msgtype": "m.location",
|
||||
"org.matrix.msc1767.text": "Lat: 51.7035, Lon: -1.14394",
|
||||
"org.matrix.msc3488.asset": {
|
||||
"type": "m.pin"
|
||||
},
|
||||
"org.matrix.msc3488.location": {
|
||||
"uri": "geo:51.7035,-1.14394"
|
||||
}
|
||||
},
|
||||
"event_id": "$1544567999:example.org",
|
||||
"origin_server_ts": 1690821582876,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 96845207
|
||||
}
|
||||
}
|
||||
],
|
||||
"limited": true,
|
||||
"prev_batch": "t34-23535_0_0"
|
||||
}
|
||||
})EVENT");
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, json.object());
|
||||
room->update(std::move(roomData));
|
||||
|
||||
eventHandler.setRoom(room);
|
||||
noEventHandler.setRoom(room);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullSetEvent()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "cannot setEvent when m_room is set to nullptr.");
|
||||
emptyHandler.setEvent(room->messageEvents().at(0).get());
|
||||
}
|
||||
|
||||
void EventHandlerTest::eventId()
|
||||
@@ -125,12 +408,6 @@ void EventHandlerTest::eventId()
|
||||
QCOMPARE(eventHandler.getId(), QStringLiteral("$153456789:example.org"));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullEventId()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getId called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getId(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::delegateType_data()
|
||||
{
|
||||
QTest::addColumn<int>("eventNum");
|
||||
@@ -154,12 +431,6 @@ void EventHandlerTest::delegateType()
|
||||
QCOMPARE(eventHandler.getDelegateType(), delegateType);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullDelegateType()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getDelegateType called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getDelegateType(), DelegateType::Other);
|
||||
}
|
||||
|
||||
void EventHandlerTest::author()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
@@ -177,15 +448,6 @@ void EventHandlerTest::author()
|
||||
QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(author));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullAuthor()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getAuthor(), QVariantMap());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
|
||||
QCOMPARE(noEventHandler.getAuthor(), room->getUser(nullptr));
|
||||
}
|
||||
|
||||
void EventHandlerTest::authorDisplayName()
|
||||
{
|
||||
auto event = room->messageEvents().at(1).get();
|
||||
@@ -194,15 +456,6 @@ void EventHandlerTest::authorDisplayName()
|
||||
QCOMPARE(eventHandler.getAuthorDisplayName(), QStringLiteral("before"));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullAuthorDisplayName()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getAuthorDisplayName(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getAuthorDisplayName(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::time()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
@@ -212,16 +465,6 @@ void EventHandlerTest::time()
|
||||
QCOMPARE(eventHandler.getTime(true, QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC)), QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullTime()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getTime called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getTime(), QDateTime());
|
||||
|
||||
eventHandler.setEvent(room->messageEvents().at(0).get());
|
||||
QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
|
||||
QCOMPARE(eventHandler.getTime(true), QDateTime());
|
||||
}
|
||||
|
||||
void EventHandlerTest::timeString()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
@@ -243,16 +486,6 @@ void EventHandlerTest::timeString()
|
||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullTimeString()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getTimeString called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getTimeString(false), QString());
|
||||
|
||||
eventHandler.setEvent(room->messageEvents().at(0).get());
|
||||
QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
|
||||
QCOMPARE(eventHandler.getTimeString(false, QLocale::ShortFormat, true), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::highlighted()
|
||||
{
|
||||
auto event = room->messageEvents().at(2).get();
|
||||
@@ -266,15 +499,6 @@ void EventHandlerTest::highlighted()
|
||||
QCOMPARE(eventHandler.isHighlighted(), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullHighlighted()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.isHighlighted(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.isHighlighted(), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::hidden()
|
||||
{
|
||||
auto event = room->messageEvents().at(3).get();
|
||||
@@ -288,15 +512,6 @@ void EventHandlerTest::hidden()
|
||||
QCOMPARE(eventHandler.isHidden(), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullHidden()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHidden called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.isHidden(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "isHidden called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.isHidden(), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::body()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
@@ -308,15 +523,6 @@ void EventHandlerTest::body()
|
||||
QCOMPARE(eventHandler.getPlainBody(true), QStringLiteral("This is an example text message"));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullBody()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getRichBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getRichBody(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getPlainBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getPlainBody(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::genericBody_data()
|
||||
{
|
||||
QTest::addColumn<int>("eventNum");
|
||||
@@ -339,12 +545,6 @@ void EventHandlerTest::genericBody()
|
||||
QCOMPARE(eventHandler.getGenericBody(), output);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullGenericBody()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getGenericBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getGenericBody(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::mediaInfo()
|
||||
{
|
||||
auto event = room->messageEvents().at(4).get();
|
||||
@@ -368,15 +568,6 @@ void EventHandlerTest::mediaInfo()
|
||||
QCOMPARE(thumbnailInfo["height"_ls], 450);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullMediaInfo()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getMediaInfo called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getMediaInfo(), QVariantMap());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getMediaInfo called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getMediaInfo(), QVariantMap());
|
||||
}
|
||||
|
||||
void EventHandlerTest::linkPreviewer()
|
||||
{
|
||||
auto event = room->messageEvents().at(2).get();
|
||||
@@ -390,15 +581,6 @@ void EventHandlerTest::linkPreviewer()
|
||||
QCOMPARE(eventHandler.getLinkPreviewer(), nullptr);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullLinkPreviewer()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getLinkPreviewer called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getLinkPreviewer(), nullptr);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getLinkPreviewer called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getLinkPreviewer(), nullptr);
|
||||
}
|
||||
|
||||
void EventHandlerTest::reactions()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
@@ -407,15 +589,6 @@ void EventHandlerTest::reactions()
|
||||
QCOMPARE(eventHandler.getReactions()->rowCount(), 1);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReactions()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReactions called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReactions(), nullptr);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReactions called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReactions(), nullptr);
|
||||
}
|
||||
|
||||
void EventHandlerTest::hasReply()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
@@ -429,12 +602,6 @@ void EventHandlerTest::hasReply()
|
||||
QCOMPARE(eventHandler.hasReply(), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullHasReply()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "hasReply called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.hasReply(), false);
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyId()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
@@ -448,12 +615,6 @@ void EventHandlerTest::replyId()
|
||||
QCOMPARE(eventHandler.getReplyId(), QStringLiteral(""));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyId()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyId called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyId(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyDelegateType()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
@@ -467,15 +628,6 @@ void EventHandlerTest::replyDelegateType()
|
||||
QCOMPARE(eventHandler.getReplyDelegateType(), DelegateType::Other);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyDelegateType()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyDelegateType called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReplyDelegateType(), DelegateType::Other);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyDelegateType called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyDelegateType(), DelegateType::Other);
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyAuthor()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
@@ -499,15 +651,6 @@ void EventHandlerTest::replyAuthor()
|
||||
QCOMPARE(eventHandler.getReplyAuthor(), room->getUser(nullptr));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyAuthor()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReplyAuthor(), QVariantMap());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_event set to nullptr. Returning empty user.");
|
||||
QCOMPARE(noEventHandler.getReplyAuthor(), room->getUser(nullptr));
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyBody()
|
||||
{
|
||||
auto event = room->messageEvents().at(5).get();
|
||||
@@ -519,15 +662,6 @@ void EventHandlerTest::replyBody()
|
||||
QCOMPARE(eventHandler.getReplyPlainBody(true), QStringLiteral("This is an example text message"));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyBody()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyRichBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyRichBody(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyPlainBody called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyPlainBody(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::replyMediaInfo()
|
||||
{
|
||||
auto event = room->messageEvents().at(6).get();
|
||||
@@ -552,47 +686,6 @@ void EventHandlerTest::replyMediaInfo()
|
||||
QCOMPARE(thumbnailInfo["height"_ls], 450);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReplyMediaInfo()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyMediaInfo called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReplyMediaInfo(), QVariantMap());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReplyMediaInfo called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReplyMediaInfo(), QVariantMap());
|
||||
}
|
||||
|
||||
void EventHandlerTest::thread()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isThreaded(), false);
|
||||
QCOMPARE(eventHandler.threadRoot(), QString());
|
||||
|
||||
event = room->messageEvents().at(9).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isThreaded(), true);
|
||||
QCOMPARE(eventHandler.threadRoot(), QStringLiteral("$threadroot:example.org"));
|
||||
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$threadroot:example.org"));
|
||||
|
||||
event = room->messageEvents().at(10).get();
|
||||
eventHandler.setEvent(event);
|
||||
|
||||
QCOMPARE(eventHandler.isThreaded(), true);
|
||||
QCOMPARE(eventHandler.threadRoot(), QStringLiteral("$threadroot:example.org"));
|
||||
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$threadmessage1:example.org"));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullThread()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "isThreaded called with m_event set to nullptr.");
|
||||
QCOMPARE(emptyHandler.isThreaded(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "threadRoot called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.threadRoot(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::location()
|
||||
{
|
||||
auto event = room->messageEvents().at(7).get();
|
||||
@@ -603,18 +696,6 @@ void EventHandlerTest::location()
|
||||
QCOMPARE(eventHandler.getLocationAssetType(), QStringLiteral("m.pin"));
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullLocation()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "getLatitude called with m_event set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getLatitude(), -100.0);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getLongitude called with m_event set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getLongitude(), -200.0);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getLocationAssetType called with m_event set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getLocationAssetType(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::readMarkers()
|
||||
{
|
||||
auto event = room->messageEvents().at(0).get();
|
||||
@@ -644,37 +725,5 @@ void EventHandlerTest::readMarkers()
|
||||
QCOMPARE(eventHandler.getReadMarkersString().startsWith(QStringLiteral("6 users:")), true);
|
||||
}
|
||||
|
||||
void EventHandlerTest::nullReadMarkers()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.hasReadMarkers(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReadMarkers(), QVariantList());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getNumberExcessReadMarkers(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_room set to nullptr.");
|
||||
QCOMPARE(emptyHandler.getReadMarkersString(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.hasReadMarkers(), false);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReadMarkers(), QVariantList());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getNumberExcessReadMarkers(), QString());
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_event set to nullptr.");
|
||||
QCOMPARE(noEventHandler.getReadMarkersString(), QString());
|
||||
}
|
||||
|
||||
void EventHandlerTest::cleanup()
|
||||
{
|
||||
eventHandler.setEvent(nullptr);
|
||||
}
|
||||
|
||||
QTEST_MAIN(EventHandlerTest)
|
||||
#include "eventhandlertest.moc"
|
||||
|
||||
@@ -42,18 +42,101 @@ void NeoChatRoomTest::initTestCase()
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
||||
|
||||
QFile testMinSyncFile;
|
||||
testMinSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-min-sync.json"));
|
||||
testMinSyncFile.open(QIODevice::ReadOnly);
|
||||
const auto testMinSyncJson = QJsonDocument::fromJson(testMinSyncFile.readAll());
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testMinSyncJson.object());
|
||||
auto json = QJsonDocument::fromJson(R"EVENT({
|
||||
"account_data": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"tags": {
|
||||
"u.work": {
|
||||
"order": 0.9
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.tag"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"custom_config_key": "custom_config_value"
|
||||
},
|
||||
"type": "org.example.custom.room.config"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ephemeral": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"user_ids": [
|
||||
"@alice:matrix.org",
|
||||
"@bob:example.com"
|
||||
]
|
||||
},
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"type": "m.typing"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice Margatroid",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"m.heroes": [
|
||||
"@alice:example.com",
|
||||
"@bob:example.com"
|
||||
],
|
||||
"m.invited_member_count": 0,
|
||||
"m.joined_member_count": 2
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"body": "This is an **example** text message",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<b>This is an example text message</b>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1235
|
||||
}
|
||||
}
|
||||
],
|
||||
"limited": true,
|
||||
"prev_batch": "t34-23535_0_0"
|
||||
}
|
||||
})EVENT");
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, json.object());
|
||||
room->update(std::move(roomData));
|
||||
}
|
||||
|
||||
void NeoChatRoomTest::subtitleTextTest()
|
||||
{
|
||||
QCOMPARE(room->timelineSize(), 1);
|
||||
QCOMPARE(room->lastEventToString(), QStringLiteral("@example:example.org: This is an example\ntext message"));
|
||||
QCOMPARE(room->lastEventToString(), QStringLiteral("@example:example.org: This is an example text message"));
|
||||
}
|
||||
|
||||
void NeoChatRoomTest::eventTest()
|
||||
|
||||
@@ -40,7 +40,6 @@ private Q_SLOTS:
|
||||
void stripDisallowedTags();
|
||||
void stripDisallowedAttributes();
|
||||
void emptyCodeTags();
|
||||
void formatBlockQuote();
|
||||
|
||||
void sendSimpleStringCase();
|
||||
void sendSingleParaMarkup();
|
||||
@@ -67,7 +66,6 @@ private Q_SLOTS:
|
||||
void receiveRichEdited_data();
|
||||
void receiveRichEdited();
|
||||
void receiveLineSeparator();
|
||||
void receiveRichCodeUrl();
|
||||
|
||||
void linkPreviewsMatch_data();
|
||||
void linkPreviewsMatch();
|
||||
@@ -80,11 +78,131 @@ void TextHandlerTest::initTestCase()
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
||||
|
||||
QFile testTextHandlerSyncFile;
|
||||
testTextHandlerSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-texthandler-sync.json"));
|
||||
testTextHandlerSyncFile.open(QIODevice::ReadOnly);
|
||||
const auto testTextHandlerSyncJson = QJsonDocument::fromJson(testTextHandlerSyncFile.readAll());
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testTextHandlerSyncJson.object());
|
||||
const auto json = QJsonDocument::fromJson(R"EVENT({
|
||||
"account_data": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"tags": {
|
||||
"u.work": {
|
||||
"order": 0.9
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "m.tag"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"custom_config_key": "custom_config_value"
|
||||
},
|
||||
"type": "org.example.custom.room.config"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ephemeral": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"user_ids": [
|
||||
"@alice:matrix.org",
|
||||
"@bob:example.com"
|
||||
]
|
||||
},
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"type": "m.typing"
|
||||
}
|
||||
]
|
||||
},
|
||||
"state": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice Margatroid",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@alice:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"m.heroes": [
|
||||
"@alice:example.com",
|
||||
"@bob:example.com"
|
||||
],
|
||||
"m.invited_member_count": 0,
|
||||
"m.joined_member_count": 2
|
||||
},
|
||||
"timeline": {
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"body": "This is an **example** text message",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<b>This is an example text message</b>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$143273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1432735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1232
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "/me This is an emote.",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "This is an emote.",
|
||||
"msgtype": "m.emote"
|
||||
},
|
||||
"event_id": "$153273582443PhrSn:example.org",
|
||||
"origin_server_ts": 1532735824654,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1231
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"body": "tested",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$zrCiBxBnqqTn0Z5FY78qSZAszno_w8nJJXzfBULG-3E",
|
||||
"origin_server_ts": 1680948575928,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 1747776,
|
||||
"m.relations": {
|
||||
"m.replace": {
|
||||
"event_id": "$UX0PlpyI7vYO32iHMuuYEP7ECMh4sX3XLGiB2SwM4mQ",
|
||||
"origin_server_ts": 1680948580992,
|
||||
"sender": "@example:example.org"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"limited": true,
|
||||
"prev_batch": "t34-23535_0_0"
|
||||
}
|
||||
})EVENT");
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, json.object());
|
||||
room->update(std::move(roomData));
|
||||
}
|
||||
|
||||
@@ -147,16 +265,6 @@ void TextHandlerTest::emptyCodeTags()
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
||||
}
|
||||
|
||||
void TextHandlerTest::formatBlockQuote()
|
||||
{
|
||||
auto input = QStringLiteral("<blockquote>\n<p>Lorem Ispum</p>\n</blockquote>");
|
||||
auto expectedOutput = QStringLiteral("<blockquote><table><tr><td>\u201CLorem Ispum\u201D</td></tr></table></blockquote>");
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(input);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), expectedOutput);
|
||||
}
|
||||
|
||||
void TextHandlerTest::sendSimpleStringCase()
|
||||
{
|
||||
const QString testInputString = QStringLiteral("This data should just be put in a paragraph.");
|
||||
@@ -469,9 +577,8 @@ void TextHandlerTest::receiveRichEdited_data()
|
||||
QTest::newRow("basic") << QStringLiteral("Edited") << QStringLiteral("Edited <span style=\"color:#000000\">(edited)</span>");
|
||||
QTest::newRow("multiple paragraphs") << QStringLiteral("<p>Edited</p>\n<p>Edited</p>")
|
||||
<< QStringLiteral("<p>Edited</p>\n<p>Edited <span style=\"color:#000000\">(edited)</span></p>");
|
||||
QTest::newRow("blockquote")
|
||||
<< QStringLiteral("<blockquote>Edited</blockquote>")
|
||||
<< QStringLiteral("<blockquote><table><tr><td>\u201CEdited\u201D</td></tr></table></blockquote><p> <span style=\"color:#000000\">(edited)</span></p>");
|
||||
QTest::newRow("blockquote") << QStringLiteral("<blockquote>Edited</blockquote>")
|
||||
<< QStringLiteral("<blockquote>Edited</blockquote><p> <span style=\"color:#000000\">(edited)</span></p>");
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveRichEdited()
|
||||
@@ -540,13 +647,5 @@ void TextHandlerTest::linkPreviewsReject()
|
||||
QCOMPARE(testTextHandler.getLinkPreviews(), testOutputLinks);
|
||||
}
|
||||
|
||||
void TextHandlerTest::receiveRichCodeUrl()
|
||||
{
|
||||
auto input = QStringLiteral("<code>https://kde.org</code>");
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(input);
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), input);
|
||||
}
|
||||
|
||||
QTEST_MAIN(TextHandlerTest)
|
||||
#include "texthandlertest.moc"
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
</provides>
|
||||
<name>NeoChat</name>
|
||||
<name xml:lang="ar">نيوتشات</name>
|
||||
<name xml:lang="ast">NeoChat</name>
|
||||
<name xml:lang="az">NeoChat</name>
|
||||
<name xml:lang="ca">NeoChat</name>
|
||||
<name xml:lang="ca-valencia">NeoChat</name>
|
||||
@@ -99,7 +98,7 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<p>NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p>
|
||||
<p xml:lang="ar">يهدف نيوتشات إلى أن يكون تطبيقًا كامل الميزات لمواصفات ماتركس. على هذا النحو يتم دعم كل شيء في المواصفات المستقرة الحالية مع الاستثناءات الملحوظة لـ VoIP والخيوط وبعض جوانب التشفير من طرف إلى طرف. هناك عدد قليل من الإغفالات الصغيرة الأخرى بسبب حقيقة أن مواصفات ماتركس تتطور باستمرار ، ولكن يبقى الهدف توفير الدعم النهائي للمواصفات بأكملها.</p>
|
||||
<p xml:lang="ca">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptatge d'extrem a extrem. Hi ha algunes altres omissions més petites a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu segueix sent proporcionar suport eventual per a tota l'especificació.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptació d'extrem a extrem. Hi ha algunes altres omissions més xicotetes a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu seguix sent proporcionar suport eventual per a tota l'especificació.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de VoIP, fils i alguns aspectes de l'encriptació d'extrem a extrem. Hi ha algunes altres omissions més xicotetes a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu seguix sent proporcionar suport eventual per a tota l'especificació.</p>
|
||||
<p xml:lang="en-GB">NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p>
|
||||
<p xml:lang="eo">NeoChat celas esti plene kapabla aplikaĵo por la Matrix-specifo. Kiel tia, ĉio en la nuna stabila specifo kun la rimarkindaj esceptoj de VoIP, fadenoj kaj kelkaj aspektoj de Fin-al-Fina Ĉifrado estas subtenataj. Estas kelkaj aliaj pli malgrandaj preterlasoj pro la fakto, ke la Matrix-speco konstante evoluas, sed la celo restas provizi finfine subtenon por la tuta specifaĵo.</p>
|
||||
<p xml:lang="es">NeoChat pretende ser una aplicación con todas las funciones para la especificación de Matrix. Como tal, admite todo en la especificación estable actual, con las notables excepciones de VoIP, subprocesos y algunas funciones de cifrado de extremo a extremo. Existen algunas omisiones menos importantes debido al hecho de que la especificación de Matrix está en constante evolución, pero el objetivo sigue siendo brindar compatibilidad final con toda la especificación.</p>
|
||||
@@ -284,7 +283,7 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<screenshot type="default">
|
||||
<image>https://cdn.kde.org/screenshots/neochat/application.png</image>
|
||||
</screenshot>
|
||||
<screenshot environment="windows">
|
||||
<screenshot x-kde-os="windows">
|
||||
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</image>
|
||||
<caption>Main view with room list, chat, and room information</caption>
|
||||
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
||||
@@ -311,7 +310,7 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<caption xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</caption>
|
||||
<caption xml:lang="x-test">xxMain view with room list, chat, and room informationxx</caption>
|
||||
</screenshot>
|
||||
<screenshot environment="windows">
|
||||
<screenshot x-kde-os="windows">
|
||||
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Login.png</image>
|
||||
<caption>Login screen</caption>
|
||||
<caption xml:lang="ar">شاشة الدخول</caption>
|
||||
@@ -343,8 +342,6 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<content_attribute id="social-chat">intense</content_attribute>
|
||||
</content_rating>
|
||||
<releases>
|
||||
<release version="23.08.3" date="2023-11-09"/>
|
||||
<release version="23.08.2" date="2023-10-12"/>
|
||||
<release version="23.08.0" date="2023-08-24">
|
||||
<url>https://kde.org/announcements/gear/23.08.0/#neochathttpsappskdeorgneochat</url>
|
||||
<description>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
Version=1.5
|
||||
Name=NeoChat
|
||||
Name[ar]=نيوتشات
|
||||
Name[ast]=NeoChat
|
||||
Name[az]=NeoChat
|
||||
Name[ca]=NeoChat
|
||||
Name[ca@valencia]=NeoChat
|
||||
|
||||
1182
po/ar/neochat.po
1182
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
4414
po/ast/neochat.po
4414
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
1185
po/az/neochat.po
1185
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1169
po/ca/neochat.po
1169
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1201
po/cs/neochat.po
1201
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1104
po/da/neochat.po
1104
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1199
po/de/neochat.po
1199
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1200
po/el/neochat.po
1200
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1194
po/en_GB/neochat.po
1194
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1139
po/eo/neochat.po
1139
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
1181
po/es/neochat.po
1181
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1164
po/eu/neochat.po
1164
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1426
po/fi/neochat.po
1426
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1330
po/fr/neochat.po
1330
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1208
po/hu/neochat.po
1208
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1168
po/ia/neochat.po
1168
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1198
po/id/neochat.po
1198
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1166
po/ie/neochat.po
1166
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1219
po/it/neochat.po
1219
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1075
po/ja/neochat.po
1075
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1158
po/ka/neochat.po
1158
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1512
po/ko/neochat.po
1512
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1075
po/lt/neochat.po
1075
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
1177
po/nl/neochat.po
1177
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
1180
po/nn/neochat.po
1180
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1176
po/pa/neochat.po
1176
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
1164
po/pl/neochat.po
1164
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1192
po/pt/neochat.po
1192
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
1188
po/pt_BR/neochat.po
1188
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
1206
po/ru/neochat.po
1206
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1182
po/sk/neochat.po
1182
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
1189
po/sl/neochat.po
1189
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
1216
po/sv/neochat.po
1216
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1301
po/ta/neochat.po
1301
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1096
po/tok/neochat.po
1096
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
1187
po/tr/neochat.po
1187
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
1176
po/uk/neochat.po
1176
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
1239
po/zh_CN/neochat.po
1239
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
1075
po/zh_TW/neochat.po
1075
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -135,10 +135,6 @@ add_library(neochat STATIC
|
||||
enums/delegatetype.h
|
||||
roomlastmessageprovider.cpp
|
||||
roomlastmessageprovider.h
|
||||
chatbarcache.cpp
|
||||
chatbarcache.h
|
||||
colorschemer.cpp
|
||||
colorschemer.h
|
||||
)
|
||||
|
||||
qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
@@ -146,31 +142,30 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
qml/main.qml
|
||||
qml/AccountMenu.qml
|
||||
qml/ExploreComponent.qml
|
||||
qml/ExploreComponentMobile.qml
|
||||
qml/ContextMenu.qml
|
||||
qml/CollapsedRoomDelegate.qml
|
||||
qml/RoomDelegate.qml
|
||||
qml/RoomListPage.qml
|
||||
qml/SpaceListContextMenu.qml
|
||||
qml/UserInfo.qml
|
||||
qml/UserInfoDesktop.qml
|
||||
qml/LoadingPage.qml
|
||||
qml/RoomPage.qml
|
||||
qml/RoomWindow.qml
|
||||
qml/JoinRoomPage.qml
|
||||
qml/ManualRoomDialog.qml
|
||||
qml/ExplorerDelegate.qml
|
||||
qml/InviteUserPage.qml
|
||||
qml/StartChatPage.qml
|
||||
qml/ImageEditorPage.qml
|
||||
qml/WelcomePage.qml
|
||||
qml/General.qml
|
||||
qml/RoomSecurity.qml
|
||||
qml/Security.qml
|
||||
qml/PushNotification.qml
|
||||
qml/Categories.qml
|
||||
qml/Permissions.qml
|
||||
qml/NeochatMaximizeComponent.qml
|
||||
qml/FancyEffectsContainer.qml
|
||||
qml/TypingPane.qml
|
||||
qml/ShimmerGradient.qml
|
||||
qml/QuickSwitcher.qml
|
||||
qml/HoverActions.qml
|
||||
qml/ChatBox.qml
|
||||
@@ -286,10 +281,6 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
qml/SpaceHomePage.qml
|
||||
qml/SpaceHierarchyDelegate.qml
|
||||
qml/RemoveChildDialog.qml
|
||||
qml/SelectParentDialog.qml
|
||||
qml/Security.qml
|
||||
qml/QrCodeMaximizeComponent.qml
|
||||
qml/SelectSpacesDialog.qml
|
||||
RESOURCES
|
||||
qml/confetti.png
|
||||
qml/glowdot.png
|
||||
@@ -311,13 +302,6 @@ ecm_qt_declare_logging_category(neochat
|
||||
DEFAULT_SEVERITY Info
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(neochat
|
||||
HEADER "chatdocumenthandler_logging.h"
|
||||
IDENTIFIER "ChatDocumentHandling"
|
||||
CATEGORY_NAME "org.kde.neochat.chatdocumenthandler"
|
||||
DEFAULT_SEVERITY Info
|
||||
)
|
||||
|
||||
add_executable(neochat-app
|
||||
main.cpp
|
||||
)
|
||||
@@ -338,13 +322,15 @@ ecm_add_app_icon(NEOCHAT_ICON ICONS ${CMAKE_SOURCE_DIR}/128-logo.png)
|
||||
target_sources(neochat-app PRIVATE ${NEOCHAT_ICON})
|
||||
|
||||
if(NOT ANDROID)
|
||||
target_sources(neochat PRIVATE colorschemer.cpp colorschemer.h)
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h)
|
||||
target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem)
|
||||
else()
|
||||
target_sources(neochat PRIVATE trayicon.cpp trayicon.h)
|
||||
endif()
|
||||
target_link_libraries(neochat PUBLIC KF6::WindowSystem ICU::uc)
|
||||
target_link_libraries(neochat PUBLIC KF6::ConfigWidgets KF6::WindowSystem ICU::uc)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_COLORSCHEME)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_WINDOWSYSTEM)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_ICU)
|
||||
endif()
|
||||
@@ -356,27 +342,7 @@ if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||
endif()
|
||||
|
||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
|
||||
target_link_libraries(neochat PUBLIC
|
||||
Qt::Core
|
||||
Qt::Quick
|
||||
Qt::Qml
|
||||
Qt::Gui
|
||||
Qt::Multimedia
|
||||
Qt::Network
|
||||
Qt::QuickControls2
|
||||
KF6::I18n
|
||||
KF6::Kirigami2
|
||||
KF6::Notifications
|
||||
KF6::ConfigCore
|
||||
KF6::ConfigGui
|
||||
KF6::CoreAddons
|
||||
KF6::SonnetCore
|
||||
KF6::ColorScheme
|
||||
KF6::ItemModels
|
||||
QuotientQt6
|
||||
cmark::cmark
|
||||
QCoro::Core
|
||||
)
|
||||
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF6::I18n KF6::Kirigami2 KF6::Notifications KF6::ConfigCore KF6::ConfigGui KF6::CoreAddons KF6::SonnetCore KF6::ItemModels QuotientQt6 cmark::cmark QCoro::Core)
|
||||
|
||||
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
||||
|
||||
@@ -462,9 +428,7 @@ if(ANDROID)
|
||||
"preferences-desktop-notification"
|
||||
"computer-symbolic"
|
||||
"gps"
|
||||
"system-users-symbolic"
|
||||
)
|
||||
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR/android})
|
||||
else()
|
||||
target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets)
|
||||
install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
|
||||
|
||||
@@ -38,33 +38,45 @@ void ActionsHandler::setRoom(NeoChatRoom *room)
|
||||
Q_EMIT roomChanged();
|
||||
}
|
||||
|
||||
void ActionsHandler::handleMessageEvent(ChatBarCache *chatBarCache)
|
||||
void ActionsHandler::handleNewMessage()
|
||||
{
|
||||
if (!chatBarCache) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkEffects(chatBarCache->text());
|
||||
if (!chatBarCache->attachmentPath().isEmpty()) {
|
||||
QUrl url(chatBarCache->attachmentPath());
|
||||
checkEffects(m_room->chatBoxText());
|
||||
if (!m_room->chatBoxAttachmentPath().isEmpty()) {
|
||||
QUrl url(m_room->chatBoxAttachmentPath());
|
||||
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
||||
m_room->uploadFile(QUrl(path), chatBarCache->text().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : chatBarCache->text());
|
||||
chatBarCache->setAttachmentPath({});
|
||||
chatBarCache->setText({});
|
||||
m_room->uploadFile(QUrl(path), m_room->chatBoxText().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : m_room->chatBoxText());
|
||||
m_room->setChatBoxAttachmentPath({});
|
||||
m_room->setChatBoxText({});
|
||||
return;
|
||||
}
|
||||
|
||||
QString handledText = chatBarCache->text();
|
||||
handledText = handleMentions(handledText, chatBarCache->mentions());
|
||||
handleMessage(m_room->mainCache()->text(), handledText, chatBarCache);
|
||||
QString handledText = m_room->chatBoxText();
|
||||
handledText = handleMentions(handledText);
|
||||
handleMessage(m_room->chatBoxText(), handledText);
|
||||
}
|
||||
|
||||
QString ActionsHandler::handleMentions(QString handledText, QList<Mention> *mentions)
|
||||
void ActionsHandler::handleEdit()
|
||||
{
|
||||
checkEffects(m_room->editText());
|
||||
|
||||
QString handledText = m_room->editText();
|
||||
handledText = handleMentions(handledText, true);
|
||||
handleMessage(m_room->editText(), handledText, true);
|
||||
}
|
||||
|
||||
QString ActionsHandler::handleMentions(QString handledText, const bool &isEdit)
|
||||
{
|
||||
if (!m_room) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QVector<Mention> *mentions;
|
||||
if (isEdit) {
|
||||
mentions = m_room->editMentions();
|
||||
} else {
|
||||
mentions = m_room->mentions();
|
||||
}
|
||||
|
||||
std::sort(mentions->begin(), mentions->end(), [](const auto &a, const auto &b) -> bool {
|
||||
return a.cursor.anchor() > b.cursor.anchor();
|
||||
});
|
||||
@@ -75,14 +87,14 @@ QString ActionsHandler::handleMentions(QString handledText, QList<Mention> *ment
|
||||
}
|
||||
handledText = handledText.replace(mention.cursor.anchor(),
|
||||
mention.cursor.position() - mention.cursor.anchor(),
|
||||
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text.toHtmlEscaped(), mention.id));
|
||||
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text, mention.id));
|
||||
}
|
||||
mentions->clear();
|
||||
|
||||
return handledText;
|
||||
}
|
||||
|
||||
void ActionsHandler::handleMessage(const QString &text, QString handledText, ChatBarCache *chatBarCache)
|
||||
void ActionsHandler::handleMessage(const QString &text, QString handledText, const bool &isEdit)
|
||||
{
|
||||
if (NeoChatConfig::allowQuickEdit()) {
|
||||
QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$"));
|
||||
@@ -122,7 +134,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
|
||||
for (const auto &action : ActionsModel::instance().allActions()) {
|
||||
if (handledText.indexOf(action.prefix) == 1
|
||||
&& (handledText.indexOf(" "_ls) == action.prefix.length() + 1 || handledText.length() == action.prefix.length() + 1)) {
|
||||
handledText = action.handle(handledText.mid(action.prefix.length() + 1).trimmed(), m_room, chatBarCache);
|
||||
handledText = action.handle(handledText.mid(action.prefix.length() + 1).trimmed(), m_room);
|
||||
if (action.messageType.has_value()) {
|
||||
messageType = *action.messageType;
|
||||
}
|
||||
@@ -149,7 +161,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
|
||||
return;
|
||||
}
|
||||
|
||||
m_room->postMessage(text, handledText, messageType, chatBarCache->replyId(), chatBarCache->editId(), chatBarCache->threadId());
|
||||
m_room->postMessage(text, handledText, messageType, m_room->chatBoxReplyId(), isEdit ? m_room->chatBoxEditId() : QString());
|
||||
}
|
||||
|
||||
void ActionsHandler::checkEffects(const QString &text)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
class NeoChatRoom;
|
||||
@@ -52,15 +51,21 @@ Q_SIGNALS:
|
||||
void showEffect(const QString &effect);
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
/**
|
||||
* @brief Pre-process text and send message event.
|
||||
* @brief Pre-process text and send message.
|
||||
*/
|
||||
void handleMessageEvent(ChatBarCache *chatBarCache);
|
||||
void handleNewMessage();
|
||||
|
||||
/**
|
||||
* @brief Pre-process text and send edit.
|
||||
*/
|
||||
void handleEdit();
|
||||
|
||||
private:
|
||||
NeoChatRoom *m_room = nullptr;
|
||||
void checkEffects(const QString &text);
|
||||
|
||||
QString handleMentions(QString handledText, QList<Mention> *mentions);
|
||||
void handleMessage(const QString &text, QString handledText, ChatBarCache *chatBarCache);
|
||||
QString handleMentions(QString handledText, const bool &isEdit = false);
|
||||
void handleMessage(const QString &text, QString handledText, const bool &isEdit = false);
|
||||
};
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "chatbarcache.h"
|
||||
|
||||
#include "eventhandler.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
ChatBarCache::ChatBarCache(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QString ChatBarCache::text() const
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
||||
void ChatBarCache::setText(const QString &text)
|
||||
{
|
||||
if (text == m_text) {
|
||||
return;
|
||||
}
|
||||
m_text = text;
|
||||
Q_EMIT textChanged();
|
||||
}
|
||||
|
||||
bool ChatBarCache::isReplying() const
|
||||
{
|
||||
return m_relationType == Reply && !m_relationId.isEmpty();
|
||||
}
|
||||
|
||||
QString ChatBarCache::replyId() const
|
||||
{
|
||||
if (m_relationType != Reply) {
|
||||
return {};
|
||||
}
|
||||
return m_relationId;
|
||||
}
|
||||
|
||||
void ChatBarCache::setReplyId(const QString &replyId)
|
||||
{
|
||||
if (m_relationType == Reply && m_relationId == replyId) {
|
||||
return;
|
||||
}
|
||||
m_relationId = replyId;
|
||||
if (m_relationId.isEmpty()) {
|
||||
m_relationType = None;
|
||||
} else {
|
||||
m_relationType = Reply;
|
||||
}
|
||||
m_attachmentPath = QString();
|
||||
Q_EMIT relationIdChanged();
|
||||
Q_EMIT attachmentPathChanged();
|
||||
}
|
||||
|
||||
bool ChatBarCache::isEditing() const
|
||||
{
|
||||
return m_relationType == Edit && !m_relationId.isEmpty();
|
||||
}
|
||||
|
||||
QString ChatBarCache::editId() const
|
||||
{
|
||||
if (m_relationType != Edit) {
|
||||
return {};
|
||||
}
|
||||
return m_relationId;
|
||||
}
|
||||
|
||||
void ChatBarCache::setEditId(const QString &editId)
|
||||
{
|
||||
if (m_relationType == Edit && m_relationId == editId) {
|
||||
return;
|
||||
}
|
||||
m_relationId = editId;
|
||||
if (m_relationId.isEmpty()) {
|
||||
m_relationType = None;
|
||||
} else {
|
||||
m_relationType = Edit;
|
||||
}
|
||||
m_attachmentPath = QString();
|
||||
Q_EMIT relationIdChanged();
|
||||
Q_EMIT attachmentPathChanged();
|
||||
}
|
||||
|
||||
QVariantMap ChatBarCache::relationUser() const
|
||||
{
|
||||
if (parent() == nullptr) {
|
||||
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
|
||||
return {};
|
||||
}
|
||||
auto room = dynamic_cast<NeoChatRoom *>(parent());
|
||||
if (room == nullptr) {
|
||||
qWarning() << "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.";
|
||||
return {};
|
||||
}
|
||||
if (m_relationId.isEmpty()) {
|
||||
return room->getUser(nullptr);
|
||||
}
|
||||
return room->getUser(room->user((*room->findInTimeline(m_relationId))->senderId()));
|
||||
}
|
||||
|
||||
QString ChatBarCache::relationMessage() const
|
||||
{
|
||||
if (parent() == nullptr) {
|
||||
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
|
||||
return {};
|
||||
}
|
||||
if (m_relationId.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
auto room = dynamic_cast<NeoChatRoom *>(parent());
|
||||
if (room == nullptr) {
|
||||
qWarning() << "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.";
|
||||
return {};
|
||||
}
|
||||
EventHandler eventhandler;
|
||||
eventhandler.setRoom(room);
|
||||
if (auto event = room->findInTimeline(m_relationId); event != room->historyEdge()) {
|
||||
eventhandler.setEvent(&**event);
|
||||
return eventhandler.getPlainBody();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ChatBarCache::isThreaded() const
|
||||
{
|
||||
return !m_threadId.isEmpty();
|
||||
}
|
||||
|
||||
QString ChatBarCache::threadId() const
|
||||
{
|
||||
return m_threadId;
|
||||
}
|
||||
|
||||
void ChatBarCache::setThreadId(const QString &threadId)
|
||||
{
|
||||
if (m_threadId == threadId) {
|
||||
return;
|
||||
}
|
||||
m_threadId = threadId;
|
||||
Q_EMIT threadIdChanged();
|
||||
}
|
||||
|
||||
QString ChatBarCache::attachmentPath() const
|
||||
{
|
||||
return m_attachmentPath;
|
||||
}
|
||||
|
||||
void ChatBarCache::setAttachmentPath(const QString &attachmentPath)
|
||||
{
|
||||
if (attachmentPath == m_attachmentPath) {
|
||||
return;
|
||||
}
|
||||
m_attachmentPath = attachmentPath;
|
||||
m_relationType = None;
|
||||
m_relationId = QString();
|
||||
Q_EMIT attachmentPathChanged();
|
||||
Q_EMIT relationIdChanged();
|
||||
}
|
||||
|
||||
QList<Mention> *ChatBarCache::mentions()
|
||||
{
|
||||
return &m_mentions;
|
||||
}
|
||||
|
||||
QString ChatBarCache::savedText() const
|
||||
{
|
||||
return m_savedText;
|
||||
}
|
||||
|
||||
void ChatBarCache::setSavedText(const QString &savedText)
|
||||
{
|
||||
m_savedText = savedText;
|
||||
}
|
||||
|
||||
#include "moc_chatbarcache.cpp"
|
||||
@@ -1,201 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QTextCursor>
|
||||
|
||||
/**
|
||||
* @brief Defines a user mention in the current chat or edit text.
|
||||
*/
|
||||
struct Mention {
|
||||
QTextCursor cursor; /**< Contains the mention's text and position in the text. */
|
||||
QString text; /**< The inserted text of the mention. */
|
||||
int start = 0; /**< Start position of the mention. */
|
||||
int position = 0; /**< End position of the mention. */
|
||||
QString id; /**< The id the mention (used to create link when sending the message). */
|
||||
};
|
||||
|
||||
/**
|
||||
* @class ChatBarCache
|
||||
*
|
||||
* A class to cache data from a chat bar.
|
||||
*
|
||||
* A chat bar can be anything that allows users to compose or edit message, it doesn't
|
||||
* necessarily have to use the ChatBar component, e.g. MessageEditComponent.
|
||||
*
|
||||
* This object is intended to allow the current contents of a chat bar to be cached
|
||||
* between different rooms, i.e. there is an expectation that each NeoChatRoom could
|
||||
* have a separate cache for each chat bar.
|
||||
*
|
||||
* @note The NeoChatRoom which this component is created in is expected to be set
|
||||
* as it's parent. This is necessary for certain functions which need to get
|
||||
* relevant room information.
|
||||
*
|
||||
* @sa ChatBar, MessageEditComponent, NeoChatRoom
|
||||
*/
|
||||
class ChatBarCache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE("")
|
||||
|
||||
/**
|
||||
* @brief The text in the chat bar.
|
||||
*
|
||||
* Due to problems with QTextDocument, unlike the other properties here,
|
||||
* text is *not* used to store the text when switching rooms.
|
||||
*/
|
||||
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether the chat bar is currently replying to a message.
|
||||
*/
|
||||
Q_PROPERTY(bool isReplying READ isReplying NOTIFY relationIdChanged)
|
||||
|
||||
/**
|
||||
* @brief The Matrix message ID of an event being replied to, if any.
|
||||
*
|
||||
* Will return empty if the RelationType is currently set to None or Edit.
|
||||
*
|
||||
* @note Replying, editing and attachments are exclusive so setting this will
|
||||
* clear an edit or attachment.
|
||||
*
|
||||
* @sa RelationType
|
||||
*/
|
||||
Q_PROPERTY(QString replyId READ replyId WRITE setReplyId NOTIFY relationIdChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether the chat bar is currently editing a message.
|
||||
*/
|
||||
Q_PROPERTY(bool isEditing READ isEditing NOTIFY relationIdChanged)
|
||||
|
||||
/**
|
||||
* @brief The Matrix message ID of an event being edited, if any.
|
||||
*
|
||||
* Will return empty if the RelationType is currently set to None or Reply.
|
||||
*
|
||||
* @note Replying, editing and attachments are exclusive so setting this will
|
||||
* clear an reply or attachment.
|
||||
*
|
||||
* @sa RelationType
|
||||
*/
|
||||
Q_PROPERTY(QString editId READ editId WRITE setEditId NOTIFY relationIdChanged)
|
||||
|
||||
/**
|
||||
* @brief Get the user for the message being replied to.
|
||||
*
|
||||
* This is different to getting a Quotient::User object
|
||||
* as neither of those can provide details like the displayName or avatarMediaId
|
||||
* without the room context as these can vary from room to room.
|
||||
*
|
||||
* Returns an empty 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(QVariantMap relationUser READ relationUser NOTIFY relationIdChanged)
|
||||
|
||||
/**
|
||||
* @brief The content of the related message.
|
||||
*
|
||||
* Will be QString() if no related message.
|
||||
*/
|
||||
Q_PROPERTY(QString relationMessage READ relationMessage NOTIFY relationIdChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether the chat bar is replying in a thread.
|
||||
*/
|
||||
Q_PROPERTY(bool isThreaded READ isThreaded NOTIFY threadIdChanged)
|
||||
|
||||
/**
|
||||
* @brief The Matrix message ID of thread root event, if any.
|
||||
*/
|
||||
Q_PROPERTY(QString threadId READ threadId WRITE setThreadId NOTIFY threadIdChanged)
|
||||
|
||||
/**
|
||||
* @brief The local path for a file to send, if any.
|
||||
*
|
||||
* @note Replying, editing and attachments are exclusive so setting this will
|
||||
* clear an edit or reply.
|
||||
*/
|
||||
Q_PROPERTY(QString attachmentPath READ attachmentPath WRITE setAttachmentPath NOTIFY attachmentPathChanged)
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Describes the type of relation which relationId can refer to.
|
||||
*
|
||||
* A chat bar can only be relating to a single message at a time making these
|
||||
* exclusive.
|
||||
*/
|
||||
enum RelationType {
|
||||
Reply, /**< The current relation is a message being replied to. */
|
||||
Edit, /**< The current relation is a message being edited. */
|
||||
None, /**< There is currently no relation event */
|
||||
};
|
||||
Q_ENUM(RelationType)
|
||||
|
||||
explicit ChatBarCache(QObject *parent = nullptr);
|
||||
|
||||
QString text() const;
|
||||
void setText(const QString &text);
|
||||
|
||||
bool isReplying() const;
|
||||
QString replyId() const;
|
||||
void setReplyId(const QString &replyId);
|
||||
|
||||
bool isEditing() const;
|
||||
QString editId() const;
|
||||
void setEditId(const QString &editId);
|
||||
|
||||
QVariantMap relationUser() const;
|
||||
|
||||
QString relationMessage() const;
|
||||
|
||||
bool isThreaded() const;
|
||||
QString threadId() const;
|
||||
void setThreadId(const QString &threadId);
|
||||
|
||||
QString attachmentPath() const;
|
||||
void setAttachmentPath(const QString &attachmentPath);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the mentions for the current chat bar text.
|
||||
*/
|
||||
QList<Mention> *mentions();
|
||||
|
||||
/**
|
||||
* @brief Get the saved chat bar text.
|
||||
*/
|
||||
QString savedText() const;
|
||||
|
||||
/**
|
||||
* @brief Save the chat bar text.
|
||||
*/
|
||||
void setSavedText(const QString &savedText);
|
||||
|
||||
Q_SIGNALS:
|
||||
void textChanged();
|
||||
void relationIdChanged();
|
||||
void threadIdChanged();
|
||||
void attachmentPathChanged();
|
||||
|
||||
private:
|
||||
QString m_text = QString();
|
||||
QString m_relationId = QString();
|
||||
RelationType m_relationType = RelationType::None;
|
||||
QString m_threadId = QString();
|
||||
QString m_attachmentPath = QString();
|
||||
QList<Mention> m_mentions;
|
||||
QString m_savedText;
|
||||
};
|
||||
@@ -14,8 +14,6 @@
|
||||
#include <Sonnet/BackgroundChecker>
|
||||
#include <Sonnet/Settings>
|
||||
|
||||
#include "chatdocumenthandler_logging.h"
|
||||
|
||||
class SyntaxHighlighter : public QSyntaxHighlighter
|
||||
{
|
||||
public:
|
||||
@@ -59,12 +57,11 @@ public:
|
||||
setFormat(error.first, error.second.size(), errorFormat);
|
||||
}
|
||||
}
|
||||
auto handler = dynamic_cast<ChatDocumentHandler *>(parent());
|
||||
auto room = handler->room();
|
||||
auto room = dynamic_cast<ChatDocumentHandler *>(parent())->room();
|
||||
if (!room) {
|
||||
return;
|
||||
}
|
||||
auto mentions = handler->chatBarCache()->mentions();
|
||||
auto mentions = room->mentions();
|
||||
mentions->erase(std::remove_if(mentions->begin(),
|
||||
mentions->end(),
|
||||
[this](auto &mention) {
|
||||
@@ -100,16 +97,21 @@ ChatDocumentHandler::ChatDocumentHandler(QObject *parent)
|
||||
, m_document(nullptr)
|
||||
, m_cursorPosition(-1)
|
||||
, m_highlighter(new SyntaxHighlighter(this))
|
||||
, m_completionModel(new CompletionModel(this))
|
||||
, m_completionModel(new CompletionModel())
|
||||
{
|
||||
connect(this, &ChatDocumentHandler::roomChanged, this, [this]() {
|
||||
m_completionModel->setRoom(m_room);
|
||||
static QPointer<NeoChatRoom> previousRoom = nullptr;
|
||||
if (previousRoom) {
|
||||
disconnect(m_chatBarCache, &ChatBarCache::textChanged, this, nullptr);
|
||||
disconnect(previousRoom, &NeoChatRoom::chatBoxTextChanged, this, nullptr);
|
||||
disconnect(previousRoom, &NeoChatRoom::editTextChanged, this, nullptr);
|
||||
}
|
||||
previousRoom = m_room;
|
||||
connect(m_chatBarCache, &ChatBarCache::textChanged, this, [this]() {
|
||||
connect(m_room, &NeoChatRoom::chatBoxTextChanged, this, [this]() {
|
||||
int start = completionStartIndex();
|
||||
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
|
||||
});
|
||||
connect(m_room, &NeoChatRoom::editTextChanged, this, [this]() {
|
||||
int start = completionStartIndex();
|
||||
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
|
||||
});
|
||||
@@ -150,6 +152,20 @@ int ChatDocumentHandler::completionStartIndex() const
|
||||
return start;
|
||||
}
|
||||
|
||||
bool ChatDocumentHandler::isEdit() const
|
||||
{
|
||||
return m_isEdit;
|
||||
}
|
||||
|
||||
void ChatDocumentHandler::setIsEdit(bool edit)
|
||||
{
|
||||
if (edit == m_isEdit) {
|
||||
return;
|
||||
}
|
||||
m_isEdit = edit;
|
||||
Q_EMIT isEditChanged();
|
||||
}
|
||||
|
||||
QQuickTextDocument *ChatDocumentHandler::document() const
|
||||
{
|
||||
return m_document;
|
||||
@@ -199,31 +215,8 @@ void ChatDocumentHandler::setRoom(NeoChatRoom *room)
|
||||
Q_EMIT roomChanged();
|
||||
}
|
||||
|
||||
ChatBarCache *ChatDocumentHandler::chatBarCache() const
|
||||
{
|
||||
return m_chatBarCache;
|
||||
}
|
||||
|
||||
void ChatDocumentHandler::setChatBarCache(ChatBarCache *chatBarCache)
|
||||
{
|
||||
if (m_chatBarCache == chatBarCache) {
|
||||
return;
|
||||
}
|
||||
m_chatBarCache = chatBarCache;
|
||||
Q_EMIT chatBarCacheChanged();
|
||||
}
|
||||
|
||||
void ChatDocumentHandler::complete(int index)
|
||||
{
|
||||
if (m_document == nullptr) {
|
||||
qCWarning(ChatDocumentHandling) << "complete called with m_document set to nullptr.";
|
||||
return;
|
||||
}
|
||||
if (m_completionModel->autoCompletionType() == CompletionModel::None) {
|
||||
qCWarning(ChatDocumentHandling) << "complete called with m_completionModel->autoCompletionType() == CompletionModel::None.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_completionModel->autoCompletionType() == CompletionModel::User) {
|
||||
auto name = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::DisplayNameRole).toString();
|
||||
auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::SubtitleRole).toString();
|
||||
@@ -307,20 +300,26 @@ void ChatDocumentHandler::setSelectionEnd(int position)
|
||||
|
||||
QString ChatDocumentHandler::getText() const
|
||||
{
|
||||
if (!m_chatBarCache) {
|
||||
qCWarning(ChatDocumentHandling) << "getText called with m_chatBarCache set to nullptr.";
|
||||
return {};
|
||||
if (!m_room) {
|
||||
return QString();
|
||||
}
|
||||
if (m_isEdit) {
|
||||
return m_room->editText();
|
||||
} else {
|
||||
return m_room->chatBoxText();
|
||||
}
|
||||
return m_chatBarCache->text();
|
||||
}
|
||||
|
||||
void ChatDocumentHandler::pushMention(const Mention mention) const
|
||||
{
|
||||
if (!m_chatBarCache) {
|
||||
qCWarning(ChatDocumentHandling) << "pushMention called with m_chatBarCache set to nullptr.";
|
||||
if (!m_room) {
|
||||
return;
|
||||
}
|
||||
m_chatBarCache->mentions()->push_back(mention);
|
||||
if (m_isEdit) {
|
||||
m_room->editMentions()->push_back(mention);
|
||||
} else {
|
||||
m_room->mentions()->push_back(mention);
|
||||
}
|
||||
}
|
||||
|
||||
QColor ChatDocumentHandler::mentionColor() const
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <QQuickTextDocument>
|
||||
#include <QTextCursor>
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "models/completionmodel.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
@@ -62,6 +61,14 @@ class ChatDocumentHandler : public QObject
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
/**
|
||||
* @brief Is the instance being used to handle an edit message.
|
||||
*
|
||||
* This is needed to ensure that the text and mentions are saved and retrieved
|
||||
* from the correct parameters in the assigned room.
|
||||
*/
|
||||
Q_PROPERTY(bool isEdit READ isEdit WRITE setIsEdit NOTIFY isEditChanged)
|
||||
|
||||
/**
|
||||
* @brief The QQuickTextDocument that is being handled.
|
||||
*/
|
||||
@@ -88,18 +95,13 @@ class ChatDocumentHandler : public QObject
|
||||
* This is typically provided to a qml component to visualise the current
|
||||
* completion results.
|
||||
*/
|
||||
Q_PROPERTY(CompletionModel *completionModel READ completionModel CONSTANT)
|
||||
Q_PROPERTY(CompletionModel *completionModel READ completionModel NOTIFY completionModelChanged)
|
||||
|
||||
/**
|
||||
* @brief The current room that the the text document is being handled for.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
|
||||
|
||||
/**
|
||||
* @brief The cache for the chat bar the text document is being handled for.
|
||||
*/
|
||||
Q_PROPERTY(ChatBarCache *chatBarCache READ chatBarCache WRITE setChatBarCache NOTIFY chatBarCacheChanged)
|
||||
|
||||
/**
|
||||
* @brief The color to highlight user mentions.
|
||||
*/
|
||||
@@ -113,6 +115,9 @@ class ChatDocumentHandler : public QObject
|
||||
public:
|
||||
explicit ChatDocumentHandler(QObject *parent = nullptr);
|
||||
|
||||
[[nodiscard]] bool isEdit() const;
|
||||
void setIsEdit(bool edit);
|
||||
|
||||
[[nodiscard]] QQuickTextDocument *document() const;
|
||||
void setDocument(QQuickTextDocument *document);
|
||||
|
||||
@@ -128,11 +133,9 @@ public:
|
||||
[[nodiscard]] NeoChatRoom *room() const;
|
||||
void setRoom(NeoChatRoom *room);
|
||||
|
||||
[[nodiscard]] ChatBarCache *chatBarCache() const;
|
||||
void setChatBarCache(ChatBarCache *chatBarCache);
|
||||
|
||||
Q_INVOKABLE void complete(int index);
|
||||
|
||||
void updateCompletions();
|
||||
CompletionModel *completionModel() const;
|
||||
|
||||
[[nodiscard]] QColor mentionColor() const;
|
||||
@@ -142,10 +145,11 @@ public:
|
||||
void setErrorColor(const QColor &color);
|
||||
|
||||
Q_SIGNALS:
|
||||
void isEditChanged();
|
||||
void documentChanged();
|
||||
void cursorPositionChanged();
|
||||
void roomChanged();
|
||||
void chatBarCacheChanged();
|
||||
void completionModelChanged();
|
||||
void selectionStartChanged();
|
||||
void selectionEndChanged();
|
||||
void errorColorChanged();
|
||||
@@ -154,10 +158,11 @@ Q_SIGNALS:
|
||||
private:
|
||||
int completionStartIndex() const;
|
||||
|
||||
bool m_isEdit = false;
|
||||
|
||||
QPointer<QQuickTextDocument> m_document;
|
||||
|
||||
QPointer<NeoChatRoom> m_room;
|
||||
QPointer<ChatBarCache> m_chatBarCache;
|
||||
bool completionVisible = false;
|
||||
|
||||
QColor m_mentionColor;
|
||||
|
||||
@@ -6,8 +6,13 @@
|
||||
|
||||
#include <qt6keychain/keychain.h>
|
||||
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
#include <KLocalizedString>
|
||||
#include <KWindowConfig>
|
||||
#ifdef HAVE_WINDOWSYSTEM
|
||||
#include <KWindowEffects>
|
||||
#endif
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
@@ -60,8 +65,7 @@ Controller::Controller(QObject *parent)
|
||||
invokeLogin();
|
||||
});
|
||||
|
||||
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [this] {
|
||||
delete m_trayIcon;
|
||||
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [] {
|
||||
NeoChatConfig::self()->save();
|
||||
});
|
||||
|
||||
@@ -99,6 +103,10 @@ Controller::Controller(QObject *parent)
|
||||
}
|
||||
oldAccountCount = m_accountRegistry.size();
|
||||
});
|
||||
|
||||
QTimer::singleShot(0, this, [this] {
|
||||
m_pushRuleModel = new PushRuleModel;
|
||||
});
|
||||
}
|
||||
|
||||
Controller &Controller::instance()
|
||||
@@ -167,8 +175,6 @@ void Controller::invokeLogin()
|
||||
QString id = NeoChatConfig::self()->activeConnection();
|
||||
for (const auto &accountId : accounts) {
|
||||
AccountSettings account{accountId};
|
||||
m_accountsLoading += accountId;
|
||||
Q_EMIT accountsLoadingChanged();
|
||||
if (id.isEmpty()) {
|
||||
// handle case where the account config is empty
|
||||
id = accountId;
|
||||
@@ -188,8 +194,6 @@ void Controller::invokeLogin()
|
||||
connect(connection, &NeoChatConnection::connected, this, [this, connection, id] {
|
||||
connection->loadState();
|
||||
addConnection(connection);
|
||||
m_accountsLoading.removeAll(connection->userId());
|
||||
Q_EMIT accountsLoadingChanged();
|
||||
if (connection->userId() == id) {
|
||||
setActiveConnection(connection);
|
||||
connectSingleShot(connection, &NeoChatConnection::syncDone, this, &Controller::initiated);
|
||||
@@ -350,6 +354,12 @@ void Controller::setActiveConnection(NeoChatConnection *connection)
|
||||
}
|
||||
NeoChatConfig::self()->save();
|
||||
Q_EMIT activeConnectionChanged();
|
||||
Q_EMIT activeConnectionIndexChanged();
|
||||
}
|
||||
|
||||
PushRuleModel *Controller::pushRuleModel() const
|
||||
{
|
||||
return m_pushRuleModel;
|
||||
}
|
||||
|
||||
void Controller::saveWindowGeometry()
|
||||
@@ -374,6 +384,56 @@ void Controller::joinRoom(const QString &alias)
|
||||
RoomManager::instance().joinRoom(m_connection, alias, QStringList{knownServer});
|
||||
}
|
||||
|
||||
void Controller::openOrCreateDirectChat(User *user)
|
||||
{
|
||||
const auto existing = activeConnection()->directChats();
|
||||
|
||||
if (existing.contains(user)) {
|
||||
const auto &room = static_cast<NeoChatRoom *>(activeConnection()->room(existing.value(user)));
|
||||
if (room) {
|
||||
RoomManager::instance().enterRoom(room);
|
||||
return;
|
||||
}
|
||||
}
|
||||
activeConnection()->requestDirectChat(user);
|
||||
}
|
||||
|
||||
QString Controller::formatByteSize(double size, int precision) const
|
||||
{
|
||||
return QLocale().formattedDataSize(size, precision);
|
||||
}
|
||||
|
||||
QString Controller::formatDuration(quint64 msecs, KFormat::DurationFormatOptions options) const
|
||||
{
|
||||
return KFormat().formatDuration(msecs, options);
|
||||
}
|
||||
|
||||
void Controller::setBlur(QQuickItem *item, bool blur)
|
||||
{
|
||||
#ifdef HAVE_WINDOWSYSTEM
|
||||
auto setWindows = [item, blur]() {
|
||||
auto reg = QRect(QPoint(0, 0), item->window()->size());
|
||||
KWindowEffects::enableBackgroundContrast(item->window(), blur, 1, 1, 1, reg);
|
||||
KWindowEffects::enableBlurBehind(item->window(), blur, reg);
|
||||
};
|
||||
|
||||
disconnect(item->window(), &QQuickWindow::heightChanged, this, nullptr);
|
||||
disconnect(item->window(), &QQuickWindow::widthChanged, this, nullptr);
|
||||
connect(item->window(), &QQuickWindow::heightChanged, this, setWindows);
|
||||
connect(item->window(), &QQuickWindow::widthChanged, this, setWindows);
|
||||
setWindows();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Controller::hasWindowSystem() const
|
||||
{
|
||||
#ifdef HAVE_WINDOWSYSTEM
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Controller::forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item)
|
||||
{
|
||||
// HACK: Workaround bug QTBUG 93281
|
||||
@@ -410,6 +470,14 @@ void Controller::setApplicationProxy()
|
||||
QNetworkProxy::setApplicationProxy(proxy);
|
||||
}
|
||||
|
||||
int Controller::activeConnectionIndex() const
|
||||
{
|
||||
auto result = std::find_if(m_accountRegistry.accounts().begin(), m_accountRegistry.accounts().end(), [this](const auto &it) {
|
||||
return it == m_connection;
|
||||
});
|
||||
return result - m_accountRegistry.accounts().begin();
|
||||
}
|
||||
|
||||
bool Controller::isFlatpak() const
|
||||
{
|
||||
#ifdef NEOCHAT_FLATPAK
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "models/pushrulemodel.h"
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QQuickItem>
|
||||
|
||||
#include <KFormat>
|
||||
|
||||
#include "neochatconnection.h"
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
@@ -46,11 +49,26 @@ class Controller : public QObject
|
||||
*/
|
||||
Q_PROPERTY(NeoChatConnection *activeConnection READ activeConnection WRITE setActiveConnection NOTIFY activeConnectionChanged)
|
||||
|
||||
/**
|
||||
* @brief The PushRuleModel that has the active connection's push rules.
|
||||
*/
|
||||
Q_PROPERTY(PushRuleModel *pushRuleModel READ pushRuleModel CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief The row number in the accounts directory of the active connection.
|
||||
*/
|
||||
Q_PROPERTY(int activeConnectionIndex READ activeConnectionIndex NOTIFY activeConnectionIndexChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether the OS NeoChat is running on supports sytem tray icons.
|
||||
*/
|
||||
Q_PROPERTY(bool supportSystemTray READ supportSystemTray CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief Whether KWindowSystem specific features are available.
|
||||
*/
|
||||
Q_PROPERTY(bool hasWindowSystem READ hasWindowSystem CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief Whether NeoChat is currently able to connect to the server.
|
||||
*/
|
||||
@@ -63,8 +81,6 @@ class Controller : public QObject
|
||||
*/
|
||||
Q_PROPERTY(bool isFlatpak READ isFlatpak CONSTANT)
|
||||
|
||||
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Defines the status after an attempt to change the password on an account.
|
||||
@@ -86,6 +102,8 @@ public:
|
||||
void setActiveConnection(NeoChatConnection *connection);
|
||||
[[nodiscard]] NeoChatConnection *activeConnection() const;
|
||||
|
||||
[[nodiscard]] PushRuleModel *pushRuleModel() const;
|
||||
|
||||
/**
|
||||
* @brief Add a new connection to the account registry.
|
||||
*/
|
||||
@@ -96,6 +114,8 @@ public:
|
||||
*/
|
||||
void dropConnection(NeoChatConnection *c);
|
||||
|
||||
int activeConnectionIndex() const;
|
||||
|
||||
/**
|
||||
* @brief Save an access token to the keychain for the given account.
|
||||
*/
|
||||
@@ -106,8 +126,20 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void joinRoom(const QString &alias);
|
||||
|
||||
/**
|
||||
* @brief Join a direct chat with the given user.
|
||||
*
|
||||
* If a direct chat with the user doesn't exist one is created and then joined.
|
||||
*/
|
||||
Q_INVOKABLE void openOrCreateDirectChat(Quotient::User *user);
|
||||
|
||||
[[nodiscard]] bool supportSystemTray() const;
|
||||
|
||||
/**
|
||||
* @brief Set the background blur status of the given item.
|
||||
*/
|
||||
Q_INVOKABLE void setBlur(QQuickItem *item, bool blur);
|
||||
|
||||
bool isOnline() const;
|
||||
|
||||
/**
|
||||
@@ -119,6 +151,20 @@ public:
|
||||
|
||||
bool isFlatpak() const;
|
||||
|
||||
/**
|
||||
* @brief Return a string for the input timestamp.
|
||||
*
|
||||
* The output format depends on the KFormat::DurationFormatOptions chosen.
|
||||
*
|
||||
* @sa KFormat::DurationFormatOptions
|
||||
*/
|
||||
Q_INVOKABLE QString formatDuration(quint64 msecs, KFormat::DurationFormatOptions options = KFormat::DefaultDuration) const;
|
||||
|
||||
/**
|
||||
* @brief Return a human readable string for a given input number of bytes.
|
||||
*/
|
||||
Q_INVOKABLE QString formatByteSize(double size, int precision = 1) const;
|
||||
|
||||
/**
|
||||
* @brief Force a QQuickTextDocument to refresh when images are loaded.
|
||||
*
|
||||
@@ -141,8 +187,10 @@ private:
|
||||
bool m_isOnline = true;
|
||||
QMap<Quotient::Room *, int> m_notificationCounts;
|
||||
|
||||
bool hasWindowSystem() const;
|
||||
|
||||
QPointer<PushRuleModel> m_pushRuleModel;
|
||||
Quotient::AccountRegistry m_accountRegistry;
|
||||
QStringList m_accountsLoading;
|
||||
|
||||
private Q_SLOTS:
|
||||
void invokeLogin();
|
||||
@@ -165,7 +213,7 @@ Q_SIGNALS:
|
||||
void passwordStatus(Controller::PasswordStatus status);
|
||||
void userConsentRequired(QUrl url);
|
||||
void isOnlineChanged(bool isOnline);
|
||||
void accountsLoadingChanged();
|
||||
void activeConnectionIndexChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
void saveWindowGeometry();
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <Quotient/events/stickerevent.h>
|
||||
#include <Quotient/quotient_common.h>
|
||||
|
||||
#include "delegatetype.h"
|
||||
#include "eventhandler_logging.h"
|
||||
#include "events/pollevent.h"
|
||||
#include "linkpreviewer.h"
|
||||
@@ -51,10 +50,6 @@ const Quotient::Event *EventHandler::getEvent() const
|
||||
|
||||
void EventHandler::setEvent(const Quotient::RoomEvent *event)
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "cannot setEvent when m_room is set to nullptr.";
|
||||
return;
|
||||
}
|
||||
if (event == m_event) {
|
||||
return;
|
||||
}
|
||||
@@ -186,7 +181,7 @@ QDateTime EventHandler::getTime(bool isPending, QDateTime lastUpdated) const
|
||||
QString EventHandler::getTimeString(bool relative, QLocale::FormatType format, bool isPending, QDateTime lastUpdated) const
|
||||
{
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getTimeString called with m_event set to nullptr.";
|
||||
qCWarning(EventHandling) << "getTime called with m_event set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
if (isPending && lastUpdated == QDateTime()) {
|
||||
@@ -221,15 +216,6 @@ bool EventHandler::isHighlighted()
|
||||
|
||||
bool EventHandler::isHidden()
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "isHidden called with m_room set to nullptr.";
|
||||
return false;
|
||||
}
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "isHidden called with m_event set to nullptr.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_event->isStateEvent() && !NeoChatConfig::self()->showStateEvent()) {
|
||||
return true;
|
||||
}
|
||||
@@ -245,8 +231,11 @@ bool EventHandler::isHidden()
|
||||
}
|
||||
}
|
||||
|
||||
if (m_event->isStateEvent() && eventCast<const StateEvent>(m_event)->repeatsState()) {
|
||||
return true;
|
||||
if (m_event->isStateEvent()) {
|
||||
auto *stateEvent = eventCast<const StateEvent>(m_event);
|
||||
if (stateEvent && stateEvent->repeatsState()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// isReplacement?
|
||||
@@ -625,14 +614,6 @@ QString EventHandler::getGenericBody() const
|
||||
|
||||
QVariantMap EventHandler::getMediaInfo() const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getMediaInfo called with m_room set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getMediaInfo called with m_event set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
return getMediaInfoForEvent(m_event);
|
||||
}
|
||||
|
||||
@@ -745,14 +726,6 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const EventContent::FileInfo
|
||||
|
||||
QSharedPointer<LinkPreviewer> EventHandler::getLinkPreviewer() const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getLinkPreviewer called with m_room set to nullptr.";
|
||||
return nullptr;
|
||||
}
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getLinkPreviewer called with m_event set to nullptr.";
|
||||
return nullptr;
|
||||
}
|
||||
if (!m_event->is<RoomMessageEvent>()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -784,7 +757,7 @@ QSharedPointer<ReactionModel> EventHandler::getReactions() const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getReactions called with m_room set to nullptr.";
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getReactions called with m_event set to nullptr.";
|
||||
@@ -836,33 +809,16 @@ QSharedPointer<ReactionModel> EventHandler::getReactions() const
|
||||
|
||||
bool EventHandler::hasReply() const
|
||||
{
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "hasReply called with m_event set to nullptr.";
|
||||
return false;
|
||||
}
|
||||
return !m_event->contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString().isEmpty();
|
||||
}
|
||||
|
||||
QString EventHandler::getReplyId() const
|
||||
{
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getReplyId called with m_event set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
return m_event->contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString();
|
||||
}
|
||||
|
||||
DelegateType::Type EventHandler::getReplyDelegateType() const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getReplyDelegateType called with m_room set to nullptr.";
|
||||
return DelegateType::Other;
|
||||
}
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getReplyDelegateType called with m_event set to nullptr.";
|
||||
return DelegateType::Other;
|
||||
}
|
||||
|
||||
auto replyEvent = m_room->getReplyForEvent(*m_event);
|
||||
if (replyEvent == nullptr) {
|
||||
return DelegateType::Other;
|
||||
@@ -948,45 +904,8 @@ QVariantMap EventHandler::getReplyMediaInfo() const
|
||||
return getMediaInfoForEvent(replyPtr);
|
||||
}
|
||||
|
||||
bool EventHandler::isThreaded() const
|
||||
{
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "isThreaded called with m_event set to nullptr.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return (m_event->contentPart<QJsonObject>("m.relates_to"_ls).contains("rel_type"_ls)
|
||||
&& m_event->contentPart<QJsonObject>("m.relates_to"_ls)["rel_type"_ls].toString() == "m.thread"_ls)
|
||||
|| (!m_event->unsignedPart<QJsonObject>("m.relations"_ls).isEmpty() && m_event->unsignedPart<QJsonObject>("m.relations"_ls).contains("m.thread"_ls));
|
||||
}
|
||||
|
||||
QString EventHandler::threadRoot() const
|
||||
{
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "threadRoot called with m_event set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get the thread root ID from m.relates_to if it exists.
|
||||
if (m_event->contentPart<QJsonObject>("m.relates_to"_ls).contains("rel_type"_ls)
|
||||
&& m_event->contentPart<QJsonObject>("m.relates_to"_ls)["rel_type"_ls].toString() == "m.thread"_ls) {
|
||||
return m_event->contentPart<QJsonObject>("m.relates_to"_ls)["event_id"_ls].toString();
|
||||
}
|
||||
// For thread root events they have an m.relations in the unsigned part with a m.thread object.
|
||||
// If so return the event ID as it is the root.
|
||||
if (!m_event->unsignedPart<QJsonObject>("m.relations"_ls).isEmpty() && m_event->unsignedPart<QJsonObject>("m.relations"_ls).contains("m.thread"_ls)) {
|
||||
return getId();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
float EventHandler::getLatitude() const
|
||||
{
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getLatitude called with m_event set to nullptr.";
|
||||
return -100.0;
|
||||
}
|
||||
|
||||
const auto geoUri = m_event->contentJson()["geo_uri"_ls].toString();
|
||||
if (geoUri.isEmpty()) {
|
||||
return -100.0; // latitude runs from -90deg to +90deg so -100 is out of range.
|
||||
@@ -997,11 +916,6 @@ float EventHandler::getLatitude() const
|
||||
|
||||
float EventHandler::getLongitude() const
|
||||
{
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getLongitude called with m_event set to nullptr.";
|
||||
return -200.0;
|
||||
}
|
||||
|
||||
const auto geoUri = m_event->contentJson()["geo_uri"_ls].toString();
|
||||
if (geoUri.isEmpty()) {
|
||||
return -200.0; // longitude runs from -180deg to +180deg so -200 is out of range.
|
||||
@@ -1012,11 +926,6 @@ float EventHandler::getLongitude() const
|
||||
|
||||
QString EventHandler::getLocationAssetType() const
|
||||
{
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getLocationAssetType called with m_event set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto assetType = m_event->contentJson()["org.matrix.msc3488.asset"_ls].toObject()["type"_ls].toString();
|
||||
if (assetType.isEmpty()) {
|
||||
return {};
|
||||
@@ -1026,15 +935,6 @@ QString EventHandler::getLocationAssetType() const
|
||||
|
||||
bool EventHandler::hasReadMarkers() const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "hasReadMarkers called with m_room set to nullptr.";
|
||||
return false;
|
||||
}
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "hasReadMarkers called with m_event set to nullptr.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||
userIds.remove(m_room->localUser()->id());
|
||||
return userIds.size() > 0;
|
||||
@@ -1042,15 +942,6 @@ bool EventHandler::hasReadMarkers() const
|
||||
|
||||
QVariantList EventHandler::getReadMarkers(int maxMarkers) const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getReadMarkers called with m_room set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getReadMarkers called with m_event set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
|
||||
auto userIds_temp = m_room->userIdsAtEvent(m_event->id());
|
||||
userIds_temp.remove(m_room->localUser()->id());
|
||||
|
||||
@@ -1071,15 +962,6 @@ QVariantList EventHandler::getReadMarkers(int maxMarkers) const
|
||||
|
||||
QString EventHandler::getNumberExcessReadMarkers(int maxMarkers) const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getNumberExcessReadMarkers called with m_room set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getNumberExcessReadMarkers called with m_event set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
|
||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||
userIds.remove(m_room->localUser()->id());
|
||||
|
||||
@@ -1092,15 +974,6 @@ QString EventHandler::getNumberExcessReadMarkers(int maxMarkers) const
|
||||
|
||||
QString EventHandler::getReadMarkersString() const
|
||||
{
|
||||
if (m_room == nullptr) {
|
||||
qCWarning(EventHandling) << "getReadMarkersString called with m_room set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
if (m_event == nullptr) {
|
||||
qCWarning(EventHandling) << "getReadMarkersString called with m_event set to nullptr.";
|
||||
return {};
|
||||
}
|
||||
|
||||
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||
userIds.remove(m_room->localUser()->id());
|
||||
|
||||
|
||||
@@ -326,20 +326,6 @@ public:
|
||||
*/
|
||||
QVariantMap getReplyMediaInfo() const;
|
||||
|
||||
/**
|
||||
* @brief Whether the message is part of a thread.
|
||||
*
|
||||
* i.e. There is a rel_type of m.thread.
|
||||
*/
|
||||
bool isThreaded() const;
|
||||
|
||||
/**
|
||||
* @brief Return the Matrix ID of the thread's root message.
|
||||
*
|
||||
* Empty if this not part of a thread.
|
||||
*/
|
||||
QString threadRoot() const;
|
||||
|
||||
/**
|
||||
* @brief Return the latitude for the event.
|
||||
*
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QVector>
|
||||
#include <Quotient/events/eventcontent.h>
|
||||
#include <Quotient/events/stateevent.h>
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
*
|
||||
* @sa ImagePackImage
|
||||
*/
|
||||
QList<ImagePackEventContent::ImagePackImage> images;
|
||||
QVector<ImagePackEventContent::ImagePackImage> images;
|
||||
|
||||
explicit ImagePackEventContent(const QJsonObject &o);
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ class LocationHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
|
||||
QML_UNCREATABLE("")
|
||||
public:
|
||||
/** Unite two rectanlges. */
|
||||
Q_INVOKABLE static QRectF unite(const QRectF &r1, const QRectF &r2);
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
file.write(buf.constData(), buf.size());
|
||||
file.flush();
|
||||
|
||||
if (oldHandler && (!context.category || (strcmp(context.category, "quotient.e2ee") != 0 || e2eeDebugEnabled))) {
|
||||
if (oldHandler && (strcmp(context.category, "quotient.e2ee") != 0 || e2eeDebugEnabled)) {
|
||||
oldHandler(type, context, message);
|
||||
}
|
||||
}
|
||||
@@ -197,6 +197,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
sInstance()->log(QtInfoMsg, context, message);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +212,7 @@ void filter(QLoggingCategory *category)
|
||||
|
||||
void initLogging()
|
||||
{
|
||||
e2eeDebugEnabled = QLoggingCategory("quotient.e2ee", QtInfoMsg).isEnabled(QtDebugMsg);
|
||||
e2eeDebugEnabled = QLoggingCategory("quotient.e2ee", QtDebugMsg).isEnabled(QtDebugMsg);
|
||||
oldCategoryFilter = QLoggingCategory::installFilter(filter);
|
||||
oldHandler = qInstallMessageHandler(messageHandler);
|
||||
sInstance->setOrigHandler(oldHandler);
|
||||
|
||||
@@ -100,8 +100,7 @@ void LoginHelper::init()
|
||||
Q_EMIT Controller::instance().globalErrorOccured(i18n("Network Error"), std::move(error));
|
||||
});
|
||||
|
||||
connectSingleShot(m_connection, &Connection::syncDone, this, [this]() {
|
||||
Q_EMIT loaded();
|
||||
connectSingleShot(m_connection, &Connection::syncDone, this, []() {
|
||||
Q_EMIT Controller::instance().initiated();
|
||||
});
|
||||
}
|
||||
|
||||
14
src/login.h
14
src/login.h
@@ -79,17 +79,7 @@ class LoginHelper : public QObject
|
||||
Q_PROPERTY(bool isInvalidPassword READ isInvalidPassword NOTIFY isInvalidPasswordChanged)
|
||||
|
||||
public:
|
||||
static LoginHelper &instance()
|
||||
{
|
||||
static LoginHelper _instance;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static LoginHelper *create(QQmlEngine *engine, QJSEngine *)
|
||||
{
|
||||
engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership);
|
||||
return &instance();
|
||||
}
|
||||
explicit LoginHelper(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void init();
|
||||
|
||||
@@ -135,7 +125,6 @@ Q_SIGNALS:
|
||||
void isLoggingInChanged();
|
||||
void isLoggedInChanged();
|
||||
void isInvalidPasswordChanged();
|
||||
void loaded();
|
||||
|
||||
private:
|
||||
void setHomeserverReachable(bool reachable);
|
||||
@@ -152,5 +141,4 @@ private:
|
||||
bool m_isLoggingIn = false;
|
||||
bool m_isLoggedIn = false;
|
||||
bool m_invalidPassword = false;
|
||||
explicit LoginHelper(QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
26
src/main.cpp
26
src/main.cpp
@@ -35,9 +35,9 @@
|
||||
#include "neochat-version.h"
|
||||
|
||||
#include <Quotient/networkaccessmanager.h>
|
||||
#include <Quotient/util.h>
|
||||
|
||||
#include "blurhashimageprovider.h"
|
||||
#include "colorschemer.h"
|
||||
#include "controller.h"
|
||||
#include "logger.h"
|
||||
#include "matriximageprovider.h"
|
||||
@@ -45,6 +45,10 @@
|
||||
#include "roommanager.h"
|
||||
#include "windowcontroller.h"
|
||||
|
||||
#ifdef HAVE_COLORSCHEME
|
||||
#include "colorschemer.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RUNNER
|
||||
#include "runner.h"
|
||||
#include <QDBusConnection>
|
||||
@@ -121,7 +125,7 @@ int main(int argc, char *argv[])
|
||||
font.setHintingPreference(QFont::PreferNoHinting);
|
||||
app.setFont(font);
|
||||
#endif
|
||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
||||
KLocalizedString::setApplicationDomain("neochat");
|
||||
|
||||
QGuiApplication::setOrganizationName("KDE"_ls);
|
||||
|
||||
@@ -131,11 +135,7 @@ int main(int argc, char *argv[])
|
||||
i18n("Matrix client"),
|
||||
KAboutLicense::GPL_V3,
|
||||
i18n("© 2018-2020 Black Hat, 2020-2023 KDE Community"));
|
||||
about.addAuthor(i18n("Carl Schwan"),
|
||||
i18n("Maintainer"),
|
||||
QStringLiteral("carl@carlschwan.eu"),
|
||||
QStringLiteral("https://carlschwan.eu"),
|
||||
QStringLiteral("https://carlschwan.eu/avatar.png"));
|
||||
about.addAuthor(i18n("Carl Schwan"), i18n("Maintainer"), QStringLiteral("carl@carlschwan.eu"), QStringLiteral("https://carlschwan.eu"));
|
||||
about.addAuthor(i18n("Tobias Fella"), i18n("Maintainer"), QStringLiteral("tobias.fella@kde.org"), QStringLiteral("https://tobiasfella.de"));
|
||||
about.addAuthor(i18n("James Graham"), i18n("Maintainer"), QStringLiteral("james.h.graham@protonmail.com"));
|
||||
about.addCredit(i18n("Black Hat"), i18n("Original author of Spectral"), QStringLiteral("bhat@encom.eu.org"));
|
||||
@@ -144,7 +144,7 @@ int main(int argc, char *argv[])
|
||||
about.setOrganizationDomain("kde.org");
|
||||
|
||||
about.addComponent(QStringLiteral("libQuotient"),
|
||||
i18n("A Qt library to write cross-platform clients for Matrix"),
|
||||
i18n("A Qt5 library to write cross-platform clients for Matrix"),
|
||||
i18nc("<version number> (built against <possibly different version number>)",
|
||||
"%1 (built against %2)",
|
||||
Quotient::versionString(),
|
||||
@@ -157,7 +157,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
initLogging();
|
||||
|
||||
#if Quotient_VERSION_MINOR == 8
|
||||
Connection::setEncryptionDefault(true);
|
||||
#endif
|
||||
|
||||
#ifdef NEOCHAT_FLATPAK
|
||||
// Copy over the included FontConfig configuration to the
|
||||
@@ -166,10 +168,12 @@ int main(int argc, char *argv[])
|
||||
QStringLiteral("/var/config/fontconfig/conf.d/99-noto-mono-color-emoji.conf"));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_COLORSCHEME
|
||||
ColorSchemer colorScheme;
|
||||
if (!NeoChatConfig::self()->colorScheme().isEmpty()) {
|
||||
colorScheme.apply(NeoChatConfig::self()->colorScheme());
|
||||
}
|
||||
#endif
|
||||
|
||||
qml_register_types_org_kde_neochat();
|
||||
qmlRegisterSingletonInstance("org.kde.neochat.config", 1, 0, "Config", NeoChatConfig::self());
|
||||
@@ -223,7 +227,7 @@ int main(int argc, char *argv[])
|
||||
});
|
||||
}
|
||||
|
||||
engine.addImageProvider(QLatin1String("mxc"), MatrixImageProvider::create(&engine, &engine));
|
||||
engine.addImageProvider(QLatin1String("mxc"), new MatrixImageProvider);
|
||||
engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider);
|
||||
|
||||
engine.load(QUrl(QStringLiteral("qrc:/org/kde/neochat/qml/main.qml")));
|
||||
@@ -236,8 +240,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
#ifdef HAVE_RUNNER
|
||||
auto runner = Runner::create(&engine, &engine);
|
||||
QDBusConnection::sessionBus().registerObject("/RoomRunner"_ls, runner, QDBusConnection::ExportScriptableContents);
|
||||
Runner runner;
|
||||
QDBusConnection::sessionBus().registerObject("/RoomRunner"_ls, &runner, QDBusConnection::ExportScriptableContents);
|
||||
#endif
|
||||
|
||||
QWindow *window = windowFromEngine(&engine);
|
||||
|
||||
@@ -13,13 +13,11 @@
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "controller.h"
|
||||
#include "neochatconnection.h"
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
ThumbnailResponse::ThumbnailResponse(QString id, QSize size, NeoChatConnection *connection)
|
||||
ThumbnailResponse::ThumbnailResponse(QString id, QSize size)
|
||||
: mediaId(std::move(id))
|
||||
, requestedSize(size)
|
||||
, localFile(QStringLiteral("%1/image_provider/%2-%3x%4.png")
|
||||
@@ -27,7 +25,6 @@ ThumbnailResponse::ThumbnailResponse(QString id, QSize size, NeoChatConnection *
|
||||
mediaId,
|
||||
QString::number(requestedSize.width()),
|
||||
QString::number(requestedSize.height())))
|
||||
, m_connection(connection)
|
||||
, errorStr("Image request hasn't started"_ls)
|
||||
{
|
||||
if (requestedSize.isEmpty()) {
|
||||
@@ -54,24 +51,24 @@ ThumbnailResponse::ThumbnailResponse(QString id, QSize size, NeoChatConnection *
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_connection) {
|
||||
if (!Controller::instance().activeConnection()) {
|
||||
qWarning() << "Current connection is null";
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute a request on the main thread asynchronously
|
||||
moveToThread(m_connection->thread());
|
||||
moveToThread(Controller::instance().activeConnection()->thread());
|
||||
QMetaObject::invokeMethod(this, &ThumbnailResponse::startRequest, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void ThumbnailResponse::startRequest()
|
||||
{
|
||||
if (!m_connection) {
|
||||
if (!Controller::instance().activeConnection()) {
|
||||
return;
|
||||
}
|
||||
// Runs in the main thread, not QML thread
|
||||
Q_ASSERT(QThread::currentThread() == m_connection->thread());
|
||||
job = m_connection->getThumbnail(mediaId, requestedSize);
|
||||
Q_ASSERT(QThread::currentThread() == Controller::instance().activeConnection()->thread());
|
||||
job = Controller::instance().activeConnection()->getThumbnail(mediaId, requestedSize);
|
||||
// Connect to any possible outcome including abandonment
|
||||
// to make sure the QML thread is not left stuck forever.
|
||||
connect(job, &BaseJob::finished, this, &ThumbnailResponse::prepareResult);
|
||||
@@ -121,7 +118,7 @@ QString ThumbnailResponse::errorString() const
|
||||
|
||||
QQuickImageResponse *MatrixImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
|
||||
{
|
||||
return new ThumbnailResponse(id, requestedSize, m_connection);
|
||||
return new ThumbnailResponse(id, requestedSize);
|
||||
}
|
||||
|
||||
#include "moc_matriximageprovider.cpp"
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
#include <QReadWriteLock>
|
||||
|
||||
class NeoChatConnection;
|
||||
|
||||
/**
|
||||
* @class ThumbnailResponse
|
||||
*
|
||||
@@ -23,7 +21,7 @@ class ThumbnailResponse : public QQuickImageResponse
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ThumbnailResponse(QString mediaId, QSize requestedSize, NeoChatConnection *m_connection);
|
||||
explicit ThumbnailResponse(QString mediaId, QSize requestedSize);
|
||||
~ThumbnailResponse() override = default;
|
||||
|
||||
private Q_SLOTS:
|
||||
@@ -35,7 +33,6 @@ private:
|
||||
QSize requestedSize;
|
||||
const QString localFile;
|
||||
Quotient::MediaThumbnailJob *job = nullptr;
|
||||
NeoChatConnection *m_connection;
|
||||
|
||||
QImage image;
|
||||
QString errorStr;
|
||||
@@ -54,27 +51,11 @@ private:
|
||||
*/
|
||||
class MatrixImageProvider : public QQuickAsyncImageProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
|
||||
Q_PROPERTY(NeoChatConnection *connection MEMBER m_connection)
|
||||
public:
|
||||
static MatrixImageProvider *create(QQmlEngine *engine, QJSEngine *)
|
||||
{
|
||||
static MatrixImageProvider instance;
|
||||
engine->setObjectOwnership(&instance, QQmlEngine::CppOwnership);
|
||||
return &instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a job to provide the image with the given ID.
|
||||
*
|
||||
* @sa QQuickAsyncImageProvider::requestImageResponse
|
||||
*/
|
||||
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
|
||||
|
||||
private:
|
||||
NeoChatConnection *m_connection = nullptr;
|
||||
MatrixImageProvider() = default;
|
||||
};
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QCoroTask>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QQmlEngine>
|
||||
#include <QVector>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "actionsmodel.h"
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "controller.h"
|
||||
#include "neochatroom.h"
|
||||
#include "roommanager.h"
|
||||
@@ -20,7 +19,7 @@ QStringList rainbowColors{"#ff2b00"_ls, "#ff5500"_ls, "#ff8000"_ls, "#ffaa00"_ls
|
||||
"#00d4ff"_ls, "#00aaff"_ls, "#007fff"_ls, "#0055ff"_ls, "#002bff"_ls, "#0000ff"_ls, "#2a00ff"_ls, "#5500ff"_ls, "#7f00ff"_ls,
|
||||
"#aa00ff"_ls, "#d400ff"_ls, "#ff00ff"_ls, "#ff00d4"_ls, "#ff00aa"_ls, "#ff0080"_ls, "#ff0055"_ls, "#ff002b"_ls, "#ff0000"_ls};
|
||||
|
||||
auto leaveRoomLambda = [](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
auto leaveRoomLambda = [](const QString &text, NeoChatRoom *room) {
|
||||
if (text.isEmpty()) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18n("Leaving this room."));
|
||||
room->connection()->leaveRoom(room);
|
||||
@@ -46,7 +45,7 @@ auto leaveRoomLambda = [](const QString &text, NeoChatRoom *room, ChatBarCache *
|
||||
return QString();
|
||||
};
|
||||
|
||||
auto roomNickLambda = [](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
auto roomNickLambda = [](const QString &text, NeoChatRoom *room) {
|
||||
if (text.isEmpty()) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("No new nickname provided, no changes will happen."));
|
||||
} else {
|
||||
@@ -55,10 +54,10 @@ auto roomNickLambda = [](const QString &text, NeoChatRoom *room, ChatBarCache *)
|
||||
return QString();
|
||||
};
|
||||
|
||||
QList<ActionsModel::Action> actions{
|
||||
QVector<ActionsModel::Action> actions{
|
||||
Action{
|
||||
QStringLiteral("shrug"),
|
||||
[](const QString &message, NeoChatRoom *, ChatBarCache *) {
|
||||
[](const QString &message, NeoChatRoom *) {
|
||||
return QStringLiteral("¯\\\\_(ツ)_/¯ %1").arg(message);
|
||||
},
|
||||
true,
|
||||
@@ -68,7 +67,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("lenny"),
|
||||
[](const QString &message, NeoChatRoom *, ChatBarCache *) {
|
||||
[](const QString &message, NeoChatRoom *) {
|
||||
return QStringLiteral("( ͡° ͜ʖ ͡°) %1").arg(message);
|
||||
},
|
||||
true,
|
||||
@@ -78,7 +77,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("tableflip"),
|
||||
[](const QString &message, NeoChatRoom *, ChatBarCache *) {
|
||||
[](const QString &message, NeoChatRoom *) {
|
||||
return QStringLiteral("(╯°□°)╯︵ ┻━┻ %1").arg(message);
|
||||
},
|
||||
true,
|
||||
@@ -88,7 +87,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("unflip"),
|
||||
[](const QString &message, NeoChatRoom *, ChatBarCache *) {
|
||||
[](const QString &message, NeoChatRoom *) {
|
||||
return QStringLiteral("┬──┬ ノ( ゜-゜ノ) %1").arg(message);
|
||||
},
|
||||
true,
|
||||
@@ -98,7 +97,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("rainbow"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *chatBarCache) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
QString rainbowText;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
rainbowText += QStringLiteral("<font color='%2'>%3</font>").arg(rainbowColors[i % rainbowColors.length()], text.at(i));
|
||||
@@ -107,8 +106,8 @@ QList<ActionsModel::Action> actions{
|
||||
room->postMessage(QStringLiteral("/rainbow %1").arg(text),
|
||||
rainbowText,
|
||||
RoomMessageEvent::MsgType::Text,
|
||||
chatBarCache->replyId(),
|
||||
chatBarCache->editId());
|
||||
room->chatBoxReplyId(),
|
||||
room->chatBoxEditId());
|
||||
return QString();
|
||||
},
|
||||
false,
|
||||
@@ -118,7 +117,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("rainbowme"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *chatBarCache) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
QString rainbowText;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
rainbowText += QStringLiteral("<font color='%2'>%3</font>").arg(rainbowColors[i % rainbowColors.length()], text.at(i));
|
||||
@@ -127,8 +126,8 @@ QList<ActionsModel::Action> actions{
|
||||
room->postMessage(QStringLiteral("/rainbow %1").arg(text),
|
||||
rainbowText,
|
||||
RoomMessageEvent::MsgType::Emote,
|
||||
chatBarCache->replyId(),
|
||||
chatBarCache->editId());
|
||||
room->chatBoxReplyId(),
|
||||
room->chatBoxEditId());
|
||||
return QString();
|
||||
},
|
||||
false,
|
||||
@@ -138,7 +137,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("plain"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
room->postMessage(text, text.toHtmlEscaped(), RoomMessageEvent::MsgType::Text, {}, {});
|
||||
return QString();
|
||||
},
|
||||
@@ -149,13 +148,13 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("spoiler"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *chatBarCache) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
// Ideally, we would just return rainbowText and let that do the rest, but the colors don't survive markdownToHTML.
|
||||
room->postMessage(QStringLiteral("/spoiler %1").arg(text),
|
||||
QStringLiteral("<span data-mx-spoiler>%1</span>").arg(text),
|
||||
RoomMessageEvent::MsgType::Text,
|
||||
chatBarCache->replyId(),
|
||||
chatBarCache->editId());
|
||||
room->chatBoxReplyId(),
|
||||
room->chatBoxEditId());
|
||||
return QString();
|
||||
},
|
||||
false,
|
||||
@@ -165,7 +164,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("me"),
|
||||
[](const QString &text, NeoChatRoom *, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *) {
|
||||
return text;
|
||||
},
|
||||
true,
|
||||
@@ -175,7 +174,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("notice"),
|
||||
[](const QString &text, NeoChatRoom *, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *) {
|
||||
return text;
|
||||
},
|
||||
true,
|
||||
@@ -185,7 +184,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("invite"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
static const QRegularExpression mxidRegex(
|
||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||
auto regexMatch = mxidRegex.match(text);
|
||||
@@ -221,7 +220,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("join"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
||||
auto regexMatch = roomRegex.match(text);
|
||||
if (!regexMatch.hasMatch()) {
|
||||
@@ -245,7 +244,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("knock"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
auto parts = text.split(QLatin1String(" "));
|
||||
QString roomName = parts[0];
|
||||
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
||||
@@ -261,7 +260,7 @@ QList<ActionsModel::Action> actions{
|
||||
return QString();
|
||||
}
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Knocking room <roomname>.", "Knocking room %1.", text));
|
||||
auto connection = room->connection();
|
||||
auto connection = Controller::instance().activeConnection();
|
||||
const auto knownServer = roomName.mid(roomName.indexOf(":"_ls) + 1);
|
||||
if (parts.length() >= 2) {
|
||||
RoomManager::instance().knockRoom(connection, roomName, parts[1], QStringList{knownServer});
|
||||
@@ -277,7 +276,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("j"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
||||
auto regexMatch = roomRegex.match(text);
|
||||
if (!regexMatch.hasMatch()) {
|
||||
@@ -285,7 +284,7 @@ QList<ActionsModel::Action> actions{
|
||||
i18nc("'<text>' does not look like a room id or alias.", "'%1' does not look like a room id or alias.", text));
|
||||
return QString();
|
||||
}
|
||||
if (room->connection()->room(text) || room->connection()->roomByAlias(text)) {
|
||||
if (Controller::instance().activeConnection()->room(text) || Controller::instance().activeConnection()->roomByAlias(text)) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("You are already in room <roomname>.", "You are already in room %1.", text));
|
||||
return QString();
|
||||
}
|
||||
@@ -316,7 +315,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("nick"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
if (text.isEmpty()) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("No new nickname provided, no changes will happen."));
|
||||
} else {
|
||||
@@ -347,7 +346,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("ignore"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
static const QRegularExpression mxidRegex(
|
||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||
auto regexMatch = mxidRegex.match(text);
|
||||
@@ -375,7 +374,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("unignore"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
static const QRegularExpression mxidRegex(
|
||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||
auto regexMatch = mxidRegex.match(text);
|
||||
@@ -403,8 +402,9 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("react"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *chatBarCache) {
|
||||
if (chatBarCache->replyId().isEmpty()) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
QString replyEventId = room->chatBoxReplyId();
|
||||
if (replyEventId.isEmpty()) {
|
||||
for (auto it = room->messageEvents().crbegin(); it != room->messageEvents().crend(); it++) {
|
||||
const auto &evt = **it;
|
||||
if (const auto event = eventCast<const RoomMessageEvent>(&evt)) {
|
||||
@@ -413,7 +413,7 @@ QList<ActionsModel::Action> actions{
|
||||
}
|
||||
}
|
||||
}
|
||||
room->toggleReaction(chatBarCache->replyId(), text);
|
||||
room->toggleReaction(replyEventId, text);
|
||||
return QString();
|
||||
},
|
||||
false,
|
||||
@@ -423,7 +423,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("ban"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
auto parts = text.split(QLatin1String(" "));
|
||||
static const QRegularExpression mxidRegex(
|
||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||
@@ -462,7 +462,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("unban"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
static const QRegularExpression mxidRegex(
|
||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||
auto regexMatch = mxidRegex.match(text);
|
||||
@@ -495,7 +495,7 @@ QList<ActionsModel::Action> actions{
|
||||
},
|
||||
Action{
|
||||
QStringLiteral("kick"),
|
||||
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
auto parts = text.split(QLatin1String(" "));
|
||||
static const QRegularExpression mxidRegex(
|
||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||
@@ -574,7 +574,7 @@ QHash<int, QByteArray> ActionsModel::roleNames() const
|
||||
};
|
||||
}
|
||||
|
||||
QList<Action> &ActionsModel::allActions() const
|
||||
QVector<Action> &ActionsModel::allActions() const
|
||||
{
|
||||
return actions;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <QAbstractListModel>
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
|
||||
class ChatBarCache;
|
||||
class NeoChatRoom;
|
||||
|
||||
/**
|
||||
@@ -29,7 +28,7 @@ public:
|
||||
/**
|
||||
* @brief The function to execute when the action is triggered.
|
||||
*/
|
||||
std::function<QString(const QString &, NeoChatRoom *, ChatBarCache *)> handle;
|
||||
std::function<QString(const QString &, NeoChatRoom *)> handle;
|
||||
/**
|
||||
* @brief Whether the action is a message type action.
|
||||
*
|
||||
@@ -88,7 +87,7 @@ public:
|
||||
/**
|
||||
* @brief Return a vector with all supported actions.
|
||||
*/
|
||||
QList<Action> &allActions() const;
|
||||
QVector<Action> &allActions() const;
|
||||
|
||||
private:
|
||||
ActionsModel() = default;
|
||||
|
||||
@@ -15,28 +15,13 @@
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
void CustomEmojiModel::setConnection(NeoChatConnection *connection)
|
||||
{
|
||||
if (connection == m_connection) {
|
||||
return;
|
||||
}
|
||||
m_connection = connection;
|
||||
Q_EMIT connectionChanged();
|
||||
fetchEmojis();
|
||||
}
|
||||
|
||||
NeoChatConnection *CustomEmojiModel::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void CustomEmojiModel::fetchEmojis()
|
||||
{
|
||||
if (!m_connection) {
|
||||
if (!Controller::instance().activeConnection()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &data = m_connection->accountData("im.ponies.user_emotes"_ls);
|
||||
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes"_ls);
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -68,10 +53,10 @@ void CustomEmojiModel::addEmoji(const QString &name, const QUrl &location)
|
||||
{
|
||||
using namespace Quotient;
|
||||
|
||||
auto job = m_connection->uploadFile(location.toLocalFile());
|
||||
auto job = Controller::instance().activeConnection()->uploadFile(location.toLocalFile());
|
||||
|
||||
connect(job, &BaseJob::success, this, [name, location, job, this] {
|
||||
const auto &data = m_connection->accountData("im.ponies.user_emotes"_ls);
|
||||
connect(job, &BaseJob::success, this, [name, location, job] {
|
||||
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes"_ls);
|
||||
auto json = data != nullptr ? data->contentJson() : QJsonObject();
|
||||
auto emojiData = json["images"_ls].toObject();
|
||||
|
||||
@@ -93,7 +78,7 @@ void CustomEmojiModel::addEmoji(const QString &name, const QUrl &location)
|
||||
});
|
||||
|
||||
json["images"_ls] = emojiData;
|
||||
m_connection->setAccountData("im.ponies.user_emotes"_ls, json);
|
||||
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes"_ls, json);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -101,7 +86,7 @@ void CustomEmojiModel::removeEmoji(const QString &name)
|
||||
{
|
||||
using namespace Quotient;
|
||||
|
||||
const auto &data = m_connection->accountData("im.ponies.user_emotes"_ls);
|
||||
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes"_ls);
|
||||
Q_ASSERT(data);
|
||||
auto json = data->contentJson();
|
||||
const QString _name = name.mid(1).chopped(1);
|
||||
@@ -124,18 +109,18 @@ void CustomEmojiModel::removeEmoji(const QString &name)
|
||||
emojiData.remove(_name);
|
||||
json["emoticons"_ls] = emojiData;
|
||||
}
|
||||
m_connection->setAccountData("im.ponies.user_emotes"_ls, json);
|
||||
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes"_ls, json);
|
||||
}
|
||||
|
||||
CustomEmojiModel::CustomEmojiModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
connect(this, &CustomEmojiModel::connectionChanged, this, [this]() {
|
||||
if (!m_connection) {
|
||||
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, [this]() {
|
||||
if (!Controller::instance().activeConnection()) {
|
||||
return;
|
||||
}
|
||||
CustomEmojiModel::fetchEmojis();
|
||||
connect(m_connection, &Connection::accountDataChanged, this, [this](const QString &id) {
|
||||
connect(Controller::instance().activeConnection(), &Connection::accountDataChanged, this, [this](const QString &id) {
|
||||
if (id != QStringLiteral("im.ponies.user_emotes")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <QRegularExpression>
|
||||
#include <memory>
|
||||
|
||||
class NeoChatConnection;
|
||||
|
||||
struct CustomEmoji {
|
||||
QString name; // with :semicolons:
|
||||
QString url; // mxc://
|
||||
@@ -33,8 +31,6 @@ class CustomEmojiModel : public QAbstractListModel
|
||||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
|
||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Defines the model roles.
|
||||
@@ -102,16 +98,9 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void removeEmoji(const QString &name);
|
||||
|
||||
void setConnection(NeoChatConnection *connection);
|
||||
NeoChatConnection *connection() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void connectionChanged();
|
||||
|
||||
private:
|
||||
explicit CustomEmojiModel(QObject *parent = nullptr);
|
||||
QList<CustomEmoji> m_emojis;
|
||||
NeoChatConnection *m_connection = nullptr;
|
||||
|
||||
void fetchEmojis();
|
||||
};
|
||||
|
||||
@@ -24,8 +24,8 @@ DevicesModel::DevicesModel(QObject *parent)
|
||||
|
||||
void DevicesModel::fetchDevices()
|
||||
{
|
||||
if (m_connection) {
|
||||
auto job = m_connection->callApi<GetDevicesJob>();
|
||||
if (Controller::instance().activeConnection()) {
|
||||
auto job = Controller::instance().activeConnection()->callApi<GetDevicesJob>();
|
||||
connect(job, &BaseJob::success, this, [this, job]() {
|
||||
beginResetModel();
|
||||
m_devices = job->devices();
|
||||
@@ -102,7 +102,7 @@ void DevicesModel::logout(const QString &deviceId, const QString &password)
|
||||
for (index = 0; m_devices[index].deviceId != deviceId; index++)
|
||||
;
|
||||
|
||||
auto job = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId);
|
||||
auto job = Controller::instance().activeConnection()->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId);
|
||||
|
||||
connect(job, &BaseJob::result, this, [this, job, password, index] {
|
||||
auto onSuccess = [this, index]() {
|
||||
@@ -117,9 +117,9 @@ void DevicesModel::logout(const QString &deviceId, const QString &password)
|
||||
authData["session"_ls] = replyData["session"_ls];
|
||||
authData["password"_ls] = password;
|
||||
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, Controller::instance().activeConnection()->user()->id()}};
|
||||
authData["identifier"_ls] = identifier;
|
||||
auto *innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
||||
auto *innerJob = Controller::instance().activeConnection()->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
||||
connect(innerJob, &BaseJob::success, this, onSuccess);
|
||||
} else {
|
||||
onSuccess();
|
||||
@@ -132,7 +132,7 @@ void DevicesModel::setName(const QString &deviceId, const QString &name)
|
||||
int index;
|
||||
for (index = 0; m_devices[index].deviceId != deviceId; index++);
|
||||
|
||||
auto job = m_connection->callApi<UpdateDeviceJob>(m_devices[index].deviceId, name);
|
||||
auto job = Controller::instance().activeConnection()->callApi<UpdateDeviceJob>(m_devices[index].deviceId, name);
|
||||
QString oldName = m_devices[index].displayName;
|
||||
beginResetModel();
|
||||
m_devices[index].displayName = name;
|
||||
@@ -160,7 +160,7 @@ void DevicesModel::setConnection(Connection *connection)
|
||||
|
||||
connect(m_connection, &Connection::sessionVerified, this, [this](const QString &userId, const QString &deviceId) {
|
||||
Q_UNUSED(deviceId);
|
||||
if (userId == m_connection->userId()) {
|
||||
if (userId == Controller::instance().activeConnection()->userId()) {
|
||||
fetchDevices();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -98,6 +98,6 @@ Q_SIGNALS:
|
||||
|
||||
private:
|
||||
void fetchDevices();
|
||||
QList<Quotient::Device> m_devices;
|
||||
QVector<Quotient::Device> m_devices;
|
||||
QPointer<Quotient::Connection> m_connection;
|
||||
};
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
EmojiModel::EmojiModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_config(KSharedConfig::openStateConfig())
|
||||
, m_configGroup(KConfigGroup(m_config, QStringLiteral("Editor")))
|
||||
{
|
||||
if (_emojis.isEmpty()) {
|
||||
#include "emojis.h"
|
||||
@@ -63,9 +61,9 @@ QHash<int, QByteArray> EmojiModel::roleNames() const
|
||||
return {{ShortNameRole, "shortName"}, {UnicodeRole, "unicode"}};
|
||||
}
|
||||
|
||||
QStringList EmojiModel::lastUsedEmojis() const
|
||||
QVariantList EmojiModel::history() const
|
||||
{
|
||||
return m_configGroup.readEntry(QStringLiteral("lastUsedEmojis"), QStringList());
|
||||
return m_settings.value(QStringLiteral("Editor/emojis"), QVariantList()).toList();
|
||||
}
|
||||
|
||||
QVariantList EmojiModel::filterModel(const QString &filter, bool limit)
|
||||
@@ -95,21 +93,19 @@ QVariantList EmojiModel::filterModelNoCustom(const QString &filter, bool limit)
|
||||
|
||||
void EmojiModel::emojiUsed(const QVariant &modelData)
|
||||
{
|
||||
auto list = lastUsedEmojis();
|
||||
const auto emoji = modelData.value<Emoji>();
|
||||
QVariantList list = history();
|
||||
|
||||
auto it = list.begin();
|
||||
while (it != list.end()) {
|
||||
if (*it == emoji.shortName) {
|
||||
if ((*it).value<Emoji>().unicode == modelData.value<Emoji>().unicode) {
|
||||
it = list.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
list.push_front(emoji.shortName);
|
||||
|
||||
m_configGroup.writeEntry(QStringLiteral("lastUsedEmojis"), list);
|
||||
list.push_front(modelData);
|
||||
m_settings.setValue(QStringLiteral("Editor/emojis"), list);
|
||||
|
||||
Q_EMIT historyChanged();
|
||||
}
|
||||
@@ -117,11 +113,11 @@ void EmojiModel::emojiUsed(const QVariant &modelData)
|
||||
QVariantList EmojiModel::emojis(Category category) const
|
||||
{
|
||||
if (category == History) {
|
||||
return emojiHistory();
|
||||
return history();
|
||||
}
|
||||
if (category == HistoryNoCustom) {
|
||||
QVariantList list;
|
||||
for (const auto &e : emojiHistory()) {
|
||||
for (const auto &e : history()) {
|
||||
auto emoji = qvariant_cast<Emoji>(e);
|
||||
if (!emoji.isCustom) {
|
||||
list.append(e);
|
||||
@@ -221,19 +217,4 @@ QVariantList EmojiModel::categoriesWithCustom() const
|
||||
return cats;
|
||||
}
|
||||
|
||||
QVariantList EmojiModel::emojiHistory() const
|
||||
{
|
||||
QVariantList list;
|
||||
for (const auto &historicEmoji : lastUsedEmojis()) {
|
||||
for (const auto &emojiCategory : _emojis) {
|
||||
for (const auto &emoji : emojiCategory) {
|
||||
if (qvariant_cast<Emoji>(emoji).shortName == historicEmoji) {
|
||||
list.append(emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
#include "moc_emojimodel.cpp"
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <KConfigGroup>
|
||||
#include <KSharedConfig>
|
||||
#include <QAbstractListModel>
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QSettings>
|
||||
|
||||
struct Emoji {
|
||||
Emoji(QString unicode, QString shortname, bool isCustom = false)
|
||||
@@ -24,6 +23,21 @@ struct Emoji {
|
||||
}
|
||||
Emoji() = default;
|
||||
|
||||
friend QDataStream &operator<<(QDataStream &arch, const Emoji &object)
|
||||
{
|
||||
arch << object.unicode;
|
||||
arch << object.shortName;
|
||||
return arch;
|
||||
}
|
||||
|
||||
friend QDataStream &operator>>(QDataStream &arch, Emoji &object)
|
||||
{
|
||||
arch >> object.unicode;
|
||||
arch >> object.shortName;
|
||||
object.isCustom = object.unicode.startsWith(QStringLiteral("image://"));
|
||||
return arch;
|
||||
}
|
||||
|
||||
QString unicode;
|
||||
QString shortName;
|
||||
QString description;
|
||||
@@ -49,6 +63,11 @@ class EmojiModel : public QAbstractListModel
|
||||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
|
||||
/**
|
||||
* @brief Return a list of recently used emojis.
|
||||
*/
|
||||
Q_PROPERTY(QVariantList history READ history NOTIFY historyChanged)
|
||||
|
||||
/**
|
||||
* @brief Return a list of emoji categories.
|
||||
*
|
||||
@@ -158,11 +177,7 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE QVariantList tones(const QString &baseEmoji) const;
|
||||
|
||||
/**
|
||||
* @brief Return a list of the last used emoji shortnames
|
||||
*/
|
||||
QStringList lastUsedEmojis() const;
|
||||
|
||||
Q_INVOKABLE QVariantList history() const;
|
||||
QVariantList categories() const;
|
||||
QVariantList categoriesWithCustom() const;
|
||||
|
||||
@@ -175,10 +190,7 @@ public Q_SLOTS:
|
||||
private:
|
||||
static QHash<Category, QVariantList> _emojis;
|
||||
|
||||
/// Returns QVariants containing the last used Emojis
|
||||
QVariantList emojiHistory() const;
|
||||
|
||||
KSharedConfig::Ptr m_config;
|
||||
KConfigGroup m_configGroup;
|
||||
// TODO: Port away from QSettings
|
||||
QSettings m_settings;
|
||||
EmojiModel(QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
@@ -151,7 +151,7 @@ void ImagePacksModel::setShowEmoticons(bool showEmoticons)
|
||||
m_showEmoticons = showEmoticons;
|
||||
Q_EMIT showEmoticonsChanged();
|
||||
}
|
||||
QList<Quotient::ImagePackEventContent::ImagePackImage> ImagePacksModel::images(int index)
|
||||
QVector<Quotient::ImagePackEventContent::ImagePackImage> ImagePacksModel::images(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_events.size()) {
|
||||
return {};
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
#include "events/imagepackevent.h"
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
#include <QPointer>
|
||||
#include <QQmlEngine>
|
||||
#include <QVector>
|
||||
|
||||
class NeoChatRoom;
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
/**
|
||||
* @brief Return a vector of the images in the pack at the given index.
|
||||
*/
|
||||
[[nodiscard]] QList<Quotient::ImagePackEventContent::ImagePackImage> images(int index);
|
||||
[[nodiscard]] QVector<Quotient::ImagePackEventContent::ImagePackImage> images(int index);
|
||||
|
||||
Q_SIGNALS:
|
||||
void roomChanged();
|
||||
@@ -96,7 +96,7 @@ Q_SIGNALS:
|
||||
|
||||
private:
|
||||
QPointer<NeoChatRoom> m_room;
|
||||
QList<Quotient::ImagePackEventContent> m_events;
|
||||
QVector<Quotient::ImagePackEventContent> m_events;
|
||||
bool m_showStickers = true;
|
||||
bool m_showEmoticons = true;
|
||||
void reloadImages();
|
||||
|
||||
112
src/models/keywordnotificationrulemodel.cpp
Normal file
112
src/models/keywordnotificationrulemodel.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// SPDX-FileCopyrightText: 2022 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 "keywordnotificationrulemodel.h"
|
||||
#include "controller.h"
|
||||
#include "notificationsmanager.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/converters.h>
|
||||
#include <Quotient/csapi/definitions/push_ruleset.h>
|
||||
#include <Quotient/csapi/pushrules.h>
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
|
||||
KeywordNotificationRuleModel::KeywordNotificationRuleModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
if (Controller::instance().activeConnection()) {
|
||||
controllerConnectionChanged();
|
||||
}
|
||||
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, &KeywordNotificationRuleModel::controllerConnectionChanged);
|
||||
}
|
||||
|
||||
void KeywordNotificationRuleModel::controllerConnectionChanged()
|
||||
{
|
||||
connect(Controller::instance().activeConnection(), &Quotient::Connection::accountDataChanged, this, &KeywordNotificationRuleModel::updateNotificationRules);
|
||||
updateNotificationRules("m.push_rules");
|
||||
}
|
||||
|
||||
void KeywordNotificationRuleModel::updateNotificationRules(const QString &type)
|
||||
{
|
||||
if (type != "m.push_rules") {
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonObject ruleDataJson = Controller::instance().activeConnection()->accountDataJson("m.push_rules");
|
||||
const Quotient::PushRuleset ruleData = Quotient::fromJson<Quotient::PushRuleset>(ruleDataJson["global"].toObject());
|
||||
const QVector<Quotient::PushRule> contentRules = ruleData.content;
|
||||
|
||||
beginResetModel();
|
||||
m_notificationRules.clear();
|
||||
for (const auto &i : contentRules) {
|
||||
if (!m_notificationRules.contains(i.ruleId) && i.ruleId[0] != '.') {
|
||||
m_notificationRules.append(i.ruleId);
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QVariant KeywordNotificationRuleModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.row() >= m_notificationRules.count()) {
|
||||
qDebug() << "KeywordNotificationRuleModel, something's wrong: index.row() >= m_notificationRules.count()";
|
||||
return {};
|
||||
}
|
||||
|
||||
if (role == NameRole) {
|
||||
return m_notificationRules.at(index.row());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
int KeywordNotificationRuleModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
return m_notificationRules.count();
|
||||
}
|
||||
|
||||
void KeywordNotificationRuleModel::addKeyword(const QString &keyword)
|
||||
{
|
||||
if (m_notificationRules.count() == 0) {
|
||||
NotificationsManager::instance().initializeKeywordNotificationAction();
|
||||
}
|
||||
|
||||
const QVector<QVariant> actions = NotificationsManager::instance().getKeywordNotificationActions();
|
||||
|
||||
auto job = Controller::instance()
|
||||
.activeConnection()
|
||||
->callApi<Quotient::SetPushRuleJob>("global", "content", keyword, actions, "", "", QVector<Quotient::PushCondition>(), keyword);
|
||||
connect(job, &Quotient::BaseJob::success, this, [this, keyword]() {
|
||||
beginInsertRows(QModelIndex(), m_notificationRules.count(), m_notificationRules.count());
|
||||
m_notificationRules.append(keyword);
|
||||
endInsertRows();
|
||||
});
|
||||
}
|
||||
|
||||
void KeywordNotificationRuleModel::removeKeywordAtIndex(int index)
|
||||
{
|
||||
auto job = Controller::instance().activeConnection()->callApi<Quotient::DeletePushRuleJob>("global", "content", m_notificationRules[index]);
|
||||
connect(job, &Quotient::BaseJob::success, this, [this, index]() {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_notificationRules.removeAt(index);
|
||||
endRemoveRows();
|
||||
|
||||
if (m_notificationRules.count() == 0) {
|
||||
NotificationsManager::instance().deactivateKeywordNotificationAction();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> KeywordNotificationRuleModel::roleNames() const
|
||||
{
|
||||
return {{NameRole, QByteArrayLiteral("name")}};
|
||||
}
|
||||
|
||||
#include "moc_keywordnotificationrulemodel.cpp"
|
||||
66
src/models/keywordnotificationrulemodel.h
Normal file
66
src/models/keywordnotificationrulemodel.h
Normal file
@@ -0,0 +1,66 @@
|
||||
// SPDX-FileCopyrightText: 2022 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/csapi/definitions/push_rule.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
/**
|
||||
* @class KeywordNotificationRuleModel
|
||||
*
|
||||
* This class defines the model for managing notification push rule keywords.
|
||||
*/
|
||||
class KeywordNotificationRuleModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Defines the model roles.
|
||||
*/
|
||||
enum EventRoles {
|
||||
NameRole = Qt::DisplayRole, /**< The push rule keyword. */
|
||||
};
|
||||
|
||||
KeywordNotificationRuleModel(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @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 EventRoles, QAbstractItemModel::roleNames()
|
||||
*/
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
/**
|
||||
* @brief Add a new keyword to the model.
|
||||
*/
|
||||
Q_INVOKABLE void addKeyword(const QString &keyword);
|
||||
|
||||
/**
|
||||
* @brief Remove a keyword from the model.
|
||||
*/
|
||||
Q_INVOKABLE void removeKeywordAtIndex(int index);
|
||||
|
||||
private Q_SLOTS:
|
||||
void controllerConnectionChanged();
|
||||
void updateNotificationRules(const QString &type);
|
||||
|
||||
private:
|
||||
QList<QString> m_notificationRules;
|
||||
};
|
||||
@@ -47,8 +47,6 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
|
||||
roles[ReplyDelegateTypeRole] = "replyDelegateType";
|
||||
roles[ReplyDisplayRole] = "replyDisplay";
|
||||
roles[ReplyMediaInfoRole] = "replyMediaInfo";
|
||||
roles[IsThreadedRole] = "isThreaded";
|
||||
roles[ThreadRootRole] = "threadRoot";
|
||||
roles[ShowAuthorRole] = "showAuthor";
|
||||
roles[ShowSectionRole] = "showSection";
|
||||
roles[ReadMarkersRole] = "readMarkers";
|
||||
@@ -100,9 +98,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
||||
room->setDisplayed();
|
||||
|
||||
for (auto event = m_currentRoom->messageEvents().begin(); event != m_currentRoom->messageEvents().end(); ++event) {
|
||||
if (const auto &roomMessageEvent = &*event->viewAs<RoomMessageEvent>()) {
|
||||
createEventObjects(roomMessageEvent);
|
||||
}
|
||||
createEventObjects(&*event->viewAs<RoomMessageEvent>());
|
||||
}
|
||||
|
||||
if (m_currentRoom->timelineSize() < 10 && !room->allHistoryLoaded()) {
|
||||
@@ -122,8 +118,9 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
||||
for (auto &&event : events) {
|
||||
const RoomMessageEvent *message = dynamic_cast<RoomMessageEvent *>(event.get());
|
||||
|
||||
createEventObjects(message);
|
||||
|
||||
if (message != nullptr) {
|
||||
createEventObjects(message);
|
||||
if (NeoChatConfig::self()->showFancyEffects()) {
|
||||
QString planBody = message->plainBody();
|
||||
// snowflake
|
||||
@@ -159,9 +156,8 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
||||
});
|
||||
connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this, [this](RoomEventsRange events) {
|
||||
for (auto &event : events) {
|
||||
if (const auto &roomMessageEvent = dynamic_cast<RoomMessageEvent *>(event.get())) {
|
||||
createEventObjects(roomMessageEvent);
|
||||
}
|
||||
RoomMessageEvent *message = dynamic_cast<RoomMessageEvent *>(event.get());
|
||||
createEventObjects(message);
|
||||
}
|
||||
if (rowCount() > 0) {
|
||||
rowBelowInserted = rowCount() - 1; // See #312
|
||||
@@ -230,9 +226,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
||||
}
|
||||
const auto eventIt = m_currentRoom->findInTimeline(eventId);
|
||||
if (eventIt != m_currentRoom->historyEdge()) {
|
||||
if (const auto &event = dynamic_cast<const RoomMessageEvent *>(&**eventIt)) {
|
||||
createEventObjects(event);
|
||||
}
|
||||
createEventObjects(static_cast<const RoomMessageEvent *>(&**eventIt));
|
||||
}
|
||||
refreshEventRoles(eventId, {ReactionRole, ShowReactionsRole, Qt::DisplayRole});
|
||||
});
|
||||
@@ -272,7 +266,7 @@ int MessageEventModel::timelineBaseIndex() const
|
||||
return m_currentRoom ? int(m_currentRoom->pendingEvents().size()) : 0;
|
||||
}
|
||||
|
||||
void MessageEventModel::refreshEventRoles(int row, const QList<int> &roles)
|
||||
void MessageEventModel::refreshEventRoles(int row, const QVector<int> &roles)
|
||||
{
|
||||
const auto idx = index(row);
|
||||
Q_EMIT dataChanged(idx, idx, roles);
|
||||
@@ -316,7 +310,7 @@ void MessageEventModel::moveReadMarker(const QString &toEventId)
|
||||
endMoveRows();
|
||||
}
|
||||
|
||||
int MessageEventModel::refreshEventRoles(const QString &id, const QList<int> &roles)
|
||||
int MessageEventModel::refreshEventRoles(const QString &id, const QVector<int> &roles)
|
||||
{
|
||||
// On 64-bit platforms, difference_type for std containers is long long
|
||||
// but Qt uses int throughout its interfaces; hence casting to int below.
|
||||
@@ -592,14 +586,6 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
return eventHandler.getReplyMediaInfo();
|
||||
}
|
||||
|
||||
if (role == IsThreadedRole) {
|
||||
return eventHandler.isThreaded();
|
||||
}
|
||||
|
||||
if (role == ThreadRootRole) {
|
||||
return eventHandler.threadRoot();
|
||||
}
|
||||
|
||||
if (role == ShowAuthorRole) {
|
||||
for (auto r = row + 1; r < rowCount(); ++r) {
|
||||
auto i = index(r);
|
||||
@@ -708,6 +694,10 @@ int MessageEventModel::eventIdToRow(const QString &eventID) const
|
||||
|
||||
void MessageEventModel::createEventObjects(const Quotient::RoomMessageEvent *event)
|
||||
{
|
||||
if (event == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto eventId = event->id();
|
||||
|
||||
EventHandler eventHandler;
|
||||
|
||||
@@ -63,9 +63,6 @@ public:
|
||||
ReplyDisplayRole, /**< The body of the message that was replied to. */
|
||||
ReplyMediaInfoRole, /**< The media info of the message that was replied to. */
|
||||
|
||||
IsThreadedRole,
|
||||
ThreadRootRole,
|
||||
|
||||
ShowAuthorRole, /**< Whether the author's name should be shown. */
|
||||
ShowSectionRole, /**< Whether the section header should be shown. */
|
||||
|
||||
@@ -140,8 +137,8 @@ private:
|
||||
void fetchMore(const QModelIndex &parent) override;
|
||||
|
||||
void refreshLastUserEvents(int baseTimelineRow);
|
||||
void refreshEventRoles(int row, const QList<int> &roles = {});
|
||||
int refreshEventRoles(const QString &eventId, const QList<int> &roles = {});
|
||||
void refreshEventRoles(int row, const QVector<int> &roles = {});
|
||||
int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {});
|
||||
void moveReadMarker(const QString &toEventId);
|
||||
|
||||
void createEventObjects(const Quotient::RoomMessageEvent *event);
|
||||
|
||||
@@ -124,20 +124,6 @@ void PublicRoomListModel::setKeyword(const QString &value)
|
||||
Q_EMIT hasMoreChanged();
|
||||
}
|
||||
|
||||
bool PublicRoomListModel::showOnlySpaces() const
|
||||
{
|
||||
return m_showOnlySpaces;
|
||||
}
|
||||
|
||||
void PublicRoomListModel::setShowOnlySpaces(bool showOnlySpaces)
|
||||
{
|
||||
if (showOnlySpaces == m_showOnlySpaces) {
|
||||
return;
|
||||
}
|
||||
m_showOnlySpaces = showOnlySpaces;
|
||||
Q_EMIT showOnlySpacesChanged();
|
||||
}
|
||||
|
||||
void PublicRoomListModel::next(int count)
|
||||
{
|
||||
if (count < 1) {
|
||||
@@ -150,11 +136,7 @@ void PublicRoomListModel::next(int count)
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList roomTypes;
|
||||
if (m_showOnlySpaces) {
|
||||
roomTypes += QLatin1String("m.space");
|
||||
}
|
||||
job = m_connection->callApi<QueryPublicRoomsJob>(m_server, count, nextBatch, QueryPublicRoomsJob::Filter{m_keyword, roomTypes});
|
||||
job = m_connection->callApi<QueryPublicRoomsJob>(m_server, count, nextBatch, QueryPublicRoomsJob::Filter{m_keyword, {}});
|
||||
Q_EMIT loadingChanged();
|
||||
|
||||
connect(job, &BaseJob::finished, this, [this] {
|
||||
|
||||
@@ -45,11 +45,6 @@ class PublicRoomListModel : public QAbstractListModel
|
||||
*/
|
||||
Q_PROPERTY(QString keyword READ keyword WRITE setKeyword NOTIFY keywordChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether only space rooms should be shown.
|
||||
*/
|
||||
Q_PROPERTY(bool showOnlySpaces READ showOnlySpaces WRITE setShowOnlySpaces NOTIFY showOnlySpacesChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether the model has more items to load.
|
||||
*/
|
||||
@@ -108,9 +103,6 @@ public:
|
||||
[[nodiscard]] QString keyword() const;
|
||||
void setKeyword(const QString &value);
|
||||
|
||||
[[nodiscard]] bool showOnlySpaces() const;
|
||||
void setShowOnlySpaces(bool showOnlySpaces);
|
||||
|
||||
[[nodiscard]] bool hasMore() const;
|
||||
|
||||
[[nodiscard]] bool loading() const;
|
||||
@@ -126,13 +118,12 @@ private:
|
||||
Quotient::Connection *m_connection = nullptr;
|
||||
QString m_server;
|
||||
QString m_keyword;
|
||||
bool m_showOnlySpaces = false;
|
||||
|
||||
bool attempted = false;
|
||||
bool m_loading = false;
|
||||
QString nextBatch;
|
||||
|
||||
QList<Quotient::PublicRoomsChunk> rooms;
|
||||
QVector<Quotient::PublicRoomsChunk> rooms;
|
||||
|
||||
Quotient::QueryPublicRoomsJob *job = nullptr;
|
||||
|
||||
@@ -140,7 +131,6 @@ Q_SIGNALS:
|
||||
void connectionChanged();
|
||||
void serverChanged();
|
||||
void keywordChanged();
|
||||
void showOnlySpacesChanged();
|
||||
void hasMoreChanged();
|
||||
void loadingChanged();
|
||||
};
|
||||
|
||||
@@ -66,6 +66,19 @@ PushRuleModel::PushRuleModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
m_defaultKeywordAction = static_cast<PushNotificationAction::Action>(NeoChatConfig::self()->keywordPushRuleDefault());
|
||||
|
||||
if (Controller::instance().activeConnection()) {
|
||||
controllerConnectionChanged();
|
||||
}
|
||||
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, &PushRuleModel::controllerConnectionChanged);
|
||||
}
|
||||
|
||||
void PushRuleModel::controllerConnectionChanged()
|
||||
{
|
||||
if (Controller::instance().activeConnection()) {
|
||||
connect(Controller::instance().activeConnection(), &Quotient::Connection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
|
||||
updateNotificationRules(QStringLiteral("m.push_rules"));
|
||||
}
|
||||
}
|
||||
|
||||
void PushRuleModel::updateNotificationRules(const QString &type)
|
||||
@@ -74,7 +87,7 @@ void PushRuleModel::updateNotificationRules(const QString &type)
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonObject ruleDataJson = m_connection->accountDataJson(QStringLiteral("m.push_rules"));
|
||||
const QJsonObject ruleDataJson = Controller::instance().activeConnection()->accountDataJson(QStringLiteral("m.push_rules"));
|
||||
const Quotient::PushRuleset ruleData = Quotient::fromJson<Quotient::PushRuleset>(ruleDataJson[QStringLiteral("global")].toObject());
|
||||
|
||||
beginResetModel();
|
||||
@@ -93,7 +106,7 @@ void PushRuleModel::updateNotificationRules(const QString &type)
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void PushRuleModel::setRules(QList<Quotient::PushRule> rules, PushNotificationKind::Kind kind)
|
||||
void PushRuleModel::setRules(QVector<Quotient::PushRule> rules, PushNotificationKind::Kind kind)
|
||||
{
|
||||
for (const auto &rule : rules) {
|
||||
QString roomId;
|
||||
@@ -143,7 +156,8 @@ PushNotificationSection::Section PushRuleModel::getSection(Quotient::PushRule ru
|
||||
*
|
||||
* Rooms that the user hasn't joined shouldn't have a rule.
|
||||
*/
|
||||
if (m_connection->room(ruleId) != nullptr) {
|
||||
auto connection = Controller::instance().activeConnection();
|
||||
if (connection->room(ruleId) != nullptr) {
|
||||
return PushNotificationSection::Undefined;
|
||||
}
|
||||
/**
|
||||
@@ -157,7 +171,7 @@ PushNotificationSection::Section PushRuleModel::getSection(Quotient::PushRule ru
|
||||
if (!testUserId.startsWith(u'@')) {
|
||||
testUserId.prepend(u'@');
|
||||
}
|
||||
if (testUserId.startsWith(u'@') && !Quotient::serverPart(testUserId).isEmpty() && m_connection->user(testUserId) != nullptr) {
|
||||
if (testUserId.startsWith(u'@') && !Quotient::serverPart(testUserId).isEmpty() && connection->user(testUserId) != nullptr) {
|
||||
return PushNotificationSection::Undefined;
|
||||
}
|
||||
// If the rule has push conditions and one is a room ID it is a room only keyword.
|
||||
@@ -293,8 +307,8 @@ void PushRuleModel::setPushRuleAction(const QString &id, PushNotificationAction:
|
||||
void PushRuleModel::addKeyword(const QString &keyword, const QString &roomId)
|
||||
{
|
||||
PushNotificationKind::Kind kind = PushNotificationKind::Content;
|
||||
const QList<QVariant> actions = actionToVariant(m_defaultKeywordAction);
|
||||
QList<Quotient::PushCondition> pushConditions;
|
||||
const QVector<QVariant> actions = actionToVariant(m_defaultKeywordAction);
|
||||
QVector<Quotient::PushCondition> pushConditions;
|
||||
if (!roomId.isEmpty()) {
|
||||
kind = PushNotificationKind::Override;
|
||||
|
||||
@@ -311,14 +325,14 @@ void PushRuleModel::addKeyword(const QString &keyword, const QString &roomId)
|
||||
pushConditions.append(keywordCondition);
|
||||
}
|
||||
|
||||
auto job = m_connection->callApi<Quotient::SetPushRuleJob>(QLatin1String("global"),
|
||||
PushNotificationKind::kindString(kind),
|
||||
keyword,
|
||||
actions,
|
||||
QString(),
|
||||
QString(),
|
||||
pushConditions,
|
||||
roomId.isEmpty() ? keyword : QString());
|
||||
auto job = Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleJob>(QLatin1String("global"),
|
||||
PushNotificationKind::kindString(kind),
|
||||
keyword,
|
||||
actions,
|
||||
QString(),
|
||||
QString(),
|
||||
pushConditions,
|
||||
roomId.isEmpty() ? keyword : QString());
|
||||
connect(job, &Quotient::BaseJob::failure, this, [job, keyword]() {
|
||||
qWarning() << QLatin1String("Unable to set push rule for keyword %1: ").arg(keyword) << job->errorString();
|
||||
});
|
||||
@@ -337,7 +351,7 @@ void PushRuleModel::removeKeyword(const QString &keyword)
|
||||
}
|
||||
|
||||
auto kind = PushNotificationKind::kindString(m_rules[index].kind);
|
||||
auto job = m_connection->callApi<Quotient::DeletePushRuleJob>(QStringLiteral("global"), kind, m_rules[index].id);
|
||||
auto job = Controller::instance().activeConnection()->callApi<Quotient::DeletePushRuleJob>(QStringLiteral("global"), kind, m_rules[index].id);
|
||||
connect(job, &Quotient::BaseJob::failure, this, [this, job, index]() {
|
||||
qWarning() << QLatin1String("Unable to remove push rule for keyword %1: ").arg(m_rules[index].id) << job->errorString();
|
||||
});
|
||||
@@ -345,27 +359,27 @@ void PushRuleModel::removeKeyword(const QString &keyword)
|
||||
|
||||
void PushRuleModel::setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled)
|
||||
{
|
||||
auto job = m_connection->callApi<Quotient::IsPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId);
|
||||
connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled, this]() {
|
||||
auto job = Controller::instance().activeConnection()->callApi<Quotient::IsPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId);
|
||||
connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled]() {
|
||||
if (job->enabled() != enabled) {
|
||||
m_connection->callApi<Quotient::SetPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId, enabled);
|
||||
Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId, enabled);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PushRuleModel::setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action)
|
||||
{
|
||||
QList<QVariant> actions;
|
||||
QVector<QVariant> actions;
|
||||
if (ruleId == QStringLiteral(".m.rule.call")) {
|
||||
actions = actionToVariant(action, QStringLiteral("ring"));
|
||||
} else {
|
||||
actions = actionToVariant(action);
|
||||
}
|
||||
|
||||
m_connection->callApi<Quotient::SetPushRuleActionsJob>(QStringLiteral("global"), kind, ruleId, actions);
|
||||
Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleActionsJob>(QStringLiteral("global"), kind, ruleId, actions);
|
||||
}
|
||||
|
||||
PushNotificationAction::Action PushRuleModel::variantToAction(const QList<QVariant> &actions, bool enabled)
|
||||
PushNotificationAction::Action PushRuleModel::variantToAction(const QVector<QVariant> &actions, bool enabled)
|
||||
{
|
||||
bool notify = false;
|
||||
bool isNoisy = false;
|
||||
@@ -408,16 +422,16 @@ PushNotificationAction::Action PushRuleModel::variantToAction(const QList<QVaria
|
||||
}
|
||||
}
|
||||
|
||||
QList<QVariant> PushRuleModel::actionToVariant(PushNotificationAction::Action action, const QString &sound)
|
||||
QVector<QVariant> PushRuleModel::actionToVariant(PushNotificationAction::Action action, const QString &sound)
|
||||
{
|
||||
// The caller should never try to set the state to unknown.
|
||||
// It exists only as a default state to diable the settings options until the actual state is retrieved from the server.
|
||||
if (action == PushNotificationAction::Unknown) {
|
||||
Q_ASSERT(false);
|
||||
return QList<QVariant>();
|
||||
return QVector<QVariant>();
|
||||
}
|
||||
|
||||
QList<QVariant> actions;
|
||||
QVector<QVariant> actions;
|
||||
|
||||
if (action != PushNotificationAction::Off) {
|
||||
actions.append(QStringLiteral("notify"));
|
||||
@@ -439,23 +453,4 @@ QList<QVariant> PushRuleModel::actionToVariant(PushNotificationAction::Action ac
|
||||
return actions;
|
||||
}
|
||||
|
||||
NeoChatConnection *PushRuleModel::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void PushRuleModel::setConnection(NeoChatConnection *connection)
|
||||
{
|
||||
if (connection == m_connection) {
|
||||
return;
|
||||
}
|
||||
m_connection = connection;
|
||||
Q_EMIT connectionChanged();
|
||||
|
||||
if (m_connection) {
|
||||
connect(m_connection, &Quotient::Connection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
|
||||
updateNotificationRules(QStringLiteral("m.push_rules"));
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_pushrulemodel.cpp"
|
||||
|
||||
@@ -157,8 +157,6 @@ class PushRuleModel : public QAbstractListModel
|
||||
*/
|
||||
Q_PROPERTY(bool globalNotificationsSet READ globalNotificationsSet NOTIFY globalNotificationsSetChanged)
|
||||
|
||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
public:
|
||||
struct Rule {
|
||||
QString id;
|
||||
@@ -227,31 +225,27 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void removeKeyword(const QString &keyword);
|
||||
|
||||
void setConnection(NeoChatConnection *connection);
|
||||
NeoChatConnection *connection() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void defaultStateChanged();
|
||||
void globalNotificationsEnabledChanged();
|
||||
void globalNotificationsSetChanged();
|
||||
void connectionChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void controllerConnectionChanged();
|
||||
void updateNotificationRules(const QString &type);
|
||||
|
||||
private:
|
||||
PushNotificationAction::Action m_defaultKeywordAction;
|
||||
QList<Rule> m_rules;
|
||||
NeoChatConnection *m_connection;
|
||||
|
||||
void setRules(QList<Quotient::PushRule> rules, PushNotificationKind::Kind kind);
|
||||
void setRules(QVector<Quotient::PushRule> rules, PushNotificationKind::Kind kind);
|
||||
|
||||
int getRuleIndex(const QString &ruleId) const;
|
||||
PushNotificationSection::Section getSection(Quotient::PushRule rule);
|
||||
|
||||
void setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled);
|
||||
void setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action);
|
||||
PushNotificationAction::Action variantToAction(const QList<QVariant> &actions, bool enabled);
|
||||
QList<QVariant> actionToVariant(PushNotificationAction::Action action, const QString &sound = QStringLiteral("default"));
|
||||
PushNotificationAction::Action variantToAction(const QVector<QVariant> &actions, bool enabled);
|
||||
QVector<QVariant> actionToVariant(PushNotificationAction::Action action, const QString &sound = QStringLiteral("default"));
|
||||
};
|
||||
Q_DECLARE_METATYPE(PushRuleModel *)
|
||||
|
||||
@@ -368,14 +368,11 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
|
||||
if (role == IsChildSpaceRole) {
|
||||
return SpaceHierarchyCache::instance().isChildSpace(room->id());
|
||||
}
|
||||
if (role == ReplacementIdRole) {
|
||||
return room->successorId();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void RoomListModel::refresh(NeoChatRoom *room, const QList<int> &roles)
|
||||
void RoomListModel::refresh(NeoChatRoom *room, const QVector<int> &roles)
|
||||
{
|
||||
const auto it = std::find(m_rooms.begin(), m_rooms.end(), room);
|
||||
if (it == m_rooms.end()) {
|
||||
|
||||
@@ -79,7 +79,6 @@ public:
|
||||
RoomIdRole, /**< The room matrix ID. */
|
||||
IsSpaceRole, /**< Whether the room is a space. */
|
||||
IsChildSpaceRole, /**< Whether this space is a child of a different space. */
|
||||
ReplacementIdRole, /**< The room id of the room replacing this one, if any. */
|
||||
};
|
||||
Q_ENUM(EventRoles)
|
||||
|
||||
@@ -159,7 +158,7 @@ private Q_SLOTS:
|
||||
void doAddRoom(Quotient::Room *room);
|
||||
void updateRoom(Quotient::Room *room, Quotient::Room *prev);
|
||||
void deleteRoom(Quotient::Room *room);
|
||||
void refresh(NeoChatRoom *room, const QList<int> &roles = {});
|
||||
void refresh(NeoChatRoom *room, const QVector<int> &roles = {});
|
||||
void refreshNotificationCount();
|
||||
void refreshHighlightCount();
|
||||
|
||||
|
||||
@@ -11,15 +11,14 @@
|
||||
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
#include <KSharedConfig>
|
||||
|
||||
ServerListModel::ServerListModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
const auto stateConfig = KSharedConfig::openStateConfig();
|
||||
const KConfigGroup serverGroup = stateConfig->group(QStringLiteral("Servers"));
|
||||
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
|
||||
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
|
||||
|
||||
QString domain = m_connection->domain();
|
||||
QString domain = Controller::instance().activeConnection()->domain();
|
||||
|
||||
// Add the user's homeserver
|
||||
m_servers.append(Server{
|
||||
@@ -92,15 +91,15 @@ int ServerListModel::rowCount(const QModelIndex &parent) const
|
||||
|
||||
void ServerListModel::checkServer(const QString &url)
|
||||
{
|
||||
const auto stateConfig = KSharedConfig::openStateConfig();
|
||||
const KConfigGroup serverGroup = stateConfig->group(QStringLiteral("Servers"));
|
||||
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
|
||||
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
|
||||
|
||||
if (!serverGroup.hasKey(url)) {
|
||||
if (Quotient::isJobPending(m_checkServerJob)) {
|
||||
m_checkServerJob->abandon();
|
||||
}
|
||||
|
||||
m_checkServerJob = m_connection->callApi<Quotient::QueryPublicRoomsJob>(url, 1);
|
||||
m_checkServerJob = Controller::instance().activeConnection()->callApi<Quotient::QueryPublicRoomsJob>(url, 1);
|
||||
connect(m_checkServerJob, &Quotient::BaseJob::success, this, [this, url] {
|
||||
Q_EMIT serverCheckComplete(url, true);
|
||||
});
|
||||
@@ -109,8 +108,8 @@ void ServerListModel::checkServer(const QString &url)
|
||||
|
||||
void ServerListModel::addServer(const QString &url)
|
||||
{
|
||||
const auto stateConfig = KSharedConfig::openStateConfig();
|
||||
KConfigGroup serverGroup = stateConfig->group(QStringLiteral("Servers"));
|
||||
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
|
||||
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
|
||||
|
||||
if (!serverGroup.hasKey(url)) {
|
||||
Server newServer = Server{
|
||||
@@ -126,21 +125,17 @@ void ServerListModel::addServer(const QString &url)
|
||||
}
|
||||
|
||||
serverGroup.writeEntry(url, url);
|
||||
stateConfig->sync();
|
||||
}
|
||||
|
||||
void ServerListModel::removeServerAtIndex(int row)
|
||||
{
|
||||
const auto stateConfig = KSharedConfig::openStateConfig();
|
||||
KConfigGroup serverGroup = stateConfig->group(QStringLiteral("Servers"));
|
||||
|
||||
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
|
||||
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
|
||||
serverGroup.deleteEntry(data(index(row), UrlRole).toString());
|
||||
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_servers.removeAt(row);
|
||||
endRemoveRows();
|
||||
|
||||
stateConfig->sync();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ServerListModel::roleNames() const
|
||||
@@ -153,18 +148,4 @@ QHash<int, QByteArray> ServerListModel::roleNames() const
|
||||
};
|
||||
}
|
||||
|
||||
NeoChatConnection *ServerListModel::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void ServerListModel::setConnection(NeoChatConnection *connection)
|
||||
{
|
||||
if (m_connection == connection) {
|
||||
return;
|
||||
}
|
||||
m_connection = connection;
|
||||
Q_EMIT connectionChanged();
|
||||
}
|
||||
|
||||
#include "moc_serverlistmodel.cpp"
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <QQmlEngine>
|
||||
#include <QUrl>
|
||||
|
||||
class NeoChatConnection;
|
||||
|
||||
/**
|
||||
* @class ServerListModel
|
||||
*
|
||||
@@ -29,8 +27,6 @@ class ServerListModel : public QAbstractListModel
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Define the data required to represent a server.
|
||||
@@ -100,15 +96,10 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void removeServerAtIndex(int index);
|
||||
|
||||
NeoChatConnection *connection() const;
|
||||
void setConnection(NeoChatConnection *connection);
|
||||
|
||||
Q_SIGNALS:
|
||||
void serverCheckComplete(QString url, bool valid);
|
||||
void connectionChanged();
|
||||
|
||||
private:
|
||||
QList<Server> m_servers;
|
||||
QPointer<Quotient::QueryPublicRoomsJob> m_checkServerJob = nullptr;
|
||||
NeoChatConnection *m_connection = nullptr;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user