Compare commits
151 Commits
work/fix_c
...
v24.01.75
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
819d88e18c | ||
|
|
dbbad2cf13 | ||
|
|
08b84c6592 | ||
|
|
b8abf0540d | ||
|
|
7f9e709559 | ||
|
|
c4f6abee9d | ||
|
|
1a4947b98a | ||
|
|
6ba2b715c3 | ||
|
|
e9e1e223f7 | ||
|
|
006da1fb16 | ||
|
|
3aff1795c8 | ||
|
|
576b1f928f | ||
|
|
fc3ab50701 | ||
|
|
e7fa3ad524 | ||
|
|
5adffddbd8 | ||
|
|
1d95d5aa15 | ||
|
|
dabd6291a5 | ||
|
|
0e55c3b38f | ||
|
|
ff4cf86ea5 | ||
|
|
f4d5ccbf12 | ||
|
|
192601d358 | ||
|
|
d7c432119e | ||
|
|
eddb2b73c2 | ||
|
|
0c60bfdb83 | ||
|
|
2bfb2fa1f9 | ||
|
|
d1aac971bf | ||
|
|
284cadf305 | ||
|
|
4697b7fcf1 | ||
|
|
9f356912c9 | ||
|
|
1cf891f845 | ||
|
|
52e2d636b9 | ||
|
|
dc6b539ddf | ||
|
|
e3cf85aa8c | ||
|
|
2065eb6684 | ||
|
|
9cac2a8abd | ||
|
|
feb87e6f70 | ||
|
|
a0057b8a49 | ||
|
|
dbb0269354 | ||
|
|
7fdb617b33 | ||
|
|
d798b0dec9 | ||
|
|
95cf23eb5b | ||
|
|
7e3db20229 | ||
|
|
12689babfb | ||
|
|
211407da44 | ||
|
|
400a84e48d | ||
|
|
7a45640e5e | ||
|
|
8af20885ab | ||
|
|
4033f07272 | ||
|
|
5df4fa297d | ||
|
|
33c5b418d2 | ||
|
|
69d378a17b | ||
|
|
f1b1b8ce53 | ||
|
|
526d4748e0 | ||
|
|
c5f93adbf4 | ||
|
|
61630cbe90 | ||
|
|
8c435e9d6d | ||
|
|
57978b1a6e | ||
|
|
f3c4d9449a | ||
|
|
9b37777f20 | ||
|
|
d6d6c161db | ||
|
|
772bca5ba6 | ||
|
|
036a60a095 | ||
|
|
b3315e1ed4 | ||
|
|
d300e9cf52 | ||
|
|
1f4bcd150f | ||
|
|
9ad8894983 | ||
|
|
9e63ca5eb7 | ||
|
|
ade66242bb | ||
|
|
2c6932b4cb | ||
|
|
5cce9e7205 | ||
|
|
7dd3ad9548 | ||
|
|
f690b76efa | ||
|
|
87b8d6710e | ||
|
|
965b890346 | ||
|
|
02b4e5cc70 | ||
|
|
410add04fb | ||
|
|
b575b1e700 | ||
|
|
5828ee1ada | ||
|
|
a64c80109e | ||
|
|
de47f7f2fa | ||
|
|
19adc7b9e5 | ||
|
|
23f60a59fe | ||
|
|
946ba2e56d | ||
|
|
9dcb7b49fa | ||
|
|
52f5901642 | ||
|
|
d4b4a7e1ff | ||
|
|
4449678b74 | ||
|
|
19e197e0ec | ||
|
|
cfc5202645 | ||
|
|
9b80d9e7aa | ||
|
|
dc409387bd | ||
|
|
1e73a7bda4 | ||
|
|
ef1d62d45c | ||
|
|
c2d82750b1 | ||
|
|
c97d276b36 | ||
|
|
681a0b1e93 | ||
|
|
39556f45ab | ||
|
|
3c7774800a | ||
|
|
bc7530eaa1 | ||
|
|
82d11f79d6 | ||
|
|
25d0368d41 | ||
|
|
83b7e7d121 | ||
|
|
26fd26f9fd | ||
|
|
0029567c3a | ||
|
|
c7614caf41 | ||
|
|
6571dbe554 | ||
|
|
b3a29068cc | ||
|
|
5adda55a85 | ||
|
|
d56f0d6086 | ||
|
|
60772be391 | ||
|
|
27f1679741 | ||
|
|
838596c3ae | ||
|
|
a57744891a | ||
|
|
f5417a6227 | ||
|
|
ac6f9ea219 | ||
|
|
4b49559d39 | ||
|
|
baa33f1843 | ||
|
|
dae5718c6c | ||
|
|
60260cff3b | ||
|
|
2df9a26cdc | ||
|
|
b16cd12b33 | ||
|
|
6a3b22ef2d | ||
|
|
b28a85ff05 | ||
|
|
e480299563 | ||
|
|
fe70e2773f | ||
|
|
e78ea4721a | ||
|
|
1699dcf0c4 | ||
|
|
9d6aef6c2b | ||
|
|
a9c2428498 | ||
|
|
0730f15e2b | ||
|
|
136856f3c3 | ||
|
|
763b6af076 | ||
|
|
ac231320a3 | ||
|
|
87aee162f1 | ||
|
|
0899db31af | ||
|
|
b4198bc13b | ||
|
|
c6bfe73d26 | ||
|
|
d490dffa36 | ||
|
|
43b2b71b73 | ||
|
|
39a51d1f35 | ||
|
|
2eb26ffbb3 | ||
|
|
87ef55215f | ||
|
|
f6186aad2e | ||
|
|
2251edbf86 | ||
|
|
1c55649740 | ||
|
|
aa0b6613de | ||
|
|
f948e813b6 | ||
|
|
b5c6411aad | ||
|
|
b1daa76d9f | ||
|
|
7180fa022b | ||
|
|
17bc08270d |
@@ -19,6 +19,7 @@
|
|||||||
"--talk-name=org.freedesktop.Notifications",
|
"--talk-name=org.freedesktop.Notifications",
|
||||||
"--talk-name=org.kde.kwalletd5",
|
"--talk-name=org.kde.kwalletd5",
|
||||||
"--talk-name=org.kde.StatusNotifierWatcher",
|
"--talk-name=org.kde.StatusNotifierWatcher",
|
||||||
|
"--talk-name=org.freedesktop.secrets",
|
||||||
"--own-name=org.kde.StatusNotifierItem-2-2"
|
"--own-name=org.kde.StatusNotifierItem-2-2"
|
||||||
],
|
],
|
||||||
"modules": [
|
"modules": [
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
include:
|
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/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/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/windows-qt6.yml
|
||||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
|
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ Dependencies:
|
|||||||
'frameworks/kitemmodels': '@latest-kf6'
|
'frameworks/kitemmodels': '@latest-kf6'
|
||||||
'frameworks/kquickcharts': '@latest-kf6'
|
'frameworks/kquickcharts': '@latest-kf6'
|
||||||
'frameworks/knotifications': '@latest-kf6'
|
'frameworks/knotifications': '@latest-kf6'
|
||||||
|
'frameworks/kcolorscheme': '@latest-kf6'
|
||||||
'libraries/kquickimageeditor': '@latest-kf6'
|
'libraries/kquickimageeditor': '@latest-kf6'
|
||||||
'frameworks/sonnet': '@latest-kf6'
|
'frameworks/sonnet': '@latest-kf6'
|
||||||
|
'frameworks/prison': '@latest-kf6'
|
||||||
'libraries/kirigami-addons': '@latest-kf6'
|
'libraries/kirigami-addons': '@latest-kf6'
|
||||||
'third-party/libquotient': '@latest'
|
'third-party/libquotient': '@latest'
|
||||||
'third-party/qtkeychain': '@latest'
|
'third-party/qtkeychain': '@latest'
|
||||||
@@ -25,7 +27,6 @@ Dependencies:
|
|||||||
'frameworks/qqc2-desktop-style': '@latest-kf6'
|
'frameworks/qqc2-desktop-style': '@latest-kf6'
|
||||||
'frameworks/kio': '@latest-kf6'
|
'frameworks/kio': '@latest-kf6'
|
||||||
'frameworks/kwindowsystem': '@latest-kf6'
|
'frameworks/kwindowsystem': '@latest-kf6'
|
||||||
'frameworks/kconfigwidgets': '@latest-kf6'
|
|
||||||
- 'on': ['Linux', 'FreeBSD']
|
- 'on': ['Linux', 'FreeBSD']
|
||||||
'require':
|
'require':
|
||||||
'frameworks/kdbusaddons': '@latest-kf6'
|
'frameworks/kdbusaddons': '@latest-kf6'
|
||||||
|
|||||||
@@ -41,3 +41,7 @@ License: CC0-1.0
|
|||||||
Files: .flatpak-manifest.json
|
Files: .flatpak-manifest.json
|
||||||
Copyright: 2020-2022 Tobias Fella <tobias.fella@kde.org>
|
Copyright: 2020-2022 Tobias Fella <tobias.fella@kde.org>
|
||||||
License: BSD-2-Clause
|
License: BSD-2-Clause
|
||||||
|
|
||||||
|
Files: autotests/data/*
|
||||||
|
Copyright: none
|
||||||
|
License: CC0-1.0
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
# KDE Applications version, managed by release script.
|
# KDE Applications version, managed by release script.
|
||||||
set(RELEASE_SERVICE_VERSION_MAJOR "23")
|
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||||
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
set(RELEASE_SERVICE_VERSION_MINOR "01")
|
||||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
set(RELEASE_SERVICE_VERSION_MICRO "75")
|
||||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||||
|
|
||||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||||
@@ -37,6 +37,7 @@ include(ECMAddAppIcon)
|
|||||||
include(KDEGitCommitHooks)
|
include(KDEGitCommitHooks)
|
||||||
include(ECMCheckOutboundLicense)
|
include(ECMCheckOutboundLicense)
|
||||||
include(ECMQtDeclareLoggingCategory)
|
include(ECMQtDeclareLoggingCategory)
|
||||||
|
include(ECMAddAndroidApk)
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
include(KDEClangFormat)
|
include(KDEClangFormat)
|
||||||
endif()
|
endif()
|
||||||
@@ -57,7 +58,7 @@ set_package_properties(Qt6 PROPERTIES
|
|||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
PURPOSE "Basic application components"
|
PURPOSE "Basic application components"
|
||||||
)
|
)
|
||||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels)
|
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
|
||||||
set_package_properties(KF6 PROPERTIES
|
set_package_properties(KF6 PROPERTIES
|
||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
PURPOSE "Basic application components"
|
PURPOSE "Basic application components"
|
||||||
@@ -76,7 +77,7 @@ if(ANDROID)
|
|||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
|
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
|
||||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle ConfigWidgets KIO WindowSystem StatusNotifierItem)
|
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem)
|
||||||
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
|
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
|
||||||
TYPE RUNTIME
|
TYPE RUNTIME
|
||||||
)
|
)
|
||||||
@@ -101,7 +102,8 @@ set_package_properties(QuotientQt6 PROPERTIES
|
|||||||
PURPOSE "Talk with matrix server"
|
PURPOSE "Talk with matrix server"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT TARGET Olm::Olm)
|
# The android part is just for CI. We do NOT support any builds without E2EE
|
||||||
|
if (NOT TARGET Olm::Olm AND NOT ANDROID)
|
||||||
message(FATAL_ERROR "NeoChat requires Quotient with the E2EE feature enabled")
|
message(FATAL_ERROR "NeoChat requires Quotient with the E2EE feature enabled")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -117,7 +119,8 @@ set_package_properties(cmark PROPERTIES
|
|||||||
ecm_find_qmlmodule(org.kde.kquickimageeditor 1.0)
|
ecm_find_qmlmodule(org.kde.kquickimageeditor 1.0)
|
||||||
ecm_find_qmlmodule(org.kde.kitemmodels 1.0)
|
ecm_find_qmlmodule(org.kde.kitemmodels 1.0)
|
||||||
ecm_find_qmlmodule(org.kde.quickcharts 1.0)
|
ecm_find_qmlmodule(org.kde.quickcharts 1.0)
|
||||||
ecm_find_qmlmodule(QtLocation ${QTLOCATION_MODULE_QML_VERSION})
|
ecm_find_qmlmodule(QtLocation)
|
||||||
|
ecm_find_qmlmodule(org.kde.prison)
|
||||||
|
|
||||||
find_package(KQuickImageEditor COMPONENTS)
|
find_package(KQuickImageEditor COMPONENTS)
|
||||||
set_package_properties(KQuickImageEditor PROPERTIES
|
set_package_properties(KQuickImageEditor PROPERTIES
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
android:versionName="${versionName}"
|
android:versionName="${versionName}"
|
||||||
android:versionCode="${versionCode}"
|
android:versionCode="${versionCode}"
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
<application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="NeoChat" android:icon="@drawable/neochat" android:usesCleartextTraffic="true">
|
<application android:name="org.qtproject.qt.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"
|
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
|
||||||
android:name="org.qtproject.qt5.android.bindings.QtActivity"
|
android:name="org.qtproject.qt.android.bindings.QtActivity"
|
||||||
android:label="NeoChat"
|
android:label="NeoChat"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.0.2'
|
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ android {
|
|||||||
* The following variables:
|
* The following variables:
|
||||||
* - androidBuildToolsVersion,
|
* - androidBuildToolsVersion,
|
||||||
* - androidCompileSdkVersion
|
* - androidCompileSdkVersion
|
||||||
* - qt5AndroidDir - holds the path to qt android files
|
* - qtAndroidDir - holds the path to qt android files
|
||||||
* needed to build any Qt application
|
* needed to build any Qt application
|
||||||
* on Android.
|
* on Android.
|
||||||
*
|
*
|
||||||
@@ -44,17 +44,20 @@ android {
|
|||||||
* Changing them manually might break the compilation!
|
* Changing them manually might break the compilation!
|
||||||
*******************************************************/
|
*******************************************************/
|
||||||
|
|
||||||
compileSdkVersion androidCompileSdkVersion.toInteger()
|
compileSdkVersion androidCompileSdkVersion
|
||||||
|
|
||||||
buildToolsVersion androidBuildToolsVersion
|
buildToolsVersion androidBuildToolsVersion
|
||||||
ndkVersion androidNdkVersion
|
ndkVersion androidNdkVersion
|
||||||
|
|
||||||
|
// Extract native libraries from the APK
|
||||||
|
packagingOptions.jniLibs.useLegacyPackaging true
|
||||||
|
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
manifest.srcFile 'AndroidManifest.xml'
|
manifest.srcFile 'AndroidManifest.xml'
|
||||||
java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
|
java.srcDirs = [qtAndroidDir + '/src', 'src', 'java']
|
||||||
aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
|
aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl']
|
||||||
res.srcDirs = [qt5AndroidDir + '/res', 'res']
|
res.srcDirs = [qtAndroidDir + '/res', 'res']
|
||||||
resources.srcDirs = ['src']
|
resources.srcDirs = ['src']
|
||||||
renderscript.srcDirs = ['src']
|
renderscript.srcDirs = ['src']
|
||||||
assets.srcDirs = ['assets']
|
assets.srcDirs = ['assets']
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
|
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" )
|
||||||
|
|
||||||
ecm_add_test(
|
ecm_add_test(
|
||||||
neochatroomtest.cpp
|
neochatroomtest.cpp
|
||||||
LINK_LIBRARIES neochat Qt::Test
|
LINK_LIBRARIES neochat Qt::Test
|
||||||
@@ -32,3 +34,15 @@ ecm_add_test(
|
|||||||
LINK_LIBRARIES neochat Qt::Test
|
LINK_LIBRARIES neochat Qt::Test
|
||||||
TEST_NAME eventhandlertest
|
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
|
||||||
|
)
|
||||||
|
|||||||
157
autotests/chatbarcachetest.cpp
Normal file
157
autotests/chatbarcachetest.cpp
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
// 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"
|
||||||
36
autotests/chatdocumenthandlertest.cpp
Normal file
36
autotests/chatdocumenthandlertest.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// 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"
|
||||||
381
autotests/data/test-eventhandler-sync.json
Normal file
381
autotests/data/test-eventhandler-sync.json
Normal file
@@ -0,0 +1,381 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
87
autotests/data/test-min-sync.json
Normal file
87
autotests/data/test-min-sync.json
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
124
autotests/data/test-texthandler-sync.json
Normal file
124
autotests/data/test-texthandler-sync.json
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
{
|
||||||
|
"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,33 +39,61 @@ private:
|
|||||||
Connection *connection = nullptr;
|
Connection *connection = nullptr;
|
||||||
TestRoom *room = nullptr;
|
TestRoom *room = nullptr;
|
||||||
EventHandler eventHandler;
|
EventHandler eventHandler;
|
||||||
|
EventHandler emptyHandler;
|
||||||
|
EventHandler noEventHandler;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
|
|
||||||
|
void nullSetEvent();
|
||||||
void eventId();
|
void eventId();
|
||||||
|
void nullEventId();
|
||||||
void delegateType_data();
|
void delegateType_data();
|
||||||
void delegateType();
|
void delegateType();
|
||||||
|
void nullDelegateType();
|
||||||
void author();
|
void author();
|
||||||
|
void nullAuthor();
|
||||||
void authorDisplayName();
|
void authorDisplayName();
|
||||||
|
void nullAuthorDisplayName();
|
||||||
void time();
|
void time();
|
||||||
|
void nullTime();
|
||||||
void timeString();
|
void timeString();
|
||||||
|
void nullTimeString();
|
||||||
void highlighted();
|
void highlighted();
|
||||||
|
void nullHighlighted();
|
||||||
void hidden();
|
void hidden();
|
||||||
|
void nullHidden();
|
||||||
void body();
|
void body();
|
||||||
|
void nullBody();
|
||||||
void genericBody_data();
|
void genericBody_data();
|
||||||
void genericBody();
|
void genericBody();
|
||||||
|
void nullGenericBody();
|
||||||
void mediaInfo();
|
void mediaInfo();
|
||||||
|
void nullMediaInfo();
|
||||||
void linkPreviewer();
|
void linkPreviewer();
|
||||||
|
void nullLinkPreviewer();
|
||||||
void reactions();
|
void reactions();
|
||||||
|
void nullReactions();
|
||||||
void hasReply();
|
void hasReply();
|
||||||
|
void nullHasReply();
|
||||||
void replyId();
|
void replyId();
|
||||||
|
void nullReplyId();
|
||||||
void replyDelegateType();
|
void replyDelegateType();
|
||||||
|
void nullReplyDelegateType();
|
||||||
void replyAuthor();
|
void replyAuthor();
|
||||||
|
void nullReplyAuthor();
|
||||||
void replyBody();
|
void replyBody();
|
||||||
|
void nullReplyBody();
|
||||||
void replyMediaInfo();
|
void replyMediaInfo();
|
||||||
|
void nullReplyMediaInfo();
|
||||||
|
void thread();
|
||||||
|
void nullThread();
|
||||||
void location();
|
void location();
|
||||||
|
void nullLocation();
|
||||||
void readMarkers();
|
void readMarkers();
|
||||||
|
void nullReadMarkers();
|
||||||
|
|
||||||
|
void cleanup();
|
||||||
};
|
};
|
||||||
|
|
||||||
void EventHandlerTest::initTestCase()
|
void EventHandlerTest::initTestCase()
|
||||||
@@ -73,332 +101,21 @@ void EventHandlerTest::initTestCase()
|
|||||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||||
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
||||||
|
|
||||||
const auto json = QJsonDocument::fromJson(R"EVENT({
|
QFile testEventHandlerSyncFile;
|
||||||
"account_data": {
|
testEventHandlerSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-eventhandler-sync.json"));
|
||||||
"events": [
|
testEventHandlerSyncFile.open(QIODevice::ReadOnly);
|
||||||
{
|
const auto testEventHandlerSyncJson = QJsonDocument::fromJson(testEventHandlerSyncFile.readAll());
|
||||||
"content": {
|
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testEventHandlerSyncJson.object());
|
||||||
"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));
|
room->update(std::move(roomData));
|
||||||
|
|
||||||
eventHandler.setRoom(room);
|
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()
|
void EventHandlerTest::eventId()
|
||||||
@@ -408,6 +125,12 @@ void EventHandlerTest::eventId()
|
|||||||
QCOMPARE(eventHandler.getId(), QStringLiteral("$153456789:example.org"));
|
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()
|
void EventHandlerTest::delegateType_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<int>("eventNum");
|
QTest::addColumn<int>("eventNum");
|
||||||
@@ -431,6 +154,12 @@ void EventHandlerTest::delegateType()
|
|||||||
QCOMPARE(eventHandler.getDelegateType(), 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()
|
void EventHandlerTest::author()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(0).get();
|
auto event = room->messageEvents().at(0).get();
|
||||||
@@ -448,6 +177,15 @@ void EventHandlerTest::author()
|
|||||||
QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(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()
|
void EventHandlerTest::authorDisplayName()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(1).get();
|
auto event = room->messageEvents().at(1).get();
|
||||||
@@ -456,6 +194,15 @@ void EventHandlerTest::authorDisplayName()
|
|||||||
QCOMPARE(eventHandler.getAuthorDisplayName(), QStringLiteral("before"));
|
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()
|
void EventHandlerTest::time()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(0).get();
|
auto event = room->messageEvents().at(0).get();
|
||||||
@@ -465,6 +212,16 @@ void EventHandlerTest::time()
|
|||||||
QCOMPARE(eventHandler.getTime(true, QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC)), QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC));
|
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()
|
void EventHandlerTest::timeString()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(0).get();
|
auto event = room->messageEvents().at(0).get();
|
||||||
@@ -486,6 +243,16 @@ void EventHandlerTest::timeString()
|
|||||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat));
|
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()
|
void EventHandlerTest::highlighted()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(2).get();
|
auto event = room->messageEvents().at(2).get();
|
||||||
@@ -499,6 +266,15 @@ void EventHandlerTest::highlighted()
|
|||||||
QCOMPARE(eventHandler.isHighlighted(), false);
|
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()
|
void EventHandlerTest::hidden()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(3).get();
|
auto event = room->messageEvents().at(3).get();
|
||||||
@@ -512,6 +288,15 @@ void EventHandlerTest::hidden()
|
|||||||
QCOMPARE(eventHandler.isHidden(), false);
|
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()
|
void EventHandlerTest::body()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(0).get();
|
auto event = room->messageEvents().at(0).get();
|
||||||
@@ -523,6 +308,15 @@ void EventHandlerTest::body()
|
|||||||
QCOMPARE(eventHandler.getPlainBody(true), QStringLiteral("This is an example text message"));
|
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()
|
void EventHandlerTest::genericBody_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<int>("eventNum");
|
QTest::addColumn<int>("eventNum");
|
||||||
@@ -545,6 +339,12 @@ void EventHandlerTest::genericBody()
|
|||||||
QCOMPARE(eventHandler.getGenericBody(), output);
|
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()
|
void EventHandlerTest::mediaInfo()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(4).get();
|
auto event = room->messageEvents().at(4).get();
|
||||||
@@ -568,6 +368,15 @@ void EventHandlerTest::mediaInfo()
|
|||||||
QCOMPARE(thumbnailInfo["height"_ls], 450);
|
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()
|
void EventHandlerTest::linkPreviewer()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(2).get();
|
auto event = room->messageEvents().at(2).get();
|
||||||
@@ -581,6 +390,15 @@ void EventHandlerTest::linkPreviewer()
|
|||||||
QCOMPARE(eventHandler.getLinkPreviewer(), nullptr);
|
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()
|
void EventHandlerTest::reactions()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(0).get();
|
auto event = room->messageEvents().at(0).get();
|
||||||
@@ -589,6 +407,15 @@ void EventHandlerTest::reactions()
|
|||||||
QCOMPARE(eventHandler.getReactions()->rowCount(), 1);
|
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()
|
void EventHandlerTest::hasReply()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(5).get();
|
auto event = room->messageEvents().at(5).get();
|
||||||
@@ -602,6 +429,12 @@ void EventHandlerTest::hasReply()
|
|||||||
QCOMPARE(eventHandler.hasReply(), false);
|
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()
|
void EventHandlerTest::replyId()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(5).get();
|
auto event = room->messageEvents().at(5).get();
|
||||||
@@ -615,6 +448,12 @@ void EventHandlerTest::replyId()
|
|||||||
QCOMPARE(eventHandler.getReplyId(), QStringLiteral(""));
|
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()
|
void EventHandlerTest::replyDelegateType()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(5).get();
|
auto event = room->messageEvents().at(5).get();
|
||||||
@@ -628,6 +467,15 @@ void EventHandlerTest::replyDelegateType()
|
|||||||
QCOMPARE(eventHandler.getReplyDelegateType(), DelegateType::Other);
|
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()
|
void EventHandlerTest::replyAuthor()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(5).get();
|
auto event = room->messageEvents().at(5).get();
|
||||||
@@ -651,6 +499,15 @@ void EventHandlerTest::replyAuthor()
|
|||||||
QCOMPARE(eventHandler.getReplyAuthor(), room->getUser(nullptr));
|
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()
|
void EventHandlerTest::replyBody()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(5).get();
|
auto event = room->messageEvents().at(5).get();
|
||||||
@@ -662,6 +519,15 @@ void EventHandlerTest::replyBody()
|
|||||||
QCOMPARE(eventHandler.getReplyPlainBody(true), QStringLiteral("This is an example text message"));
|
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()
|
void EventHandlerTest::replyMediaInfo()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(6).get();
|
auto event = room->messageEvents().at(6).get();
|
||||||
@@ -686,6 +552,47 @@ void EventHandlerTest::replyMediaInfo()
|
|||||||
QCOMPARE(thumbnailInfo["height"_ls], 450);
|
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()
|
void EventHandlerTest::location()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(7).get();
|
auto event = room->messageEvents().at(7).get();
|
||||||
@@ -696,6 +603,18 @@ void EventHandlerTest::location()
|
|||||||
QCOMPARE(eventHandler.getLocationAssetType(), QStringLiteral("m.pin"));
|
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()
|
void EventHandlerTest::readMarkers()
|
||||||
{
|
{
|
||||||
auto event = room->messageEvents().at(0).get();
|
auto event = room->messageEvents().at(0).get();
|
||||||
@@ -725,5 +644,37 @@ void EventHandlerTest::readMarkers()
|
|||||||
QCOMPARE(eventHandler.getReadMarkersString().startsWith(QStringLiteral("6 users:")), true);
|
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)
|
QTEST_MAIN(EventHandlerTest)
|
||||||
#include "eventhandlertest.moc"
|
#include "eventhandlertest.moc"
|
||||||
|
|||||||
@@ -42,101 +42,18 @@ void NeoChatRoomTest::initTestCase()
|
|||||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||||
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
||||||
|
|
||||||
auto json = QJsonDocument::fromJson(R"EVENT({
|
QFile testMinSyncFile;
|
||||||
"account_data": {
|
testMinSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-min-sync.json"));
|
||||||
"events": [
|
testMinSyncFile.open(QIODevice::ReadOnly);
|
||||||
{
|
const auto testMinSyncJson = QJsonDocument::fromJson(testMinSyncFile.readAll());
|
||||||
"content": {
|
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testMinSyncJson.object());
|
||||||
"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));
|
room->update(std::move(roomData));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NeoChatRoomTest::subtitleTextTest()
|
void NeoChatRoomTest::subtitleTextTest()
|
||||||
{
|
{
|
||||||
QCOMPARE(room->timelineSize(), 1);
|
QCOMPARE(room->timelineSize(), 1);
|
||||||
QCOMPARE(room->lastEventToString(), QStringLiteral("@example:example.org: This is an example text message"));
|
QCOMPARE(room->lastEventToString(), QStringLiteral("@example:example.org: This is an example\ntext message"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NeoChatRoomTest::eventTest()
|
void NeoChatRoomTest::eventTest()
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ private Q_SLOTS:
|
|||||||
void stripDisallowedTags();
|
void stripDisallowedTags();
|
||||||
void stripDisallowedAttributes();
|
void stripDisallowedAttributes();
|
||||||
void emptyCodeTags();
|
void emptyCodeTags();
|
||||||
|
void formatBlockQuote();
|
||||||
|
|
||||||
void sendSimpleStringCase();
|
void sendSimpleStringCase();
|
||||||
void sendSingleParaMarkup();
|
void sendSingleParaMarkup();
|
||||||
@@ -66,6 +67,7 @@ private Q_SLOTS:
|
|||||||
void receiveRichEdited_data();
|
void receiveRichEdited_data();
|
||||||
void receiveRichEdited();
|
void receiveRichEdited();
|
||||||
void receiveLineSeparator();
|
void receiveLineSeparator();
|
||||||
|
void receiveRichCodeUrl();
|
||||||
|
|
||||||
void linkPreviewsMatch_data();
|
void linkPreviewsMatch_data();
|
||||||
void linkPreviewsMatch();
|
void linkPreviewsMatch();
|
||||||
@@ -78,131 +80,11 @@ void TextHandlerTest::initTestCase()
|
|||||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||||
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
||||||
|
|
||||||
const auto json = QJsonDocument::fromJson(R"EVENT({
|
QFile testTextHandlerSyncFile;
|
||||||
"account_data": {
|
testTextHandlerSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-texthandler-sync.json"));
|
||||||
"events": [
|
testTextHandlerSyncFile.open(QIODevice::ReadOnly);
|
||||||
{
|
const auto testTextHandlerSyncJson = QJsonDocument::fromJson(testTextHandlerSyncFile.readAll());
|
||||||
"content": {
|
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testTextHandlerSyncJson.object());
|
||||||
"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));
|
room->update(std::move(roomData));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,6 +147,16 @@ void TextHandlerTest::emptyCodeTags()
|
|||||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
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()
|
void TextHandlerTest::sendSimpleStringCase()
|
||||||
{
|
{
|
||||||
const QString testInputString = QStringLiteral("This data should just be put in a paragraph.");
|
const QString testInputString = QStringLiteral("This data should just be put in a paragraph.");
|
||||||
@@ -577,8 +469,9 @@ void TextHandlerTest::receiveRichEdited_data()
|
|||||||
QTest::newRow("basic") << QStringLiteral("Edited") << QStringLiteral("Edited <span style=\"color:#000000\">(edited)</span>");
|
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>")
|
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>");
|
<< QStringLiteral("<p>Edited</p>\n<p>Edited <span style=\"color:#000000\">(edited)</span></p>");
|
||||||
QTest::newRow("blockquote") << QStringLiteral("<blockquote>Edited</blockquote>")
|
QTest::newRow("blockquote")
|
||||||
<< QStringLiteral("<blockquote>Edited</blockquote><p> <span style=\"color:#000000\">(edited)</span></p>");
|
<< QStringLiteral("<blockquote>Edited</blockquote>")
|
||||||
|
<< QStringLiteral("<blockquote><table><tr><td>\u201CEdited\u201D</td></tr></table></blockquote><p> <span style=\"color:#000000\">(edited)</span></p>");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::receiveRichEdited()
|
void TextHandlerTest::receiveRichEdited()
|
||||||
@@ -647,5 +540,13 @@ void TextHandlerTest::linkPreviewsReject()
|
|||||||
QCOMPARE(testTextHandler.getLinkPreviews(), testOutputLinks);
|
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)
|
QTEST_MAIN(TextHandlerTest)
|
||||||
#include "texthandlertest.moc"
|
#include "texthandlertest.moc"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
</provides>
|
</provides>
|
||||||
<name>NeoChat</name>
|
<name>NeoChat</name>
|
||||||
<name xml:lang="ar">نيوتشات</name>
|
<name xml:lang="ar">نيوتشات</name>
|
||||||
|
<name xml:lang="ast">NeoChat</name>
|
||||||
<name xml:lang="az">NeoChat</name>
|
<name xml:lang="az">NeoChat</name>
|
||||||
<name xml:lang="ca">NeoChat</name>
|
<name xml:lang="ca">NeoChat</name>
|
||||||
<name xml:lang="ca-valencia">NeoChat</name>
|
<name xml:lang="ca-valencia">NeoChat</name>
|
||||||
@@ -98,7 +99,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>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="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">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 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 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="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="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="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>
|
<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>
|
||||||
@@ -283,7 +284,7 @@ to provide a convergent experience across multiple platforms.</p>
|
|||||||
<screenshot type="default">
|
<screenshot type="default">
|
||||||
<image>https://cdn.kde.org/screenshots/neochat/application.png</image>
|
<image>https://cdn.kde.org/screenshots/neochat/application.png</image>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
<screenshot x-kde-os="windows">
|
<screenshot environment="windows">
|
||||||
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</image>
|
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</image>
|
||||||
<caption>Main view with room list, chat, and room information</caption>
|
<caption>Main view with room list, chat, and room information</caption>
|
||||||
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
||||||
@@ -310,7 +311,7 @@ to provide a convergent experience across multiple platforms.</p>
|
|||||||
<caption xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</caption>
|
<caption xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</caption>
|
||||||
<caption xml:lang="x-test">xxMain view with room list, chat, and room informationxx</caption>
|
<caption xml:lang="x-test">xxMain view with room list, chat, and room informationxx</caption>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
<screenshot x-kde-os="windows">
|
<screenshot environment="windows">
|
||||||
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Login.png</image>
|
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Login.png</image>
|
||||||
<caption>Login screen</caption>
|
<caption>Login screen</caption>
|
||||||
<caption xml:lang="ar">شاشة الدخول</caption>
|
<caption xml:lang="ar">شاشة الدخول</caption>
|
||||||
@@ -342,6 +343,8 @@ to provide a convergent experience across multiple platforms.</p>
|
|||||||
<content_attribute id="social-chat">intense</content_attribute>
|
<content_attribute id="social-chat">intense</content_attribute>
|
||||||
</content_rating>
|
</content_rating>
|
||||||
<releases>
|
<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">
|
<release version="23.08.0" date="2023-08-24">
|
||||||
<url>https://kde.org/announcements/gear/23.08.0/#neochathttpsappskdeorgneochat</url>
|
<url>https://kde.org/announcements/gear/23.08.0/#neochathttpsappskdeorgneochat</url>
|
||||||
<description>
|
<description>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
Version=1.5
|
Version=1.5
|
||||||
Name=NeoChat
|
Name=NeoChat
|
||||||
Name[ar]=نيوتشات
|
Name[ar]=نيوتشات
|
||||||
|
Name[ast]=NeoChat
|
||||||
Name[az]=NeoChat
|
Name[az]=NeoChat
|
||||||
Name[ca]=NeoChat
|
Name[ca]=NeoChat
|
||||||
Name[ca@valencia]=NeoChat
|
Name[ca@valencia]=NeoChat
|
||||||
|
|||||||
1172
po/ar/neochat.po
1172
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
4414
po/ast/neochat.po
Normal file
4414
po/ast/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
1161
po/az/neochat.po
1161
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
1203
po/cs/neochat.po
1203
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1148
po/da/neochat.po
1148
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1195
po/de/neochat.po
1195
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1188
po/el/neochat.po
1188
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1182
po/en_GB/neochat.po
1182
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1141
po/eo/neochat.po
1141
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
1166
po/eu/neochat.po
1166
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1418
po/fi/neochat.po
1418
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1310
po/fr/neochat.po
1310
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1196
po/hu/neochat.po
1196
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
1186
po/id/neochat.po
1186
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1144
po/ie/neochat.po
1144
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1213
po/it/neochat.po
1213
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1121
po/ja/neochat.po
1121
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1160
po/ka/neochat.po
1160
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1506
po/ko/neochat.po
1506
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1121
po/lt/neochat.po
1121
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
1168
po/nn/neochat.po
1168
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1156
po/pa/neochat.po
1156
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
1180
po/pt/neochat.po
1180
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
1164
po/pt_BR/neochat.po
1164
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
1194
po/ru/neochat.po
1194
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1158
po/sk/neochat.po
1158
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
1204
po/sv/neochat.po
1204
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1289
po/ta/neochat.po
1289
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1140
po/tok/neochat.po
1140
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
1235
po/zh_CN/neochat.po
1235
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
1121
po/zh_TW/neochat.po
1121
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -135,6 +135,10 @@ add_library(neochat STATIC
|
|||||||
enums/delegatetype.h
|
enums/delegatetype.h
|
||||||
roomlastmessageprovider.cpp
|
roomlastmessageprovider.cpp
|
||||||
roomlastmessageprovider.h
|
roomlastmessageprovider.h
|
||||||
|
chatbarcache.cpp
|
||||||
|
chatbarcache.h
|
||||||
|
colorschemer.cpp
|
||||||
|
colorschemer.h
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||||
@@ -142,30 +146,31 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/main.qml
|
qml/main.qml
|
||||||
qml/AccountMenu.qml
|
qml/AccountMenu.qml
|
||||||
qml/ExploreComponent.qml
|
qml/ExploreComponent.qml
|
||||||
|
qml/ExploreComponentMobile.qml
|
||||||
qml/ContextMenu.qml
|
qml/ContextMenu.qml
|
||||||
qml/CollapsedRoomDelegate.qml
|
qml/CollapsedRoomDelegate.qml
|
||||||
qml/RoomDelegate.qml
|
qml/RoomDelegate.qml
|
||||||
qml/RoomListPage.qml
|
qml/RoomListPage.qml
|
||||||
qml/SpaceListContextMenu.qml
|
qml/SpaceListContextMenu.qml
|
||||||
qml/UserInfo.qml
|
qml/UserInfo.qml
|
||||||
qml/LoadingPage.qml
|
qml/UserInfoDesktop.qml
|
||||||
qml/RoomPage.qml
|
qml/RoomPage.qml
|
||||||
qml/RoomWindow.qml
|
qml/RoomWindow.qml
|
||||||
qml/JoinRoomPage.qml
|
qml/JoinRoomPage.qml
|
||||||
|
qml/ManualRoomDialog.qml
|
||||||
qml/ExplorerDelegate.qml
|
qml/ExplorerDelegate.qml
|
||||||
qml/InviteUserPage.qml
|
qml/InviteUserPage.qml
|
||||||
qml/StartChatPage.qml
|
qml/StartChatPage.qml
|
||||||
qml/ImageEditorPage.qml
|
qml/ImageEditorPage.qml
|
||||||
qml/WelcomePage.qml
|
qml/WelcomePage.qml
|
||||||
qml/General.qml
|
qml/General.qml
|
||||||
qml/Security.qml
|
qml/RoomSecurity.qml
|
||||||
qml/PushNotification.qml
|
qml/PushNotification.qml
|
||||||
qml/Categories.qml
|
qml/Categories.qml
|
||||||
qml/Permissions.qml
|
qml/Permissions.qml
|
||||||
qml/NeochatMaximizeComponent.qml
|
qml/NeochatMaximizeComponent.qml
|
||||||
qml/FancyEffectsContainer.qml
|
qml/FancyEffectsContainer.qml
|
||||||
qml/TypingPane.qml
|
qml/TypingPane.qml
|
||||||
qml/ShimmerGradient.qml
|
|
||||||
qml/QuickSwitcher.qml
|
qml/QuickSwitcher.qml
|
||||||
qml/HoverActions.qml
|
qml/HoverActions.qml
|
||||||
qml/ChatBox.qml
|
qml/ChatBox.qml
|
||||||
@@ -281,6 +286,10 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
|||||||
qml/SpaceHomePage.qml
|
qml/SpaceHomePage.qml
|
||||||
qml/SpaceHierarchyDelegate.qml
|
qml/SpaceHierarchyDelegate.qml
|
||||||
qml/RemoveChildDialog.qml
|
qml/RemoveChildDialog.qml
|
||||||
|
qml/SelectParentDialog.qml
|
||||||
|
qml/Security.qml
|
||||||
|
qml/QrCodeMaximizeComponent.qml
|
||||||
|
qml/SelectSpacesDialog.qml
|
||||||
RESOURCES
|
RESOURCES
|
||||||
qml/confetti.png
|
qml/confetti.png
|
||||||
qml/glowdot.png
|
qml/glowdot.png
|
||||||
@@ -302,6 +311,13 @@ ecm_qt_declare_logging_category(neochat
|
|||||||
DEFAULT_SEVERITY Info
|
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
|
add_executable(neochat-app
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
@@ -322,15 +338,13 @@ ecm_add_app_icon(NEOCHAT_ICON ICONS ${CMAKE_SOURCE_DIR}/128-logo.png)
|
|||||||
target_sources(neochat-app PRIVATE ${NEOCHAT_ICON})
|
target_sources(neochat-app PRIVATE ${NEOCHAT_ICON})
|
||||||
|
|
||||||
if(NOT ANDROID)
|
if(NOT ANDROID)
|
||||||
target_sources(neochat PRIVATE colorschemer.cpp colorschemer.h)
|
|
||||||
if (NOT WIN32 AND NOT APPLE)
|
if (NOT WIN32 AND NOT APPLE)
|
||||||
target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h)
|
target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h)
|
||||||
target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem)
|
target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem)
|
||||||
else()
|
else()
|
||||||
target_sources(neochat PRIVATE trayicon.cpp trayicon.h)
|
target_sources(neochat PRIVATE trayicon.cpp trayicon.h)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(neochat PUBLIC KF6::ConfigWidgets KF6::WindowSystem ICU::uc)
|
target_link_libraries(neochat PUBLIC KF6::WindowSystem ICU::uc)
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_COLORSCHEME)
|
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_WINDOWSYSTEM)
|
target_compile_definitions(neochat PUBLIC -DHAVE_WINDOWSYSTEM)
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_ICU)
|
target_compile_definitions(neochat PUBLIC -DHAVE_ICU)
|
||||||
endif()
|
endif()
|
||||||
@@ -342,7 +356,27 @@ if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
|
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
|
||||||
target_link_libraries(neochat 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)
|
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
|
||||||
|
)
|
||||||
|
|
||||||
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
||||||
|
|
||||||
@@ -428,7 +462,9 @@ if(ANDROID)
|
|||||||
"preferences-desktop-notification"
|
"preferences-desktop-notification"
|
||||||
"computer-symbolic"
|
"computer-symbolic"
|
||||||
"gps"
|
"gps"
|
||||||
|
"system-users-symbolic"
|
||||||
)
|
)
|
||||||
|
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR/android})
|
||||||
else()
|
else()
|
||||||
target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets)
|
target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets)
|
||||||
install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
|
install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
|
||||||
|
|||||||
@@ -38,45 +38,33 @@ void ActionsHandler::setRoom(NeoChatRoom *room)
|
|||||||
Q_EMIT roomChanged();
|
Q_EMIT roomChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActionsHandler::handleNewMessage()
|
void ActionsHandler::handleMessageEvent(ChatBarCache *chatBarCache)
|
||||||
{
|
{
|
||||||
checkEffects(m_room->chatBoxText());
|
if (!chatBarCache) {
|
||||||
if (!m_room->chatBoxAttachmentPath().isEmpty()) {
|
|
||||||
QUrl url(m_room->chatBoxAttachmentPath());
|
|
||||||
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString handledText = m_room->chatBoxText();
|
checkEffects(chatBarCache->text());
|
||||||
handledText = handleMentions(handledText);
|
if (!chatBarCache->attachmentPath().isEmpty()) {
|
||||||
handleMessage(m_room->chatBoxText(), handledText);
|
QUrl url(chatBarCache->attachmentPath());
|
||||||
|
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({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString handledText = chatBarCache->text();
|
||||||
|
handledText = handleMentions(handledText, chatBarCache->mentions());
|
||||||
|
handleMessage(m_room->mainCache()->text(), handledText, chatBarCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActionsHandler::handleEdit()
|
QString ActionsHandler::handleMentions(QString handledText, QList<Mention> *mentions)
|
||||||
{
|
|
||||||
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) {
|
if (!m_room) {
|
||||||
return QString();
|
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 {
|
std::sort(mentions->begin(), mentions->end(), [](const auto &a, const auto &b) -> bool {
|
||||||
return a.cursor.anchor() > b.cursor.anchor();
|
return a.cursor.anchor() > b.cursor.anchor();
|
||||||
});
|
});
|
||||||
@@ -87,14 +75,14 @@ QString ActionsHandler::handleMentions(QString handledText, const bool &isEdit)
|
|||||||
}
|
}
|
||||||
handledText = handledText.replace(mention.cursor.anchor(),
|
handledText = handledText.replace(mention.cursor.anchor(),
|
||||||
mention.cursor.position() - mention.cursor.anchor(),
|
mention.cursor.position() - mention.cursor.anchor(),
|
||||||
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text, mention.id));
|
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text.toHtmlEscaped(), mention.id));
|
||||||
}
|
}
|
||||||
mentions->clear();
|
mentions->clear();
|
||||||
|
|
||||||
return handledText;
|
return handledText;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActionsHandler::handleMessage(const QString &text, QString handledText, const bool &isEdit)
|
void ActionsHandler::handleMessage(const QString &text, QString handledText, ChatBarCache *chatBarCache)
|
||||||
{
|
{
|
||||||
if (NeoChatConfig::allowQuickEdit()) {
|
if (NeoChatConfig::allowQuickEdit()) {
|
||||||
QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$"));
|
QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$"));
|
||||||
@@ -134,7 +122,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, con
|
|||||||
for (const auto &action : ActionsModel::instance().allActions()) {
|
for (const auto &action : ActionsModel::instance().allActions()) {
|
||||||
if (handledText.indexOf(action.prefix) == 1
|
if (handledText.indexOf(action.prefix) == 1
|
||||||
&& (handledText.indexOf(" "_ls) == action.prefix.length() + 1 || handledText.length() == action.prefix.length() + 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);
|
handledText = action.handle(handledText.mid(action.prefix.length() + 1).trimmed(), m_room, chatBarCache);
|
||||||
if (action.messageType.has_value()) {
|
if (action.messageType.has_value()) {
|
||||||
messageType = *action.messageType;
|
messageType = *action.messageType;
|
||||||
}
|
}
|
||||||
@@ -161,7 +149,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, con
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_room->postMessage(text, handledText, messageType, m_room->chatBoxReplyId(), isEdit ? m_room->chatBoxEditId() : QString());
|
m_room->postMessage(text, handledText, messageType, chatBarCache->replyId(), chatBarCache->editId(), chatBarCache->threadId());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActionsHandler::checkEffects(const QString &text)
|
void ActionsHandler::checkEffects(const QString &text)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <Quotient/events/roommessageevent.h>
|
#include <Quotient/events/roommessageevent.h>
|
||||||
|
|
||||||
|
#include "chatbarcache.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
|
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
@@ -51,21 +52,15 @@ Q_SIGNALS:
|
|||||||
void showEffect(const QString &effect);
|
void showEffect(const QString &effect);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pre-process text and send message.
|
* @brief Pre-process text and send message event.
|
||||||
*/
|
*/
|
||||||
void handleNewMessage();
|
void handleMessageEvent(ChatBarCache *chatBarCache);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Pre-process text and send edit.
|
|
||||||
*/
|
|
||||||
void handleEdit();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NeoChatRoom *m_room = nullptr;
|
NeoChatRoom *m_room = nullptr;
|
||||||
void checkEffects(const QString &text);
|
void checkEffects(const QString &text);
|
||||||
|
|
||||||
QString handleMentions(QString handledText, const bool &isEdit = false);
|
QString handleMentions(QString handledText, QList<Mention> *mentions);
|
||||||
void handleMessage(const QString &text, QString handledText, const bool &isEdit = false);
|
void handleMessage(const QString &text, QString handledText, ChatBarCache *chatBarCache);
|
||||||
};
|
};
|
||||||
|
|||||||
177
src/chatbarcache.cpp
Normal file
177
src/chatbarcache.cpp
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
// 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"
|
||||||
201
src/chatbarcache.h
Normal file
201
src/chatbarcache.h
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
// 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,6 +14,8 @@
|
|||||||
#include <Sonnet/BackgroundChecker>
|
#include <Sonnet/BackgroundChecker>
|
||||||
#include <Sonnet/Settings>
|
#include <Sonnet/Settings>
|
||||||
|
|
||||||
|
#include "chatdocumenthandler_logging.h"
|
||||||
|
|
||||||
class SyntaxHighlighter : public QSyntaxHighlighter
|
class SyntaxHighlighter : public QSyntaxHighlighter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -57,11 +59,12 @@ public:
|
|||||||
setFormat(error.first, error.second.size(), errorFormat);
|
setFormat(error.first, error.second.size(), errorFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto room = dynamic_cast<ChatDocumentHandler *>(parent())->room();
|
auto handler = dynamic_cast<ChatDocumentHandler *>(parent());
|
||||||
|
auto room = handler->room();
|
||||||
if (!room) {
|
if (!room) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto mentions = room->mentions();
|
auto mentions = handler->chatBarCache()->mentions();
|
||||||
mentions->erase(std::remove_if(mentions->begin(),
|
mentions->erase(std::remove_if(mentions->begin(),
|
||||||
mentions->end(),
|
mentions->end(),
|
||||||
[this](auto &mention) {
|
[this](auto &mention) {
|
||||||
@@ -97,21 +100,16 @@ ChatDocumentHandler::ChatDocumentHandler(QObject *parent)
|
|||||||
, m_document(nullptr)
|
, m_document(nullptr)
|
||||||
, m_cursorPosition(-1)
|
, m_cursorPosition(-1)
|
||||||
, m_highlighter(new SyntaxHighlighter(this))
|
, m_highlighter(new SyntaxHighlighter(this))
|
||||||
, m_completionModel(new CompletionModel())
|
, m_completionModel(new CompletionModel(this))
|
||||||
{
|
{
|
||||||
connect(this, &ChatDocumentHandler::roomChanged, this, [this]() {
|
connect(this, &ChatDocumentHandler::roomChanged, this, [this]() {
|
||||||
m_completionModel->setRoom(m_room);
|
m_completionModel->setRoom(m_room);
|
||||||
static QPointer<NeoChatRoom> previousRoom = nullptr;
|
static QPointer<NeoChatRoom> previousRoom = nullptr;
|
||||||
if (previousRoom) {
|
if (previousRoom) {
|
||||||
disconnect(previousRoom, &NeoChatRoom::chatBoxTextChanged, this, nullptr);
|
disconnect(m_chatBarCache, &ChatBarCache::textChanged, this, nullptr);
|
||||||
disconnect(previousRoom, &NeoChatRoom::editTextChanged, this, nullptr);
|
|
||||||
}
|
}
|
||||||
previousRoom = m_room;
|
previousRoom = m_room;
|
||||||
connect(m_room, &NeoChatRoom::chatBoxTextChanged, this, [this]() {
|
connect(m_chatBarCache, &ChatBarCache::textChanged, 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();
|
int start = completionStartIndex();
|
||||||
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
|
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
|
||||||
});
|
});
|
||||||
@@ -152,20 +150,6 @@ int ChatDocumentHandler::completionStartIndex() const
|
|||||||
return start;
|
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
|
QQuickTextDocument *ChatDocumentHandler::document() const
|
||||||
{
|
{
|
||||||
return m_document;
|
return m_document;
|
||||||
@@ -215,8 +199,31 @@ void ChatDocumentHandler::setRoom(NeoChatRoom *room)
|
|||||||
Q_EMIT roomChanged();
|
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)
|
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) {
|
if (m_completionModel->autoCompletionType() == CompletionModel::User) {
|
||||||
auto name = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::DisplayNameRole).toString();
|
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();
|
auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::SubtitleRole).toString();
|
||||||
@@ -300,26 +307,20 @@ void ChatDocumentHandler::setSelectionEnd(int position)
|
|||||||
|
|
||||||
QString ChatDocumentHandler::getText() const
|
QString ChatDocumentHandler::getText() const
|
||||||
{
|
{
|
||||||
if (!m_room) {
|
if (!m_chatBarCache) {
|
||||||
return QString();
|
qCWarning(ChatDocumentHandling) << "getText called with m_chatBarCache set to nullptr.";
|
||||||
}
|
return {};
|
||||||
if (m_isEdit) {
|
|
||||||
return m_room->editText();
|
|
||||||
} else {
|
|
||||||
return m_room->chatBoxText();
|
|
||||||
}
|
}
|
||||||
|
return m_chatBarCache->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatDocumentHandler::pushMention(const Mention mention) const
|
void ChatDocumentHandler::pushMention(const Mention mention) const
|
||||||
{
|
{
|
||||||
if (!m_room) {
|
if (!m_chatBarCache) {
|
||||||
|
qCWarning(ChatDocumentHandling) << "pushMention called with m_chatBarCache set to nullptr.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_isEdit) {
|
m_chatBarCache->mentions()->push_back(mention);
|
||||||
m_room->editMentions()->push_back(mention);
|
|
||||||
} else {
|
|
||||||
m_room->mentions()->push_back(mention);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor ChatDocumentHandler::mentionColor() const
|
QColor ChatDocumentHandler::mentionColor() const
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <QQuickTextDocument>
|
#include <QQuickTextDocument>
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
|
|
||||||
|
#include "chatbarcache.h"
|
||||||
#include "models/completionmodel.h"
|
#include "models/completionmodel.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
|
|
||||||
@@ -61,14 +62,6 @@ class ChatDocumentHandler : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
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.
|
* @brief The QQuickTextDocument that is being handled.
|
||||||
*/
|
*/
|
||||||
@@ -95,13 +88,18 @@ class ChatDocumentHandler : public QObject
|
|||||||
* This is typically provided to a qml component to visualise the current
|
* This is typically provided to a qml component to visualise the current
|
||||||
* completion results.
|
* completion results.
|
||||||
*/
|
*/
|
||||||
Q_PROPERTY(CompletionModel *completionModel READ completionModel NOTIFY completionModelChanged)
|
Q_PROPERTY(CompletionModel *completionModel READ completionModel CONSTANT)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The current room that the the text document is being handled for.
|
* @brief The current room that the the text document is being handled for.
|
||||||
*/
|
*/
|
||||||
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
|
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.
|
* @brief The color to highlight user mentions.
|
||||||
*/
|
*/
|
||||||
@@ -115,9 +113,6 @@ class ChatDocumentHandler : public QObject
|
|||||||
public:
|
public:
|
||||||
explicit ChatDocumentHandler(QObject *parent = nullptr);
|
explicit ChatDocumentHandler(QObject *parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] bool isEdit() const;
|
|
||||||
void setIsEdit(bool edit);
|
|
||||||
|
|
||||||
[[nodiscard]] QQuickTextDocument *document() const;
|
[[nodiscard]] QQuickTextDocument *document() const;
|
||||||
void setDocument(QQuickTextDocument *document);
|
void setDocument(QQuickTextDocument *document);
|
||||||
|
|
||||||
@@ -133,9 +128,11 @@ public:
|
|||||||
[[nodiscard]] NeoChatRoom *room() const;
|
[[nodiscard]] NeoChatRoom *room() const;
|
||||||
void setRoom(NeoChatRoom *room);
|
void setRoom(NeoChatRoom *room);
|
||||||
|
|
||||||
|
[[nodiscard]] ChatBarCache *chatBarCache() const;
|
||||||
|
void setChatBarCache(ChatBarCache *chatBarCache);
|
||||||
|
|
||||||
Q_INVOKABLE void complete(int index);
|
Q_INVOKABLE void complete(int index);
|
||||||
|
|
||||||
void updateCompletions();
|
|
||||||
CompletionModel *completionModel() const;
|
CompletionModel *completionModel() const;
|
||||||
|
|
||||||
[[nodiscard]] QColor mentionColor() const;
|
[[nodiscard]] QColor mentionColor() const;
|
||||||
@@ -145,11 +142,10 @@ public:
|
|||||||
void setErrorColor(const QColor &color);
|
void setErrorColor(const QColor &color);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void isEditChanged();
|
|
||||||
void documentChanged();
|
void documentChanged();
|
||||||
void cursorPositionChanged();
|
void cursorPositionChanged();
|
||||||
void roomChanged();
|
void roomChanged();
|
||||||
void completionModelChanged();
|
void chatBarCacheChanged();
|
||||||
void selectionStartChanged();
|
void selectionStartChanged();
|
||||||
void selectionEndChanged();
|
void selectionEndChanged();
|
||||||
void errorColorChanged();
|
void errorColorChanged();
|
||||||
@@ -158,11 +154,10 @@ Q_SIGNALS:
|
|||||||
private:
|
private:
|
||||||
int completionStartIndex() const;
|
int completionStartIndex() const;
|
||||||
|
|
||||||
bool m_isEdit = false;
|
|
||||||
|
|
||||||
QPointer<QQuickTextDocument> m_document;
|
QPointer<QQuickTextDocument> m_document;
|
||||||
|
|
||||||
QPointer<NeoChatRoom> m_room;
|
QPointer<NeoChatRoom> m_room;
|
||||||
|
QPointer<ChatBarCache> m_chatBarCache;
|
||||||
bool completionVisible = false;
|
bool completionVisible = false;
|
||||||
|
|
||||||
QColor m_mentionColor;
|
QColor m_mentionColor;
|
||||||
|
|||||||
@@ -6,13 +6,8 @@
|
|||||||
|
|
||||||
#include <qt6keychain/keychain.h>
|
#include <qt6keychain/keychain.h>
|
||||||
|
|
||||||
#include <KConfig>
|
|
||||||
#include <KConfigGroup>
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
#include <KWindowConfig>
|
#include <KWindowConfig>
|
||||||
#ifdef HAVE_WINDOWSYSTEM
|
|
||||||
#include <KWindowEffects>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
@@ -65,7 +60,8 @@ Controller::Controller(QObject *parent)
|
|||||||
invokeLogin();
|
invokeLogin();
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [] {
|
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [this] {
|
||||||
|
delete m_trayIcon;
|
||||||
NeoChatConfig::self()->save();
|
NeoChatConfig::self()->save();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -103,10 +99,6 @@ Controller::Controller(QObject *parent)
|
|||||||
}
|
}
|
||||||
oldAccountCount = m_accountRegistry.size();
|
oldAccountCount = m_accountRegistry.size();
|
||||||
});
|
});
|
||||||
|
|
||||||
QTimer::singleShot(0, this, [this] {
|
|
||||||
m_pushRuleModel = new PushRuleModel;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller &Controller::instance()
|
Controller &Controller::instance()
|
||||||
@@ -175,6 +167,8 @@ void Controller::invokeLogin()
|
|||||||
QString id = NeoChatConfig::self()->activeConnection();
|
QString id = NeoChatConfig::self()->activeConnection();
|
||||||
for (const auto &accountId : accounts) {
|
for (const auto &accountId : accounts) {
|
||||||
AccountSettings account{accountId};
|
AccountSettings account{accountId};
|
||||||
|
m_accountsLoading += accountId;
|
||||||
|
Q_EMIT accountsLoadingChanged();
|
||||||
if (id.isEmpty()) {
|
if (id.isEmpty()) {
|
||||||
// handle case where the account config is empty
|
// handle case where the account config is empty
|
||||||
id = accountId;
|
id = accountId;
|
||||||
@@ -194,6 +188,8 @@ void Controller::invokeLogin()
|
|||||||
connect(connection, &NeoChatConnection::connected, this, [this, connection, id] {
|
connect(connection, &NeoChatConnection::connected, this, [this, connection, id] {
|
||||||
connection->loadState();
|
connection->loadState();
|
||||||
addConnection(connection);
|
addConnection(connection);
|
||||||
|
m_accountsLoading.removeAll(connection->userId());
|
||||||
|
Q_EMIT accountsLoadingChanged();
|
||||||
if (connection->userId() == id) {
|
if (connection->userId() == id) {
|
||||||
setActiveConnection(connection);
|
setActiveConnection(connection);
|
||||||
connectSingleShot(connection, &NeoChatConnection::syncDone, this, &Controller::initiated);
|
connectSingleShot(connection, &NeoChatConnection::syncDone, this, &Controller::initiated);
|
||||||
@@ -354,12 +350,6 @@ void Controller::setActiveConnection(NeoChatConnection *connection)
|
|||||||
}
|
}
|
||||||
NeoChatConfig::self()->save();
|
NeoChatConfig::self()->save();
|
||||||
Q_EMIT activeConnectionChanged();
|
Q_EMIT activeConnectionChanged();
|
||||||
Q_EMIT activeConnectionIndexChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
PushRuleModel *Controller::pushRuleModel() const
|
|
||||||
{
|
|
||||||
return m_pushRuleModel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::saveWindowGeometry()
|
void Controller::saveWindowGeometry()
|
||||||
@@ -384,56 +374,6 @@ void Controller::joinRoom(const QString &alias)
|
|||||||
RoomManager::instance().joinRoom(m_connection, alias, QStringList{knownServer});
|
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)
|
void Controller::forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item)
|
||||||
{
|
{
|
||||||
// HACK: Workaround bug QTBUG 93281
|
// HACK: Workaround bug QTBUG 93281
|
||||||
@@ -470,14 +410,6 @@ void Controller::setApplicationProxy()
|
|||||||
QNetworkProxy::setApplicationProxy(proxy);
|
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
|
bool Controller::isFlatpak() const
|
||||||
{
|
{
|
||||||
#ifdef NEOCHAT_FLATPAK
|
#ifdef NEOCHAT_FLATPAK
|
||||||
|
|||||||
@@ -3,13 +3,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "models/pushrulemodel.h"
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
|
|
||||||
#include <KFormat>
|
|
||||||
|
|
||||||
#include "neochatconnection.h"
|
#include "neochatconnection.h"
|
||||||
#include <Quotient/accountregistry.h>
|
#include <Quotient/accountregistry.h>
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
@@ -49,26 +46,11 @@ class Controller : public QObject
|
|||||||
*/
|
*/
|
||||||
Q_PROPERTY(NeoChatConnection *activeConnection READ activeConnection WRITE setActiveConnection NOTIFY activeConnectionChanged)
|
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.
|
* @brief Whether the OS NeoChat is running on supports sytem tray icons.
|
||||||
*/
|
*/
|
||||||
Q_PROPERTY(bool supportSystemTray READ supportSystemTray CONSTANT)
|
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.
|
* @brief Whether NeoChat is currently able to connect to the server.
|
||||||
*/
|
*/
|
||||||
@@ -81,6 +63,8 @@ class Controller : public QObject
|
|||||||
*/
|
*/
|
||||||
Q_PROPERTY(bool isFlatpak READ isFlatpak CONSTANT)
|
Q_PROPERTY(bool isFlatpak READ isFlatpak CONSTANT)
|
||||||
|
|
||||||
|
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Defines the status after an attempt to change the password on an account.
|
* @brief Defines the status after an attempt to change the password on an account.
|
||||||
@@ -102,8 +86,6 @@ public:
|
|||||||
void setActiveConnection(NeoChatConnection *connection);
|
void setActiveConnection(NeoChatConnection *connection);
|
||||||
[[nodiscard]] NeoChatConnection *activeConnection() const;
|
[[nodiscard]] NeoChatConnection *activeConnection() const;
|
||||||
|
|
||||||
[[nodiscard]] PushRuleModel *pushRuleModel() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add a new connection to the account registry.
|
* @brief Add a new connection to the account registry.
|
||||||
*/
|
*/
|
||||||
@@ -114,8 +96,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void dropConnection(NeoChatConnection *c);
|
void dropConnection(NeoChatConnection *c);
|
||||||
|
|
||||||
int activeConnectionIndex() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Save an access token to the keychain for the given account.
|
* @brief Save an access token to the keychain for the given account.
|
||||||
*/
|
*/
|
||||||
@@ -126,20 +106,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE void joinRoom(const QString &alias);
|
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;
|
[[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;
|
bool isOnline() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,20 +119,6 @@ public:
|
|||||||
|
|
||||||
bool isFlatpak() const;
|
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.
|
* @brief Force a QQuickTextDocument to refresh when images are loaded.
|
||||||
*
|
*
|
||||||
@@ -187,10 +141,8 @@ private:
|
|||||||
bool m_isOnline = true;
|
bool m_isOnline = true;
|
||||||
QMap<Quotient::Room *, int> m_notificationCounts;
|
QMap<Quotient::Room *, int> m_notificationCounts;
|
||||||
|
|
||||||
bool hasWindowSystem() const;
|
|
||||||
|
|
||||||
QPointer<PushRuleModel> m_pushRuleModel;
|
|
||||||
Quotient::AccountRegistry m_accountRegistry;
|
Quotient::AccountRegistry m_accountRegistry;
|
||||||
|
QStringList m_accountsLoading;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void invokeLogin();
|
void invokeLogin();
|
||||||
@@ -213,7 +165,7 @@ Q_SIGNALS:
|
|||||||
void passwordStatus(Controller::PasswordStatus status);
|
void passwordStatus(Controller::PasswordStatus status);
|
||||||
void userConsentRequired(QUrl url);
|
void userConsentRequired(QUrl url);
|
||||||
void isOnlineChanged(bool isOnline);
|
void isOnlineChanged(bool isOnline);
|
||||||
void activeConnectionIndexChanged();
|
void accountsLoadingChanged();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void saveWindowGeometry();
|
void saveWindowGeometry();
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <Quotient/events/stickerevent.h>
|
#include <Quotient/events/stickerevent.h>
|
||||||
#include <Quotient/quotient_common.h>
|
#include <Quotient/quotient_common.h>
|
||||||
|
|
||||||
|
#include "delegatetype.h"
|
||||||
#include "eventhandler_logging.h"
|
#include "eventhandler_logging.h"
|
||||||
#include "events/pollevent.h"
|
#include "events/pollevent.h"
|
||||||
#include "linkpreviewer.h"
|
#include "linkpreviewer.h"
|
||||||
@@ -50,6 +51,10 @@ const Quotient::Event *EventHandler::getEvent() const
|
|||||||
|
|
||||||
void EventHandler::setEvent(const Quotient::RoomEvent *event)
|
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) {
|
if (event == m_event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -181,7 +186,7 @@ QDateTime EventHandler::getTime(bool isPending, QDateTime lastUpdated) const
|
|||||||
QString EventHandler::getTimeString(bool relative, QLocale::FormatType format, bool isPending, QDateTime lastUpdated) const
|
QString EventHandler::getTimeString(bool relative, QLocale::FormatType format, bool isPending, QDateTime lastUpdated) const
|
||||||
{
|
{
|
||||||
if (m_event == nullptr) {
|
if (m_event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getTime called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "getTimeString called with m_event set to nullptr.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (isPending && lastUpdated == QDateTime()) {
|
if (isPending && lastUpdated == QDateTime()) {
|
||||||
@@ -216,6 +221,15 @@ bool EventHandler::isHighlighted()
|
|||||||
|
|
||||||
bool EventHandler::isHidden()
|
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()) {
|
if (m_event->isStateEvent() && !NeoChatConfig::self()->showStateEvent()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -611,6 +625,14 @@ QString EventHandler::getGenericBody() const
|
|||||||
|
|
||||||
QVariantMap EventHandler::getMediaInfo() 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);
|
return getMediaInfoForEvent(m_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -723,6 +745,14 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const EventContent::FileInfo
|
|||||||
|
|
||||||
QSharedPointer<LinkPreviewer> EventHandler::getLinkPreviewer() const
|
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>()) {
|
if (!m_event->is<RoomMessageEvent>()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -754,7 +784,7 @@ QSharedPointer<ReactionModel> EventHandler::getReactions() const
|
|||||||
{
|
{
|
||||||
if (m_room == nullptr) {
|
if (m_room == nullptr) {
|
||||||
qCWarning(EventHandling) << "getReactions called with m_room set to nullptr.";
|
qCWarning(EventHandling) << "getReactions called with m_room set to nullptr.";
|
||||||
return {};
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (m_event == nullptr) {
|
if (m_event == nullptr) {
|
||||||
qCWarning(EventHandling) << "getReactions called with m_event set to nullptr.";
|
qCWarning(EventHandling) << "getReactions called with m_event set to nullptr.";
|
||||||
@@ -806,16 +836,33 @@ QSharedPointer<ReactionModel> EventHandler::getReactions() const
|
|||||||
|
|
||||||
bool EventHandler::hasReply() 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();
|
return !m_event->contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventHandler::getReplyId() const
|
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();
|
return m_event->contentJson()["m.relates_to"_ls].toObject()["m.in_reply_to"_ls].toObject()["event_id"_ls].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
DelegateType::Type EventHandler::getReplyDelegateType() const
|
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);
|
auto replyEvent = m_room->getReplyForEvent(*m_event);
|
||||||
if (replyEvent == nullptr) {
|
if (replyEvent == nullptr) {
|
||||||
return DelegateType::Other;
|
return DelegateType::Other;
|
||||||
@@ -901,8 +948,45 @@ QVariantMap EventHandler::getReplyMediaInfo() const
|
|||||||
return getMediaInfoForEvent(replyPtr);
|
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
|
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();
|
const auto geoUri = m_event->contentJson()["geo_uri"_ls].toString();
|
||||||
if (geoUri.isEmpty()) {
|
if (geoUri.isEmpty()) {
|
||||||
return -100.0; // latitude runs from -90deg to +90deg so -100 is out of range.
|
return -100.0; // latitude runs from -90deg to +90deg so -100 is out of range.
|
||||||
@@ -913,6 +997,11 @@ float EventHandler::getLatitude() const
|
|||||||
|
|
||||||
float EventHandler::getLongitude() 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();
|
const auto geoUri = m_event->contentJson()["geo_uri"_ls].toString();
|
||||||
if (geoUri.isEmpty()) {
|
if (geoUri.isEmpty()) {
|
||||||
return -200.0; // longitude runs from -180deg to +180deg so -200 is out of range.
|
return -200.0; // longitude runs from -180deg to +180deg so -200 is out of range.
|
||||||
@@ -923,6 +1012,11 @@ float EventHandler::getLongitude() const
|
|||||||
|
|
||||||
QString EventHandler::getLocationAssetType() 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();
|
const auto assetType = m_event->contentJson()["org.matrix.msc3488.asset"_ls].toObject()["type"_ls].toString();
|
||||||
if (assetType.isEmpty()) {
|
if (assetType.isEmpty()) {
|
||||||
return {};
|
return {};
|
||||||
@@ -932,6 +1026,15 @@ QString EventHandler::getLocationAssetType() const
|
|||||||
|
|
||||||
bool EventHandler::hasReadMarkers() 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());
|
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||||
userIds.remove(m_room->localUser()->id());
|
userIds.remove(m_room->localUser()->id());
|
||||||
return userIds.size() > 0;
|
return userIds.size() > 0;
|
||||||
@@ -939,6 +1042,15 @@ bool EventHandler::hasReadMarkers() const
|
|||||||
|
|
||||||
QVariantList EventHandler::getReadMarkers(int maxMarkers) 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());
|
auto userIds_temp = m_room->userIdsAtEvent(m_event->id());
|
||||||
userIds_temp.remove(m_room->localUser()->id());
|
userIds_temp.remove(m_room->localUser()->id());
|
||||||
|
|
||||||
@@ -959,6 +1071,15 @@ QVariantList EventHandler::getReadMarkers(int maxMarkers) const
|
|||||||
|
|
||||||
QString EventHandler::getNumberExcessReadMarkers(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());
|
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||||
userIds.remove(m_room->localUser()->id());
|
userIds.remove(m_room->localUser()->id());
|
||||||
|
|
||||||
@@ -971,6 +1092,15 @@ QString EventHandler::getNumberExcessReadMarkers(int maxMarkers) const
|
|||||||
|
|
||||||
QString EventHandler::getReadMarkersString() 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());
|
auto userIds = m_room->userIdsAtEvent(m_event->id());
|
||||||
userIds.remove(m_room->localUser()->id());
|
userIds.remove(m_room->localUser()->id());
|
||||||
|
|
||||||
|
|||||||
@@ -326,6 +326,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
QVariantMap getReplyMediaInfo() const;
|
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.
|
* @brief Return the latitude for the event.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QVector>
|
#include <QList>
|
||||||
#include <Quotient/events/eventcontent.h>
|
#include <Quotient/events/eventcontent.h>
|
||||||
#include <Quotient/events/stateevent.h>
|
#include <Quotient/events/stateevent.h>
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @sa ImagePackImage
|
* @sa ImagePackImage
|
||||||
*/
|
*/
|
||||||
QVector<ImagePackEventContent::ImagePackImage> images;
|
QList<ImagePackEventContent::ImagePackImage> images;
|
||||||
|
|
||||||
explicit ImagePackEventContent(const QJsonObject &o);
|
explicit ImagePackEventContent(const QJsonObject &o);
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ class LocationHelper : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
QML_UNCREATABLE("")
|
QML_SINGLETON
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Unite two rectanlges. */
|
/** Unite two rectanlges. */
|
||||||
Q_INVOKABLE static QRectF unite(const QRectF &r1, const QRectF &r2);
|
Q_INVOKABLE static QRectF unite(const QRectF &r1, const QRectF &r2);
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public:
|
|||||||
file.write(buf.constData(), buf.size());
|
file.write(buf.constData(), buf.size());
|
||||||
file.flush();
|
file.flush();
|
||||||
|
|
||||||
if (oldHandler && (strcmp(context.category, "quotient.e2ee") != 0 || e2eeDebugEnabled)) {
|
if (oldHandler && (!context.category || (strcmp(context.category, "quotient.e2ee") != 0 || e2eeDebugEnabled))) {
|
||||||
oldHandler(type, context, message);
|
oldHandler(type, context, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,7 +197,6 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt
|
|||||||
break;
|
break;
|
||||||
case QtFatalMsg:
|
case QtFatalMsg:
|
||||||
sInstance()->log(QtInfoMsg, context, message);
|
sInstance()->log(QtInfoMsg, context, message);
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +211,7 @@ void filter(QLoggingCategory *category)
|
|||||||
|
|
||||||
void initLogging()
|
void initLogging()
|
||||||
{
|
{
|
||||||
e2eeDebugEnabled = QLoggingCategory("quotient.e2ee", QtDebugMsg).isEnabled(QtDebugMsg);
|
e2eeDebugEnabled = QLoggingCategory("quotient.e2ee", QtInfoMsg).isEnabled(QtDebugMsg);
|
||||||
oldCategoryFilter = QLoggingCategory::installFilter(filter);
|
oldCategoryFilter = QLoggingCategory::installFilter(filter);
|
||||||
oldHandler = qInstallMessageHandler(messageHandler);
|
oldHandler = qInstallMessageHandler(messageHandler);
|
||||||
sInstance->setOrigHandler(oldHandler);
|
sInstance->setOrigHandler(oldHandler);
|
||||||
|
|||||||
@@ -100,7 +100,8 @@ void LoginHelper::init()
|
|||||||
Q_EMIT Controller::instance().globalErrorOccured(i18n("Network Error"), std::move(error));
|
Q_EMIT Controller::instance().globalErrorOccured(i18n("Network Error"), std::move(error));
|
||||||
});
|
});
|
||||||
|
|
||||||
connectSingleShot(m_connection, &Connection::syncDone, this, []() {
|
connectSingleShot(m_connection, &Connection::syncDone, this, [this]() {
|
||||||
|
Q_EMIT loaded();
|
||||||
Q_EMIT Controller::instance().initiated();
|
Q_EMIT Controller::instance().initiated();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/login.h
14
src/login.h
@@ -79,7 +79,17 @@ class LoginHelper : public QObject
|
|||||||
Q_PROPERTY(bool isInvalidPassword READ isInvalidPassword NOTIFY isInvalidPasswordChanged)
|
Q_PROPERTY(bool isInvalidPassword READ isInvalidPassword NOTIFY isInvalidPasswordChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LoginHelper(QObject *parent = nullptr);
|
static LoginHelper &instance()
|
||||||
|
{
|
||||||
|
static LoginHelper _instance;
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LoginHelper *create(QQmlEngine *engine, QJSEngine *)
|
||||||
|
{
|
||||||
|
engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership);
|
||||||
|
return &instance();
|
||||||
|
}
|
||||||
|
|
||||||
Q_INVOKABLE void init();
|
Q_INVOKABLE void init();
|
||||||
|
|
||||||
@@ -125,6 +135,7 @@ Q_SIGNALS:
|
|||||||
void isLoggingInChanged();
|
void isLoggingInChanged();
|
||||||
void isLoggedInChanged();
|
void isLoggedInChanged();
|
||||||
void isInvalidPasswordChanged();
|
void isInvalidPasswordChanged();
|
||||||
|
void loaded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setHomeserverReachable(bool reachable);
|
void setHomeserverReachable(bool reachable);
|
||||||
@@ -141,4 +152,5 @@ private:
|
|||||||
bool m_isLoggingIn = false;
|
bool m_isLoggingIn = false;
|
||||||
bool m_isLoggedIn = false;
|
bool m_isLoggedIn = false;
|
||||||
bool m_invalidPassword = 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 "neochat-version.h"
|
||||||
|
|
||||||
#include <Quotient/networkaccessmanager.h>
|
#include <Quotient/networkaccessmanager.h>
|
||||||
#include <Quotient/util.h>
|
|
||||||
|
|
||||||
#include "blurhashimageprovider.h"
|
#include "blurhashimageprovider.h"
|
||||||
|
#include "colorschemer.h"
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "matriximageprovider.h"
|
#include "matriximageprovider.h"
|
||||||
@@ -45,10 +45,6 @@
|
|||||||
#include "roommanager.h"
|
#include "roommanager.h"
|
||||||
#include "windowcontroller.h"
|
#include "windowcontroller.h"
|
||||||
|
|
||||||
#ifdef HAVE_COLORSCHEME
|
|
||||||
#include "colorschemer.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_RUNNER
|
#ifdef HAVE_RUNNER
|
||||||
#include "runner.h"
|
#include "runner.h"
|
||||||
#include <QDBusConnection>
|
#include <QDBusConnection>
|
||||||
@@ -125,7 +121,7 @@ int main(int argc, char *argv[])
|
|||||||
font.setHintingPreference(QFont::PreferNoHinting);
|
font.setHintingPreference(QFont::PreferNoHinting);
|
||||||
app.setFont(font);
|
app.setFont(font);
|
||||||
#endif
|
#endif
|
||||||
KLocalizedString::setApplicationDomain("neochat");
|
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
||||||
|
|
||||||
QGuiApplication::setOrganizationName("KDE"_ls);
|
QGuiApplication::setOrganizationName("KDE"_ls);
|
||||||
|
|
||||||
@@ -135,7 +131,11 @@ int main(int argc, char *argv[])
|
|||||||
i18n("Matrix client"),
|
i18n("Matrix client"),
|
||||||
KAboutLicense::GPL_V3,
|
KAboutLicense::GPL_V3,
|
||||||
i18n("© 2018-2020 Black Hat, 2020-2023 KDE Community"));
|
i18n("© 2018-2020 Black Hat, 2020-2023 KDE Community"));
|
||||||
about.addAuthor(i18n("Carl Schwan"), i18n("Maintainer"), QStringLiteral("carl@carlschwan.eu"), QStringLiteral("https://carlschwan.eu"));
|
about.addAuthor(i18n("Carl Schwan"),
|
||||||
|
i18n("Maintainer"),
|
||||||
|
QStringLiteral("carl@carlschwan.eu"),
|
||||||
|
QStringLiteral("https://carlschwan.eu"),
|
||||||
|
QStringLiteral("https://carlschwan.eu/avatar.png"));
|
||||||
about.addAuthor(i18n("Tobias Fella"), i18n("Maintainer"), QStringLiteral("tobias.fella@kde.org"), QStringLiteral("https://tobiasfella.de"));
|
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.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"));
|
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.setOrganizationDomain("kde.org");
|
||||||
|
|
||||||
about.addComponent(QStringLiteral("libQuotient"),
|
about.addComponent(QStringLiteral("libQuotient"),
|
||||||
i18n("A Qt5 library to write cross-platform clients for Matrix"),
|
i18n("A Qt library to write cross-platform clients for Matrix"),
|
||||||
i18nc("<version number> (built against <possibly different version number>)",
|
i18nc("<version number> (built against <possibly different version number>)",
|
||||||
"%1 (built against %2)",
|
"%1 (built against %2)",
|
||||||
Quotient::versionString(),
|
Quotient::versionString(),
|
||||||
@@ -157,9 +157,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
initLogging();
|
initLogging();
|
||||||
|
|
||||||
#if Quotient_VERSION_MINOR == 8
|
|
||||||
Connection::setEncryptionDefault(true);
|
Connection::setEncryptionDefault(true);
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef NEOCHAT_FLATPAK
|
#ifdef NEOCHAT_FLATPAK
|
||||||
// Copy over the included FontConfig configuration to the
|
// Copy over the included FontConfig configuration to the
|
||||||
@@ -168,12 +166,10 @@ int main(int argc, char *argv[])
|
|||||||
QStringLiteral("/var/config/fontconfig/conf.d/99-noto-mono-color-emoji.conf"));
|
QStringLiteral("/var/config/fontconfig/conf.d/99-noto-mono-color-emoji.conf"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_COLORSCHEME
|
|
||||||
ColorSchemer colorScheme;
|
ColorSchemer colorScheme;
|
||||||
if (!NeoChatConfig::self()->colorScheme().isEmpty()) {
|
if (!NeoChatConfig::self()->colorScheme().isEmpty()) {
|
||||||
colorScheme.apply(NeoChatConfig::self()->colorScheme());
|
colorScheme.apply(NeoChatConfig::self()->colorScheme());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
qml_register_types_org_kde_neochat();
|
qml_register_types_org_kde_neochat();
|
||||||
qmlRegisterSingletonInstance("org.kde.neochat.config", 1, 0, "Config", NeoChatConfig::self());
|
qmlRegisterSingletonInstance("org.kde.neochat.config", 1, 0, "Config", NeoChatConfig::self());
|
||||||
@@ -227,7 +223,7 @@ int main(int argc, char *argv[])
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.addImageProvider(QLatin1String("mxc"), new MatrixImageProvider);
|
engine.addImageProvider(QLatin1String("mxc"), MatrixImageProvider::create(&engine, &engine));
|
||||||
engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider);
|
engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider);
|
||||||
|
|
||||||
engine.load(QUrl(QStringLiteral("qrc:/org/kde/neochat/qml/main.qml")));
|
engine.load(QUrl(QStringLiteral("qrc:/org/kde/neochat/qml/main.qml")));
|
||||||
@@ -240,8 +236,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_RUNNER
|
#ifdef HAVE_RUNNER
|
||||||
Runner runner;
|
auto runner = Runner::create(&engine, &engine);
|
||||||
QDBusConnection::sessionBus().registerObject("/RoomRunner"_ls, &runner, QDBusConnection::ExportScriptableContents);
|
QDBusConnection::sessionBus().registerObject("/RoomRunner"_ls, runner, QDBusConnection::ExportScriptableContents);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QWindow *window = windowFromEngine(&engine);
|
QWindow *window = windowFromEngine(&engine);
|
||||||
|
|||||||
@@ -13,11 +13,13 @@
|
|||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
|
#include "neochatconnection.h"
|
||||||
|
|
||||||
#include <Quotient/connection.h>
|
#include <Quotient/connection.h>
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
ThumbnailResponse::ThumbnailResponse(QString id, QSize size)
|
ThumbnailResponse::ThumbnailResponse(QString id, QSize size, NeoChatConnection *connection)
|
||||||
: mediaId(std::move(id))
|
: mediaId(std::move(id))
|
||||||
, requestedSize(size)
|
, requestedSize(size)
|
||||||
, localFile(QStringLiteral("%1/image_provider/%2-%3x%4.png")
|
, localFile(QStringLiteral("%1/image_provider/%2-%3x%4.png")
|
||||||
@@ -25,6 +27,7 @@ ThumbnailResponse::ThumbnailResponse(QString id, QSize size)
|
|||||||
mediaId,
|
mediaId,
|
||||||
QString::number(requestedSize.width()),
|
QString::number(requestedSize.width()),
|
||||||
QString::number(requestedSize.height())))
|
QString::number(requestedSize.height())))
|
||||||
|
, m_connection(connection)
|
||||||
, errorStr("Image request hasn't started"_ls)
|
, errorStr("Image request hasn't started"_ls)
|
||||||
{
|
{
|
||||||
if (requestedSize.isEmpty()) {
|
if (requestedSize.isEmpty()) {
|
||||||
@@ -51,24 +54,24 @@ ThumbnailResponse::ThumbnailResponse(QString id, QSize size)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Controller::instance().activeConnection()) {
|
if (!m_connection) {
|
||||||
qWarning() << "Current connection is null";
|
qWarning() << "Current connection is null";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute a request on the main thread asynchronously
|
// Execute a request on the main thread asynchronously
|
||||||
moveToThread(Controller::instance().activeConnection()->thread());
|
moveToThread(m_connection->thread());
|
||||||
QMetaObject::invokeMethod(this, &ThumbnailResponse::startRequest, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, &ThumbnailResponse::startRequest, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThumbnailResponse::startRequest()
|
void ThumbnailResponse::startRequest()
|
||||||
{
|
{
|
||||||
if (!Controller::instance().activeConnection()) {
|
if (!m_connection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Runs in the main thread, not QML thread
|
// Runs in the main thread, not QML thread
|
||||||
Q_ASSERT(QThread::currentThread() == Controller::instance().activeConnection()->thread());
|
Q_ASSERT(QThread::currentThread() == m_connection->thread());
|
||||||
job = Controller::instance().activeConnection()->getThumbnail(mediaId, requestedSize);
|
job = m_connection->getThumbnail(mediaId, requestedSize);
|
||||||
// Connect to any possible outcome including abandonment
|
// Connect to any possible outcome including abandonment
|
||||||
// to make sure the QML thread is not left stuck forever.
|
// to make sure the QML thread is not left stuck forever.
|
||||||
connect(job, &BaseJob::finished, this, &ThumbnailResponse::prepareResult);
|
connect(job, &BaseJob::finished, this, &ThumbnailResponse::prepareResult);
|
||||||
@@ -118,7 +121,7 @@ QString ThumbnailResponse::errorString() const
|
|||||||
|
|
||||||
QQuickImageResponse *MatrixImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
|
QQuickImageResponse *MatrixImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
|
||||||
{
|
{
|
||||||
return new ThumbnailResponse(id, requestedSize);
|
return new ThumbnailResponse(id, requestedSize, m_connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_matriximageprovider.cpp"
|
#include "moc_matriximageprovider.cpp"
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
|
|
||||||
|
class NeoChatConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class ThumbnailResponse
|
* @class ThumbnailResponse
|
||||||
*
|
*
|
||||||
@@ -21,7 +23,7 @@ class ThumbnailResponse : public QQuickImageResponse
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ThumbnailResponse(QString mediaId, QSize requestedSize);
|
explicit ThumbnailResponse(QString mediaId, QSize requestedSize, NeoChatConnection *m_connection);
|
||||||
~ThumbnailResponse() override = default;
|
~ThumbnailResponse() override = default;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
@@ -33,6 +35,7 @@ private:
|
|||||||
QSize requestedSize;
|
QSize requestedSize;
|
||||||
const QString localFile;
|
const QString localFile;
|
||||||
Quotient::MediaThumbnailJob *job = nullptr;
|
Quotient::MediaThumbnailJob *job = nullptr;
|
||||||
|
NeoChatConnection *m_connection;
|
||||||
|
|
||||||
QImage image;
|
QImage image;
|
||||||
QString errorStr;
|
QString errorStr;
|
||||||
@@ -51,11 +54,27 @@ private:
|
|||||||
*/
|
*/
|
||||||
class MatrixImageProvider : public QQuickAsyncImageProvider
|
class MatrixImageProvider : public QQuickAsyncImageProvider
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_SINGLETON
|
||||||
|
|
||||||
|
Q_PROPERTY(NeoChatConnection *connection MEMBER m_connection)
|
||||||
public:
|
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.
|
* @brief Return a job to provide the image with the given ID.
|
||||||
*
|
*
|
||||||
* @sa QQuickAsyncImageProvider::requestImageResponse
|
* @sa QQuickAsyncImageProvider::requestImageResponse
|
||||||
*/
|
*/
|
||||||
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
|
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
NeoChatConnection *m_connection = nullptr;
|
||||||
|
MatrixImageProvider() = default;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QCoroTask>
|
#include <QCoroTask>
|
||||||
|
#include <QList>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QVector>
|
|
||||||
|
|
||||||
#include <Quotient/connection.h>
|
#include <Quotient/connection.h>
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "actionsmodel.h"
|
#include "actionsmodel.h"
|
||||||
|
|
||||||
|
#include "chatbarcache.h"
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "roommanager.h"
|
#include "roommanager.h"
|
||||||
@@ -19,7 +20,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,
|
"#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};
|
"#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) {
|
auto leaveRoomLambda = [](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
if (text.isEmpty()) {
|
if (text.isEmpty()) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18n("Leaving this room."));
|
Q_EMIT room->showMessage(NeoChatRoom::Info, i18n("Leaving this room."));
|
||||||
room->connection()->leaveRoom(room);
|
room->connection()->leaveRoom(room);
|
||||||
@@ -45,7 +46,7 @@ auto leaveRoomLambda = [](const QString &text, NeoChatRoom *room) {
|
|||||||
return QString();
|
return QString();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto roomNickLambda = [](const QString &text, NeoChatRoom *room) {
|
auto roomNickLambda = [](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
if (text.isEmpty()) {
|
if (text.isEmpty()) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("No new nickname provided, no changes will happen."));
|
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("No new nickname provided, no changes will happen."));
|
||||||
} else {
|
} else {
|
||||||
@@ -54,10 +55,10 @@ auto roomNickLambda = [](const QString &text, NeoChatRoom *room) {
|
|||||||
return QString();
|
return QString();
|
||||||
};
|
};
|
||||||
|
|
||||||
QVector<ActionsModel::Action> actions{
|
QList<ActionsModel::Action> actions{
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("shrug"),
|
QStringLiteral("shrug"),
|
||||||
[](const QString &message, NeoChatRoom *) {
|
[](const QString &message, NeoChatRoom *, ChatBarCache *) {
|
||||||
return QStringLiteral("¯\\\\_(ツ)_/¯ %1").arg(message);
|
return QStringLiteral("¯\\\\_(ツ)_/¯ %1").arg(message);
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
@@ -67,7 +68,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("lenny"),
|
QStringLiteral("lenny"),
|
||||||
[](const QString &message, NeoChatRoom *) {
|
[](const QString &message, NeoChatRoom *, ChatBarCache *) {
|
||||||
return QStringLiteral("( ͡° ͜ʖ ͡°) %1").arg(message);
|
return QStringLiteral("( ͡° ͜ʖ ͡°) %1").arg(message);
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
@@ -77,7 +78,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("tableflip"),
|
QStringLiteral("tableflip"),
|
||||||
[](const QString &message, NeoChatRoom *) {
|
[](const QString &message, NeoChatRoom *, ChatBarCache *) {
|
||||||
return QStringLiteral("(╯°□°)╯︵ ┻━┻ %1").arg(message);
|
return QStringLiteral("(╯°□°)╯︵ ┻━┻ %1").arg(message);
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
@@ -87,7 +88,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("unflip"),
|
QStringLiteral("unflip"),
|
||||||
[](const QString &message, NeoChatRoom *) {
|
[](const QString &message, NeoChatRoom *, ChatBarCache *) {
|
||||||
return QStringLiteral("┬──┬ ノ( ゜-゜ノ) %1").arg(message);
|
return QStringLiteral("┬──┬ ノ( ゜-゜ノ) %1").arg(message);
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
@@ -97,7 +98,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("rainbow"),
|
QStringLiteral("rainbow"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *chatBarCache) {
|
||||||
QString rainbowText;
|
QString rainbowText;
|
||||||
for (int i = 0; i < text.length(); i++) {
|
for (int i = 0; i < text.length(); i++) {
|
||||||
rainbowText += QStringLiteral("<font color='%2'>%3</font>").arg(rainbowColors[i % rainbowColors.length()], text.at(i));
|
rainbowText += QStringLiteral("<font color='%2'>%3</font>").arg(rainbowColors[i % rainbowColors.length()], text.at(i));
|
||||||
@@ -106,8 +107,8 @@ QVector<ActionsModel::Action> actions{
|
|||||||
room->postMessage(QStringLiteral("/rainbow %1").arg(text),
|
room->postMessage(QStringLiteral("/rainbow %1").arg(text),
|
||||||
rainbowText,
|
rainbowText,
|
||||||
RoomMessageEvent::MsgType::Text,
|
RoomMessageEvent::MsgType::Text,
|
||||||
room->chatBoxReplyId(),
|
chatBarCache->replyId(),
|
||||||
room->chatBoxEditId());
|
chatBarCache->editId());
|
||||||
return QString();
|
return QString();
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
@@ -117,7 +118,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("rainbowme"),
|
QStringLiteral("rainbowme"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *chatBarCache) {
|
||||||
QString rainbowText;
|
QString rainbowText;
|
||||||
for (int i = 0; i < text.length(); i++) {
|
for (int i = 0; i < text.length(); i++) {
|
||||||
rainbowText += QStringLiteral("<font color='%2'>%3</font>").arg(rainbowColors[i % rainbowColors.length()], text.at(i));
|
rainbowText += QStringLiteral("<font color='%2'>%3</font>").arg(rainbowColors[i % rainbowColors.length()], text.at(i));
|
||||||
@@ -126,8 +127,8 @@ QVector<ActionsModel::Action> actions{
|
|||||||
room->postMessage(QStringLiteral("/rainbow %1").arg(text),
|
room->postMessage(QStringLiteral("/rainbow %1").arg(text),
|
||||||
rainbowText,
|
rainbowText,
|
||||||
RoomMessageEvent::MsgType::Emote,
|
RoomMessageEvent::MsgType::Emote,
|
||||||
room->chatBoxReplyId(),
|
chatBarCache->replyId(),
|
||||||
room->chatBoxEditId());
|
chatBarCache->editId());
|
||||||
return QString();
|
return QString();
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
@@ -137,7 +138,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("plain"),
|
QStringLiteral("plain"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
room->postMessage(text, text.toHtmlEscaped(), RoomMessageEvent::MsgType::Text, {}, {});
|
room->postMessage(text, text.toHtmlEscaped(), RoomMessageEvent::MsgType::Text, {}, {});
|
||||||
return QString();
|
return QString();
|
||||||
},
|
},
|
||||||
@@ -148,13 +149,13 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("spoiler"),
|
QStringLiteral("spoiler"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *chatBarCache) {
|
||||||
// Ideally, we would just return rainbowText and let that do the rest, but the colors don't survive markdownToHTML.
|
// 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),
|
room->postMessage(QStringLiteral("/spoiler %1").arg(text),
|
||||||
QStringLiteral("<span data-mx-spoiler>%1</span>").arg(text),
|
QStringLiteral("<span data-mx-spoiler>%1</span>").arg(text),
|
||||||
RoomMessageEvent::MsgType::Text,
|
RoomMessageEvent::MsgType::Text,
|
||||||
room->chatBoxReplyId(),
|
chatBarCache->replyId(),
|
||||||
room->chatBoxEditId());
|
chatBarCache->editId());
|
||||||
return QString();
|
return QString();
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
@@ -164,7 +165,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("me"),
|
QStringLiteral("me"),
|
||||||
[](const QString &text, NeoChatRoom *) {
|
[](const QString &text, NeoChatRoom *, ChatBarCache *) {
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
@@ -174,7 +175,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("notice"),
|
QStringLiteral("notice"),
|
||||||
[](const QString &text, NeoChatRoom *) {
|
[](const QString &text, NeoChatRoom *, ChatBarCache *) {
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
@@ -184,7 +185,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("invite"),
|
QStringLiteral("invite"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
static const QRegularExpression mxidRegex(
|
static const QRegularExpression mxidRegex(
|
||||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||||
auto regexMatch = mxidRegex.match(text);
|
auto regexMatch = mxidRegex.match(text);
|
||||||
@@ -220,7 +221,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("join"),
|
QStringLiteral("join"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
||||||
auto regexMatch = roomRegex.match(text);
|
auto regexMatch = roomRegex.match(text);
|
||||||
if (!regexMatch.hasMatch()) {
|
if (!regexMatch.hasMatch()) {
|
||||||
@@ -244,7 +245,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("knock"),
|
QStringLiteral("knock"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
auto parts = text.split(QLatin1String(" "));
|
auto parts = text.split(QLatin1String(" "));
|
||||||
QString roomName = parts[0];
|
QString roomName = parts[0];
|
||||||
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
||||||
@@ -260,7 +261,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Knocking room <roomname>.", "Knocking room %1.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Knocking room <roomname>.", "Knocking room %1.", text));
|
||||||
auto connection = Controller::instance().activeConnection();
|
auto connection = room->connection();
|
||||||
const auto knownServer = roomName.mid(roomName.indexOf(":"_ls) + 1);
|
const auto knownServer = roomName.mid(roomName.indexOf(":"_ls) + 1);
|
||||||
if (parts.length() >= 2) {
|
if (parts.length() >= 2) {
|
||||||
RoomManager::instance().knockRoom(connection, roomName, parts[1], QStringList{knownServer});
|
RoomManager::instance().knockRoom(connection, roomName, parts[1], QStringList{knownServer});
|
||||||
@@ -276,7 +277,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("j"),
|
QStringLiteral("j"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
||||||
auto regexMatch = roomRegex.match(text);
|
auto regexMatch = roomRegex.match(text);
|
||||||
if (!regexMatch.hasMatch()) {
|
if (!regexMatch.hasMatch()) {
|
||||||
@@ -284,7 +285,7 @@ QVector<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));
|
i18nc("'<text>' does not look like a room id or alias.", "'%1' does not look like a room id or alias.", text));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (Controller::instance().activeConnection()->room(text) || Controller::instance().activeConnection()->roomByAlias(text)) {
|
if (room->connection()->room(text) || room->connection()->roomByAlias(text)) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("You are already in room <roomname>.", "You are already in room %1.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("You are already in room <roomname>.", "You are already in room %1.", text));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@@ -315,7 +316,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("nick"),
|
QStringLiteral("nick"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
if (text.isEmpty()) {
|
if (text.isEmpty()) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("No new nickname provided, no changes will happen."));
|
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("No new nickname provided, no changes will happen."));
|
||||||
} else {
|
} else {
|
||||||
@@ -346,7 +347,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("ignore"),
|
QStringLiteral("ignore"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
static const QRegularExpression mxidRegex(
|
static const QRegularExpression mxidRegex(
|
||||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||||
auto regexMatch = mxidRegex.match(text);
|
auto regexMatch = mxidRegex.match(text);
|
||||||
@@ -374,7 +375,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("unignore"),
|
QStringLiteral("unignore"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
static const QRegularExpression mxidRegex(
|
static const QRegularExpression mxidRegex(
|
||||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||||
auto regexMatch = mxidRegex.match(text);
|
auto regexMatch = mxidRegex.match(text);
|
||||||
@@ -402,9 +403,8 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("react"),
|
QStringLiteral("react"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *chatBarCache) {
|
||||||
QString replyEventId = room->chatBoxReplyId();
|
if (chatBarCache->replyId().isEmpty()) {
|
||||||
if (replyEventId.isEmpty()) {
|
|
||||||
for (auto it = room->messageEvents().crbegin(); it != room->messageEvents().crend(); it++) {
|
for (auto it = room->messageEvents().crbegin(); it != room->messageEvents().crend(); it++) {
|
||||||
const auto &evt = **it;
|
const auto &evt = **it;
|
||||||
if (const auto event = eventCast<const RoomMessageEvent>(&evt)) {
|
if (const auto event = eventCast<const RoomMessageEvent>(&evt)) {
|
||||||
@@ -413,7 +413,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
room->toggleReaction(replyEventId, text);
|
room->toggleReaction(chatBarCache->replyId(), text);
|
||||||
return QString();
|
return QString();
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
@@ -423,7 +423,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("ban"),
|
QStringLiteral("ban"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
auto parts = text.split(QLatin1String(" "));
|
auto parts = text.split(QLatin1String(" "));
|
||||||
static const QRegularExpression mxidRegex(
|
static const QRegularExpression mxidRegex(
|
||||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||||
@@ -462,7 +462,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("unban"),
|
QStringLiteral("unban"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
static const QRegularExpression mxidRegex(
|
static const QRegularExpression mxidRegex(
|
||||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||||
auto regexMatch = mxidRegex.match(text);
|
auto regexMatch = mxidRegex.match(text);
|
||||||
@@ -495,7 +495,7 @@ QVector<ActionsModel::Action> actions{
|
|||||||
},
|
},
|
||||||
Action{
|
Action{
|
||||||
QStringLiteral("kick"),
|
QStringLiteral("kick"),
|
||||||
[](const QString &text, NeoChatRoom *room) {
|
[](const QString &text, NeoChatRoom *room, ChatBarCache *) {
|
||||||
auto parts = text.split(QLatin1String(" "));
|
auto parts = text.split(QLatin1String(" "));
|
||||||
static const QRegularExpression mxidRegex(
|
static const QRegularExpression mxidRegex(
|
||||||
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))"));
|
||||||
@@ -574,7 +574,7 @@ QHash<int, QByteArray> ActionsModel::roleNames() const
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<Action> &ActionsModel::allActions() const
|
QList<Action> &ActionsModel::allActions() const
|
||||||
{
|
{
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <Quotient/events/roommessageevent.h>
|
#include <Quotient/events/roommessageevent.h>
|
||||||
|
|
||||||
|
class ChatBarCache;
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,7 +29,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief The function to execute when the action is triggered.
|
* @brief The function to execute when the action is triggered.
|
||||||
*/
|
*/
|
||||||
std::function<QString(const QString &, NeoChatRoom *)> handle;
|
std::function<QString(const QString &, NeoChatRoom *, ChatBarCache *)> handle;
|
||||||
/**
|
/**
|
||||||
* @brief Whether the action is a message type action.
|
* @brief Whether the action is a message type action.
|
||||||
*
|
*
|
||||||
@@ -87,7 +88,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Return a vector with all supported actions.
|
* @brief Return a vector with all supported actions.
|
||||||
*/
|
*/
|
||||||
QVector<Action> &allActions() const;
|
QList<Action> &allActions() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ActionsModel() = default;
|
ActionsModel() = default;
|
||||||
|
|||||||
@@ -15,13 +15,28 @@
|
|||||||
|
|
||||||
using namespace Quotient;
|
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()
|
void CustomEmojiModel::fetchEmojis()
|
||||||
{
|
{
|
||||||
if (!Controller::instance().activeConnection()) {
|
if (!m_connection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes"_ls);
|
const auto &data = m_connection->accountData("im.ponies.user_emotes"_ls);
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -53,10 +68,10 @@ void CustomEmojiModel::addEmoji(const QString &name, const QUrl &location)
|
|||||||
{
|
{
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
auto job = Controller::instance().activeConnection()->uploadFile(location.toLocalFile());
|
auto job = m_connection->uploadFile(location.toLocalFile());
|
||||||
|
|
||||||
connect(job, &BaseJob::success, this, [name, location, job] {
|
connect(job, &BaseJob::success, this, [name, location, job, this] {
|
||||||
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes"_ls);
|
const auto &data = m_connection->accountData("im.ponies.user_emotes"_ls);
|
||||||
auto json = data != nullptr ? data->contentJson() : QJsonObject();
|
auto json = data != nullptr ? data->contentJson() : QJsonObject();
|
||||||
auto emojiData = json["images"_ls].toObject();
|
auto emojiData = json["images"_ls].toObject();
|
||||||
|
|
||||||
@@ -78,7 +93,7 @@ void CustomEmojiModel::addEmoji(const QString &name, const QUrl &location)
|
|||||||
});
|
});
|
||||||
|
|
||||||
json["images"_ls] = emojiData;
|
json["images"_ls] = emojiData;
|
||||||
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes"_ls, json);
|
m_connection->setAccountData("im.ponies.user_emotes"_ls, json);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +101,7 @@ void CustomEmojiModel::removeEmoji(const QString &name)
|
|||||||
{
|
{
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes"_ls);
|
const auto &data = m_connection->accountData("im.ponies.user_emotes"_ls);
|
||||||
Q_ASSERT(data);
|
Q_ASSERT(data);
|
||||||
auto json = data->contentJson();
|
auto json = data->contentJson();
|
||||||
const QString _name = name.mid(1).chopped(1);
|
const QString _name = name.mid(1).chopped(1);
|
||||||
@@ -109,18 +124,18 @@ void CustomEmojiModel::removeEmoji(const QString &name)
|
|||||||
emojiData.remove(_name);
|
emojiData.remove(_name);
|
||||||
json["emoticons"_ls] = emojiData;
|
json["emoticons"_ls] = emojiData;
|
||||||
}
|
}
|
||||||
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes"_ls, json);
|
m_connection->setAccountData("im.ponies.user_emotes"_ls, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomEmojiModel::CustomEmojiModel(QObject *parent)
|
CustomEmojiModel::CustomEmojiModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, [this]() {
|
connect(this, &CustomEmojiModel::connectionChanged, this, [this]() {
|
||||||
if (!Controller::instance().activeConnection()) {
|
if (!m_connection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CustomEmojiModel::fetchEmojis();
|
CustomEmojiModel::fetchEmojis();
|
||||||
connect(Controller::instance().activeConnection(), &Connection::accountDataChanged, this, [this](const QString &id) {
|
connect(m_connection, &Connection::accountDataChanged, this, [this](const QString &id) {
|
||||||
if (id != QStringLiteral("im.ponies.user_emotes")) {
|
if (id != QStringLiteral("im.ponies.user_emotes")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
class NeoChatConnection;
|
||||||
|
|
||||||
struct CustomEmoji {
|
struct CustomEmoji {
|
||||||
QString name; // with :semicolons:
|
QString name; // with :semicolons:
|
||||||
QString url; // mxc://
|
QString url; // mxc://
|
||||||
@@ -31,6 +33,8 @@ class CustomEmojiModel : public QAbstractListModel
|
|||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
QML_SINGLETON
|
QML_SINGLETON
|
||||||
|
|
||||||
|
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Defines the model roles.
|
* @brief Defines the model roles.
|
||||||
@@ -98,9 +102,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE void removeEmoji(const QString &name);
|
Q_INVOKABLE void removeEmoji(const QString &name);
|
||||||
|
|
||||||
|
void setConnection(NeoChatConnection *connection);
|
||||||
|
NeoChatConnection *connection() const;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void connectionChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit CustomEmojiModel(QObject *parent = nullptr);
|
explicit CustomEmojiModel(QObject *parent = nullptr);
|
||||||
QList<CustomEmoji> m_emojis;
|
QList<CustomEmoji> m_emojis;
|
||||||
|
NeoChatConnection *m_connection = nullptr;
|
||||||
|
|
||||||
void fetchEmojis();
|
void fetchEmojis();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ DevicesModel::DevicesModel(QObject *parent)
|
|||||||
|
|
||||||
void DevicesModel::fetchDevices()
|
void DevicesModel::fetchDevices()
|
||||||
{
|
{
|
||||||
if (Controller::instance().activeConnection()) {
|
if (m_connection) {
|
||||||
auto job = Controller::instance().activeConnection()->callApi<GetDevicesJob>();
|
auto job = m_connection->callApi<GetDevicesJob>();
|
||||||
connect(job, &BaseJob::success, this, [this, job]() {
|
connect(job, &BaseJob::success, this, [this, job]() {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_devices = job->devices();
|
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++)
|
for (index = 0; m_devices[index].deviceId != deviceId; index++)
|
||||||
;
|
;
|
||||||
|
|
||||||
auto job = Controller::instance().activeConnection()->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId);
|
auto job = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId);
|
||||||
|
|
||||||
connect(job, &BaseJob::result, this, [this, job, password, index] {
|
connect(job, &BaseJob::result, this, [this, job, password, index] {
|
||||||
auto onSuccess = [this, 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["session"_ls] = replyData["session"_ls];
|
||||||
authData["password"_ls] = password;
|
authData["password"_ls] = password;
|
||||||
authData["type"_ls] = "m.login.password"_ls;
|
authData["type"_ls] = "m.login.password"_ls;
|
||||||
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, Controller::instance().activeConnection()->user()->id()}};
|
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, m_connection->user()->id()}};
|
||||||
authData["identifier"_ls] = identifier;
|
authData["identifier"_ls] = identifier;
|
||||||
auto *innerJob = Controller::instance().activeConnection()->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
auto *innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
||||||
connect(innerJob, &BaseJob::success, this, onSuccess);
|
connect(innerJob, &BaseJob::success, this, onSuccess);
|
||||||
} else {
|
} else {
|
||||||
onSuccess();
|
onSuccess();
|
||||||
@@ -132,7 +132,7 @@ void DevicesModel::setName(const QString &deviceId, const QString &name)
|
|||||||
int index;
|
int index;
|
||||||
for (index = 0; m_devices[index].deviceId != deviceId; index++);
|
for (index = 0; m_devices[index].deviceId != deviceId; index++);
|
||||||
|
|
||||||
auto job = Controller::instance().activeConnection()->callApi<UpdateDeviceJob>(m_devices[index].deviceId, name);
|
auto job = m_connection->callApi<UpdateDeviceJob>(m_devices[index].deviceId, name);
|
||||||
QString oldName = m_devices[index].displayName;
|
QString oldName = m_devices[index].displayName;
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_devices[index].displayName = name;
|
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) {
|
connect(m_connection, &Connection::sessionVerified, this, [this](const QString &userId, const QString &deviceId) {
|
||||||
Q_UNUSED(deviceId);
|
Q_UNUSED(deviceId);
|
||||||
if (userId == Controller::instance().activeConnection()->userId()) {
|
if (userId == m_connection->userId()) {
|
||||||
fetchDevices();
|
fetchDevices();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -98,6 +98,6 @@ Q_SIGNALS:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void fetchDevices();
|
void fetchDevices();
|
||||||
QVector<Quotient::Device> m_devices;
|
QList<Quotient::Device> m_devices;
|
||||||
QPointer<Quotient::Connection> m_connection;
|
QPointer<Quotient::Connection> m_connection;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
EmojiModel::EmojiModel(QObject *parent)
|
EmojiModel::EmojiModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
|
, m_config(KSharedConfig::openStateConfig())
|
||||||
|
, m_configGroup(KConfigGroup(m_config, QStringLiteral("Editor")))
|
||||||
{
|
{
|
||||||
if (_emojis.isEmpty()) {
|
if (_emojis.isEmpty()) {
|
||||||
#include "emojis.h"
|
#include "emojis.h"
|
||||||
@@ -61,9 +63,9 @@ QHash<int, QByteArray> EmojiModel::roleNames() const
|
|||||||
return {{ShortNameRole, "shortName"}, {UnicodeRole, "unicode"}};
|
return {{ShortNameRole, "shortName"}, {UnicodeRole, "unicode"}};
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantList EmojiModel::history() const
|
QStringList EmojiModel::lastUsedEmojis() const
|
||||||
{
|
{
|
||||||
return m_settings.value(QStringLiteral("Editor/emojis"), QVariantList()).toList();
|
return m_configGroup.readEntry(QStringLiteral("lastUsedEmojis"), QStringList());
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantList EmojiModel::filterModel(const QString &filter, bool limit)
|
QVariantList EmojiModel::filterModel(const QString &filter, bool limit)
|
||||||
@@ -93,19 +95,21 @@ QVariantList EmojiModel::filterModelNoCustom(const QString &filter, bool limit)
|
|||||||
|
|
||||||
void EmojiModel::emojiUsed(const QVariant &modelData)
|
void EmojiModel::emojiUsed(const QVariant &modelData)
|
||||||
{
|
{
|
||||||
QVariantList list = history();
|
auto list = lastUsedEmojis();
|
||||||
|
const auto emoji = modelData.value<Emoji>();
|
||||||
|
|
||||||
auto it = list.begin();
|
auto it = list.begin();
|
||||||
while (it != list.end()) {
|
while (it != list.end()) {
|
||||||
if ((*it).value<Emoji>().unicode == modelData.value<Emoji>().unicode) {
|
if (*it == emoji.shortName) {
|
||||||
it = list.erase(it);
|
it = list.erase(it);
|
||||||
} else {
|
} else {
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list.push_front(modelData);
|
list.push_front(emoji.shortName);
|
||||||
m_settings.setValue(QStringLiteral("Editor/emojis"), list);
|
|
||||||
|
m_configGroup.writeEntry(QStringLiteral("lastUsedEmojis"), list);
|
||||||
|
|
||||||
Q_EMIT historyChanged();
|
Q_EMIT historyChanged();
|
||||||
}
|
}
|
||||||
@@ -113,11 +117,11 @@ void EmojiModel::emojiUsed(const QVariant &modelData)
|
|||||||
QVariantList EmojiModel::emojis(Category category) const
|
QVariantList EmojiModel::emojis(Category category) const
|
||||||
{
|
{
|
||||||
if (category == History) {
|
if (category == History) {
|
||||||
return history();
|
return emojiHistory();
|
||||||
}
|
}
|
||||||
if (category == HistoryNoCustom) {
|
if (category == HistoryNoCustom) {
|
||||||
QVariantList list;
|
QVariantList list;
|
||||||
for (const auto &e : history()) {
|
for (const auto &e : emojiHistory()) {
|
||||||
auto emoji = qvariant_cast<Emoji>(e);
|
auto emoji = qvariant_cast<Emoji>(e);
|
||||||
if (!emoji.isCustom) {
|
if (!emoji.isCustom) {
|
||||||
list.append(e);
|
list.append(e);
|
||||||
@@ -217,4 +221,19 @@ QVariantList EmojiModel::categoriesWithCustom() const
|
|||||||
return cats;
|
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"
|
#include "moc_emojimodel.cpp"
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <KConfigGroup>
|
||||||
|
#include <KSharedConfig>
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QSettings>
|
|
||||||
|
|
||||||
struct Emoji {
|
struct Emoji {
|
||||||
Emoji(QString unicode, QString shortname, bool isCustom = false)
|
Emoji(QString unicode, QString shortname, bool isCustom = false)
|
||||||
@@ -23,21 +24,6 @@ struct Emoji {
|
|||||||
}
|
}
|
||||||
Emoji() = default;
|
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 unicode;
|
||||||
QString shortName;
|
QString shortName;
|
||||||
QString description;
|
QString description;
|
||||||
@@ -63,11 +49,6 @@ class EmojiModel : public QAbstractListModel
|
|||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
QML_SINGLETON
|
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.
|
* @brief Return a list of emoji categories.
|
||||||
*
|
*
|
||||||
@@ -177,7 +158,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE QVariantList tones(const QString &baseEmoji) const;
|
Q_INVOKABLE QVariantList tones(const QString &baseEmoji) const;
|
||||||
|
|
||||||
Q_INVOKABLE QVariantList history() const;
|
/**
|
||||||
|
* @brief Return a list of the last used emoji shortnames
|
||||||
|
*/
|
||||||
|
QStringList lastUsedEmojis() const;
|
||||||
|
|
||||||
QVariantList categories() const;
|
QVariantList categories() const;
|
||||||
QVariantList categoriesWithCustom() const;
|
QVariantList categoriesWithCustom() const;
|
||||||
|
|
||||||
@@ -190,7 +175,10 @@ public Q_SLOTS:
|
|||||||
private:
|
private:
|
||||||
static QHash<Category, QVariantList> _emojis;
|
static QHash<Category, QVariantList> _emojis;
|
||||||
|
|
||||||
// TODO: Port away from QSettings
|
/// Returns QVariants containing the last used Emojis
|
||||||
QSettings m_settings;
|
QVariantList emojiHistory() const;
|
||||||
|
|
||||||
|
KSharedConfig::Ptr m_config;
|
||||||
|
KConfigGroup m_configGroup;
|
||||||
EmojiModel(QObject *parent = nullptr);
|
EmojiModel(QObject *parent = nullptr);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ void ImagePacksModel::setShowEmoticons(bool showEmoticons)
|
|||||||
m_showEmoticons = showEmoticons;
|
m_showEmoticons = showEmoticons;
|
||||||
Q_EMIT showEmoticonsChanged();
|
Q_EMIT showEmoticonsChanged();
|
||||||
}
|
}
|
||||||
QVector<Quotient::ImagePackEventContent::ImagePackImage> ImagePacksModel::images(int index)
|
QList<Quotient::ImagePackEventContent::ImagePackImage> ImagePacksModel::images(int index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= m_events.size()) {
|
if (index < 0 || index >= m_events.size()) {
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#include "events/imagepackevent.h"
|
#include "events/imagepackevent.h"
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
|
#include <QList>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QVector>
|
|
||||||
|
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Return a vector of the images in the pack at the given index.
|
* @brief Return a vector of the images in the pack at the given index.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] QVector<Quotient::ImagePackEventContent::ImagePackImage> images(int index);
|
[[nodiscard]] QList<Quotient::ImagePackEventContent::ImagePackImage> images(int index);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void roomChanged();
|
void roomChanged();
|
||||||
@@ -96,7 +96,7 @@ Q_SIGNALS:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QPointer<NeoChatRoom> m_room;
|
QPointer<NeoChatRoom> m_room;
|
||||||
QVector<Quotient::ImagePackEventContent> m_events;
|
QList<Quotient::ImagePackEventContent> m_events;
|
||||||
bool m_showStickers = true;
|
bool m_showStickers = true;
|
||||||
bool m_showEmoticons = true;
|
bool m_showEmoticons = true;
|
||||||
void reloadImages();
|
void reloadImages();
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
// 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"
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
// 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,6 +47,8 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
|
|||||||
roles[ReplyDelegateTypeRole] = "replyDelegateType";
|
roles[ReplyDelegateTypeRole] = "replyDelegateType";
|
||||||
roles[ReplyDisplayRole] = "replyDisplay";
|
roles[ReplyDisplayRole] = "replyDisplay";
|
||||||
roles[ReplyMediaInfoRole] = "replyMediaInfo";
|
roles[ReplyMediaInfoRole] = "replyMediaInfo";
|
||||||
|
roles[IsThreadedRole] = "isThreaded";
|
||||||
|
roles[ThreadRootRole] = "threadRoot";
|
||||||
roles[ShowAuthorRole] = "showAuthor";
|
roles[ShowAuthorRole] = "showAuthor";
|
||||||
roles[ShowSectionRole] = "showSection";
|
roles[ShowSectionRole] = "showSection";
|
||||||
roles[ReadMarkersRole] = "readMarkers";
|
roles[ReadMarkersRole] = "readMarkers";
|
||||||
@@ -98,7 +100,9 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
|||||||
room->setDisplayed();
|
room->setDisplayed();
|
||||||
|
|
||||||
for (auto event = m_currentRoom->messageEvents().begin(); event != m_currentRoom->messageEvents().end(); ++event) {
|
for (auto event = m_currentRoom->messageEvents().begin(); event != m_currentRoom->messageEvents().end(); ++event) {
|
||||||
createEventObjects(&*event->viewAs<RoomMessageEvent>());
|
if (const auto &roomMessageEvent = &*event->viewAs<RoomMessageEvent>()) {
|
||||||
|
createEventObjects(roomMessageEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_currentRoom->timelineSize() < 10 && !room->allHistoryLoaded()) {
|
if (m_currentRoom->timelineSize() < 10 && !room->allHistoryLoaded()) {
|
||||||
@@ -118,9 +122,8 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
|||||||
for (auto &&event : events) {
|
for (auto &&event : events) {
|
||||||
const RoomMessageEvent *message = dynamic_cast<RoomMessageEvent *>(event.get());
|
const RoomMessageEvent *message = dynamic_cast<RoomMessageEvent *>(event.get());
|
||||||
|
|
||||||
createEventObjects(message);
|
|
||||||
|
|
||||||
if (message != nullptr) {
|
if (message != nullptr) {
|
||||||
|
createEventObjects(message);
|
||||||
if (NeoChatConfig::self()->showFancyEffects()) {
|
if (NeoChatConfig::self()->showFancyEffects()) {
|
||||||
QString planBody = message->plainBody();
|
QString planBody = message->plainBody();
|
||||||
// snowflake
|
// snowflake
|
||||||
@@ -156,8 +159,9 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
|||||||
});
|
});
|
||||||
connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this, [this](RoomEventsRange events) {
|
connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this, [this](RoomEventsRange events) {
|
||||||
for (auto &event : events) {
|
for (auto &event : events) {
|
||||||
RoomMessageEvent *message = dynamic_cast<RoomMessageEvent *>(event.get());
|
if (const auto &roomMessageEvent = dynamic_cast<RoomMessageEvent *>(event.get())) {
|
||||||
createEventObjects(message);
|
createEventObjects(roomMessageEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (rowCount() > 0) {
|
if (rowCount() > 0) {
|
||||||
rowBelowInserted = rowCount() - 1; // See #312
|
rowBelowInserted = rowCount() - 1; // See #312
|
||||||
@@ -226,7 +230,9 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
|||||||
}
|
}
|
||||||
const auto eventIt = m_currentRoom->findInTimeline(eventId);
|
const auto eventIt = m_currentRoom->findInTimeline(eventId);
|
||||||
if (eventIt != m_currentRoom->historyEdge()) {
|
if (eventIt != m_currentRoom->historyEdge()) {
|
||||||
createEventObjects(static_cast<const RoomMessageEvent *>(&**eventIt));
|
if (const auto &event = dynamic_cast<const RoomMessageEvent *>(&**eventIt)) {
|
||||||
|
createEventObjects(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
refreshEventRoles(eventId, {ReactionRole, ShowReactionsRole, Qt::DisplayRole});
|
refreshEventRoles(eventId, {ReactionRole, ShowReactionsRole, Qt::DisplayRole});
|
||||||
});
|
});
|
||||||
@@ -266,7 +272,7 @@ int MessageEventModel::timelineBaseIndex() const
|
|||||||
return m_currentRoom ? int(m_currentRoom->pendingEvents().size()) : 0;
|
return m_currentRoom ? int(m_currentRoom->pendingEvents().size()) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageEventModel::refreshEventRoles(int row, const QVector<int> &roles)
|
void MessageEventModel::refreshEventRoles(int row, const QList<int> &roles)
|
||||||
{
|
{
|
||||||
const auto idx = index(row);
|
const auto idx = index(row);
|
||||||
Q_EMIT dataChanged(idx, idx, roles);
|
Q_EMIT dataChanged(idx, idx, roles);
|
||||||
@@ -310,7 +316,7 @@ void MessageEventModel::moveReadMarker(const QString &toEventId)
|
|||||||
endMoveRows();
|
endMoveRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
int MessageEventModel::refreshEventRoles(const QString &id, const QVector<int> &roles)
|
int MessageEventModel::refreshEventRoles(const QString &id, const QList<int> &roles)
|
||||||
{
|
{
|
||||||
// On 64-bit platforms, difference_type for std containers is long long
|
// On 64-bit platforms, difference_type for std containers is long long
|
||||||
// but Qt uses int throughout its interfaces; hence casting to int below.
|
// but Qt uses int throughout its interfaces; hence casting to int below.
|
||||||
@@ -586,6 +592,14 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
|||||||
return eventHandler.getReplyMediaInfo();
|
return eventHandler.getReplyMediaInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (role == IsThreadedRole) {
|
||||||
|
return eventHandler.isThreaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role == ThreadRootRole) {
|
||||||
|
return eventHandler.threadRoot();
|
||||||
|
}
|
||||||
|
|
||||||
if (role == ShowAuthorRole) {
|
if (role == ShowAuthorRole) {
|
||||||
for (auto r = row + 1; r < rowCount(); ++r) {
|
for (auto r = row + 1; r < rowCount(); ++r) {
|
||||||
auto i = index(r);
|
auto i = index(r);
|
||||||
@@ -694,10 +708,6 @@ int MessageEventModel::eventIdToRow(const QString &eventID) const
|
|||||||
|
|
||||||
void MessageEventModel::createEventObjects(const Quotient::RoomMessageEvent *event)
|
void MessageEventModel::createEventObjects(const Quotient::RoomMessageEvent *event)
|
||||||
{
|
{
|
||||||
if (event == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto eventId = event->id();
|
auto eventId = event->id();
|
||||||
|
|
||||||
EventHandler eventHandler;
|
EventHandler eventHandler;
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ public:
|
|||||||
ReplyDisplayRole, /**< The body of the message that was replied to. */
|
ReplyDisplayRole, /**< The body of the message that was replied to. */
|
||||||
ReplyMediaInfoRole, /**< The media info 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. */
|
ShowAuthorRole, /**< Whether the author's name should be shown. */
|
||||||
ShowSectionRole, /**< Whether the section header should be shown. */
|
ShowSectionRole, /**< Whether the section header should be shown. */
|
||||||
|
|
||||||
@@ -137,8 +140,8 @@ private:
|
|||||||
void fetchMore(const QModelIndex &parent) override;
|
void fetchMore(const QModelIndex &parent) override;
|
||||||
|
|
||||||
void refreshLastUserEvents(int baseTimelineRow);
|
void refreshLastUserEvents(int baseTimelineRow);
|
||||||
void refreshEventRoles(int row, const QVector<int> &roles = {});
|
void refreshEventRoles(int row, const QList<int> &roles = {});
|
||||||
int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {});
|
int refreshEventRoles(const QString &eventId, const QList<int> &roles = {});
|
||||||
void moveReadMarker(const QString &toEventId);
|
void moveReadMarker(const QString &toEventId);
|
||||||
|
|
||||||
void createEventObjects(const Quotient::RoomMessageEvent *event);
|
void createEventObjects(const Quotient::RoomMessageEvent *event);
|
||||||
|
|||||||
@@ -124,6 +124,20 @@ void PublicRoomListModel::setKeyword(const QString &value)
|
|||||||
Q_EMIT hasMoreChanged();
|
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)
|
void PublicRoomListModel::next(int count)
|
||||||
{
|
{
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
@@ -136,7 +150,11 @@ void PublicRoomListModel::next(int count)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
job = m_connection->callApi<QueryPublicRoomsJob>(m_server, count, nextBatch, QueryPublicRoomsJob::Filter{m_keyword, {}});
|
QStringList roomTypes;
|
||||||
|
if (m_showOnlySpaces) {
|
||||||
|
roomTypes += QLatin1String("m.space");
|
||||||
|
}
|
||||||
|
job = m_connection->callApi<QueryPublicRoomsJob>(m_server, count, nextBatch, QueryPublicRoomsJob::Filter{m_keyword, roomTypes});
|
||||||
Q_EMIT loadingChanged();
|
Q_EMIT loadingChanged();
|
||||||
|
|
||||||
connect(job, &BaseJob::finished, this, [this] {
|
connect(job, &BaseJob::finished, this, [this] {
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ class PublicRoomListModel : public QAbstractListModel
|
|||||||
*/
|
*/
|
||||||
Q_PROPERTY(QString keyword READ keyword WRITE setKeyword NOTIFY keywordChanged)
|
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.
|
* @brief Whether the model has more items to load.
|
||||||
*/
|
*/
|
||||||
@@ -103,6 +108,9 @@ public:
|
|||||||
[[nodiscard]] QString keyword() const;
|
[[nodiscard]] QString keyword() const;
|
||||||
void setKeyword(const QString &value);
|
void setKeyword(const QString &value);
|
||||||
|
|
||||||
|
[[nodiscard]] bool showOnlySpaces() const;
|
||||||
|
void setShowOnlySpaces(bool showOnlySpaces);
|
||||||
|
|
||||||
[[nodiscard]] bool hasMore() const;
|
[[nodiscard]] bool hasMore() const;
|
||||||
|
|
||||||
[[nodiscard]] bool loading() const;
|
[[nodiscard]] bool loading() const;
|
||||||
@@ -118,12 +126,13 @@ private:
|
|||||||
Quotient::Connection *m_connection = nullptr;
|
Quotient::Connection *m_connection = nullptr;
|
||||||
QString m_server;
|
QString m_server;
|
||||||
QString m_keyword;
|
QString m_keyword;
|
||||||
|
bool m_showOnlySpaces = false;
|
||||||
|
|
||||||
bool attempted = false;
|
bool attempted = false;
|
||||||
bool m_loading = false;
|
bool m_loading = false;
|
||||||
QString nextBatch;
|
QString nextBatch;
|
||||||
|
|
||||||
QVector<Quotient::PublicRoomsChunk> rooms;
|
QList<Quotient::PublicRoomsChunk> rooms;
|
||||||
|
|
||||||
Quotient::QueryPublicRoomsJob *job = nullptr;
|
Quotient::QueryPublicRoomsJob *job = nullptr;
|
||||||
|
|
||||||
@@ -131,6 +140,7 @@ Q_SIGNALS:
|
|||||||
void connectionChanged();
|
void connectionChanged();
|
||||||
void serverChanged();
|
void serverChanged();
|
||||||
void keywordChanged();
|
void keywordChanged();
|
||||||
|
void showOnlySpacesChanged();
|
||||||
void hasMoreChanged();
|
void hasMoreChanged();
|
||||||
void loadingChanged();
|
void loadingChanged();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -66,19 +66,6 @@ PushRuleModel::PushRuleModel(QObject *parent)
|
|||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
m_defaultKeywordAction = static_cast<PushNotificationAction::Action>(NeoChatConfig::self()->keywordPushRuleDefault());
|
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)
|
void PushRuleModel::updateNotificationRules(const QString &type)
|
||||||
@@ -87,7 +74,7 @@ void PushRuleModel::updateNotificationRules(const QString &type)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QJsonObject ruleDataJson = Controller::instance().activeConnection()->accountDataJson(QStringLiteral("m.push_rules"));
|
const QJsonObject ruleDataJson = m_connection->accountDataJson(QStringLiteral("m.push_rules"));
|
||||||
const Quotient::PushRuleset ruleData = Quotient::fromJson<Quotient::PushRuleset>(ruleDataJson[QStringLiteral("global")].toObject());
|
const Quotient::PushRuleset ruleData = Quotient::fromJson<Quotient::PushRuleset>(ruleDataJson[QStringLiteral("global")].toObject());
|
||||||
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
@@ -106,7 +93,7 @@ void PushRuleModel::updateNotificationRules(const QString &type)
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PushRuleModel::setRules(QVector<Quotient::PushRule> rules, PushNotificationKind::Kind kind)
|
void PushRuleModel::setRules(QList<Quotient::PushRule> rules, PushNotificationKind::Kind kind)
|
||||||
{
|
{
|
||||||
for (const auto &rule : rules) {
|
for (const auto &rule : rules) {
|
||||||
QString roomId;
|
QString roomId;
|
||||||
@@ -156,8 +143,7 @@ PushNotificationSection::Section PushRuleModel::getSection(Quotient::PushRule ru
|
|||||||
*
|
*
|
||||||
* Rooms that the user hasn't joined shouldn't have a rule.
|
* Rooms that the user hasn't joined shouldn't have a rule.
|
||||||
*/
|
*/
|
||||||
auto connection = Controller::instance().activeConnection();
|
if (m_connection->room(ruleId) != nullptr) {
|
||||||
if (connection->room(ruleId) != nullptr) {
|
|
||||||
return PushNotificationSection::Undefined;
|
return PushNotificationSection::Undefined;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -171,7 +157,7 @@ PushNotificationSection::Section PushRuleModel::getSection(Quotient::PushRule ru
|
|||||||
if (!testUserId.startsWith(u'@')) {
|
if (!testUserId.startsWith(u'@')) {
|
||||||
testUserId.prepend(u'@');
|
testUserId.prepend(u'@');
|
||||||
}
|
}
|
||||||
if (testUserId.startsWith(u'@') && !Quotient::serverPart(testUserId).isEmpty() && connection->user(testUserId) != nullptr) {
|
if (testUserId.startsWith(u'@') && !Quotient::serverPart(testUserId).isEmpty() && m_connection->user(testUserId) != nullptr) {
|
||||||
return PushNotificationSection::Undefined;
|
return PushNotificationSection::Undefined;
|
||||||
}
|
}
|
||||||
// If the rule has push conditions and one is a room ID it is a room only keyword.
|
// If the rule has push conditions and one is a room ID it is a room only keyword.
|
||||||
@@ -307,8 +293,8 @@ void PushRuleModel::setPushRuleAction(const QString &id, PushNotificationAction:
|
|||||||
void PushRuleModel::addKeyword(const QString &keyword, const QString &roomId)
|
void PushRuleModel::addKeyword(const QString &keyword, const QString &roomId)
|
||||||
{
|
{
|
||||||
PushNotificationKind::Kind kind = PushNotificationKind::Content;
|
PushNotificationKind::Kind kind = PushNotificationKind::Content;
|
||||||
const QVector<QVariant> actions = actionToVariant(m_defaultKeywordAction);
|
const QList<QVariant> actions = actionToVariant(m_defaultKeywordAction);
|
||||||
QVector<Quotient::PushCondition> pushConditions;
|
QList<Quotient::PushCondition> pushConditions;
|
||||||
if (!roomId.isEmpty()) {
|
if (!roomId.isEmpty()) {
|
||||||
kind = PushNotificationKind::Override;
|
kind = PushNotificationKind::Override;
|
||||||
|
|
||||||
@@ -325,14 +311,14 @@ void PushRuleModel::addKeyword(const QString &keyword, const QString &roomId)
|
|||||||
pushConditions.append(keywordCondition);
|
pushConditions.append(keywordCondition);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto job = Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleJob>(QLatin1String("global"),
|
auto job = m_connection->callApi<Quotient::SetPushRuleJob>(QLatin1String("global"),
|
||||||
PushNotificationKind::kindString(kind),
|
PushNotificationKind::kindString(kind),
|
||||||
keyword,
|
keyword,
|
||||||
actions,
|
actions,
|
||||||
QString(),
|
QString(),
|
||||||
QString(),
|
QString(),
|
||||||
pushConditions,
|
pushConditions,
|
||||||
roomId.isEmpty() ? keyword : QString());
|
roomId.isEmpty() ? keyword : QString());
|
||||||
connect(job, &Quotient::BaseJob::failure, this, [job, keyword]() {
|
connect(job, &Quotient::BaseJob::failure, this, [job, keyword]() {
|
||||||
qWarning() << QLatin1String("Unable to set push rule for keyword %1: ").arg(keyword) << job->errorString();
|
qWarning() << QLatin1String("Unable to set push rule for keyword %1: ").arg(keyword) << job->errorString();
|
||||||
});
|
});
|
||||||
@@ -351,7 +337,7 @@ void PushRuleModel::removeKeyword(const QString &keyword)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto kind = PushNotificationKind::kindString(m_rules[index].kind);
|
auto kind = PushNotificationKind::kindString(m_rules[index].kind);
|
||||||
auto job = Controller::instance().activeConnection()->callApi<Quotient::DeletePushRuleJob>(QStringLiteral("global"), kind, m_rules[index].id);
|
auto job = m_connection->callApi<Quotient::DeletePushRuleJob>(QStringLiteral("global"), kind, m_rules[index].id);
|
||||||
connect(job, &Quotient::BaseJob::failure, this, [this, job, index]() {
|
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();
|
qWarning() << QLatin1String("Unable to remove push rule for keyword %1: ").arg(m_rules[index].id) << job->errorString();
|
||||||
});
|
});
|
||||||
@@ -359,27 +345,27 @@ void PushRuleModel::removeKeyword(const QString &keyword)
|
|||||||
|
|
||||||
void PushRuleModel::setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled)
|
void PushRuleModel::setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled)
|
||||||
{
|
{
|
||||||
auto job = Controller::instance().activeConnection()->callApi<Quotient::IsPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId);
|
auto job = m_connection->callApi<Quotient::IsPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId);
|
||||||
connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled]() {
|
connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled, this]() {
|
||||||
if (job->enabled() != enabled) {
|
if (job->enabled() != enabled) {
|
||||||
Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId, enabled);
|
m_connection->callApi<Quotient::SetPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId, enabled);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void PushRuleModel::setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action)
|
void PushRuleModel::setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action)
|
||||||
{
|
{
|
||||||
QVector<QVariant> actions;
|
QList<QVariant> actions;
|
||||||
if (ruleId == QStringLiteral(".m.rule.call")) {
|
if (ruleId == QStringLiteral(".m.rule.call")) {
|
||||||
actions = actionToVariant(action, QStringLiteral("ring"));
|
actions = actionToVariant(action, QStringLiteral("ring"));
|
||||||
} else {
|
} else {
|
||||||
actions = actionToVariant(action);
|
actions = actionToVariant(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller::instance().activeConnection()->callApi<Quotient::SetPushRuleActionsJob>(QStringLiteral("global"), kind, ruleId, actions);
|
m_connection->callApi<Quotient::SetPushRuleActionsJob>(QStringLiteral("global"), kind, ruleId, actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
PushNotificationAction::Action PushRuleModel::variantToAction(const QVector<QVariant> &actions, bool enabled)
|
PushNotificationAction::Action PushRuleModel::variantToAction(const QList<QVariant> &actions, bool enabled)
|
||||||
{
|
{
|
||||||
bool notify = false;
|
bool notify = false;
|
||||||
bool isNoisy = false;
|
bool isNoisy = false;
|
||||||
@@ -422,16 +408,16 @@ PushNotificationAction::Action PushRuleModel::variantToAction(const QVector<QVar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QVariant> PushRuleModel::actionToVariant(PushNotificationAction::Action action, const QString &sound)
|
QList<QVariant> PushRuleModel::actionToVariant(PushNotificationAction::Action action, const QString &sound)
|
||||||
{
|
{
|
||||||
// The caller should never try to set the state to unknown.
|
// 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.
|
// 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) {
|
if (action == PushNotificationAction::Unknown) {
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
return QVector<QVariant>();
|
return QList<QVariant>();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QVariant> actions;
|
QList<QVariant> actions;
|
||||||
|
|
||||||
if (action != PushNotificationAction::Off) {
|
if (action != PushNotificationAction::Off) {
|
||||||
actions.append(QStringLiteral("notify"));
|
actions.append(QStringLiteral("notify"));
|
||||||
@@ -453,4 +439,23 @@ QVector<QVariant> PushRuleModel::actionToVariant(PushNotificationAction::Action
|
|||||||
return actions;
|
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"
|
#include "moc_pushrulemodel.cpp"
|
||||||
|
|||||||
@@ -157,6 +157,8 @@ class PushRuleModel : public QAbstractListModel
|
|||||||
*/
|
*/
|
||||||
Q_PROPERTY(bool globalNotificationsSet READ globalNotificationsSet NOTIFY globalNotificationsSetChanged)
|
Q_PROPERTY(bool globalNotificationsSet READ globalNotificationsSet NOTIFY globalNotificationsSetChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Rule {
|
struct Rule {
|
||||||
QString id;
|
QString id;
|
||||||
@@ -225,27 +227,31 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE void removeKeyword(const QString &keyword);
|
Q_INVOKABLE void removeKeyword(const QString &keyword);
|
||||||
|
|
||||||
|
void setConnection(NeoChatConnection *connection);
|
||||||
|
NeoChatConnection *connection() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void defaultStateChanged();
|
void defaultStateChanged();
|
||||||
void globalNotificationsEnabledChanged();
|
void globalNotificationsEnabledChanged();
|
||||||
void globalNotificationsSetChanged();
|
void globalNotificationsSetChanged();
|
||||||
|
void connectionChanged();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void controllerConnectionChanged();
|
|
||||||
void updateNotificationRules(const QString &type);
|
void updateNotificationRules(const QString &type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PushNotificationAction::Action m_defaultKeywordAction;
|
PushNotificationAction::Action m_defaultKeywordAction;
|
||||||
QList<Rule> m_rules;
|
QList<Rule> m_rules;
|
||||||
|
NeoChatConnection *m_connection;
|
||||||
|
|
||||||
void setRules(QVector<Quotient::PushRule> rules, PushNotificationKind::Kind kind);
|
void setRules(QList<Quotient::PushRule> rules, PushNotificationKind::Kind kind);
|
||||||
|
|
||||||
int getRuleIndex(const QString &ruleId) const;
|
int getRuleIndex(const QString &ruleId) const;
|
||||||
PushNotificationSection::Section getSection(Quotient::PushRule rule);
|
PushNotificationSection::Section getSection(Quotient::PushRule rule);
|
||||||
|
|
||||||
void setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled);
|
void setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled);
|
||||||
void setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action);
|
void setNotificationRuleActions(const QString &kind, const QString &ruleId, PushNotificationAction::Action action);
|
||||||
PushNotificationAction::Action variantToAction(const QVector<QVariant> &actions, bool enabled);
|
PushNotificationAction::Action variantToAction(const QList<QVariant> &actions, bool enabled);
|
||||||
QVector<QVariant> actionToVariant(PushNotificationAction::Action action, const QString &sound = QStringLiteral("default"));
|
QList<QVariant> actionToVariant(PushNotificationAction::Action action, const QString &sound = QStringLiteral("default"));
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(PushRuleModel *)
|
Q_DECLARE_METATYPE(PushRuleModel *)
|
||||||
|
|||||||
@@ -368,11 +368,14 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
|
|||||||
if (role == IsChildSpaceRole) {
|
if (role == IsChildSpaceRole) {
|
||||||
return SpaceHierarchyCache::instance().isChildSpace(room->id());
|
return SpaceHierarchyCache::instance().isChildSpace(room->id());
|
||||||
}
|
}
|
||||||
|
if (role == ReplacementIdRole) {
|
||||||
|
return room->successorId();
|
||||||
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomListModel::refresh(NeoChatRoom *room, const QVector<int> &roles)
|
void RoomListModel::refresh(NeoChatRoom *room, const QList<int> &roles)
|
||||||
{
|
{
|
||||||
const auto it = std::find(m_rooms.begin(), m_rooms.end(), room);
|
const auto it = std::find(m_rooms.begin(), m_rooms.end(), room);
|
||||||
if (it == m_rooms.end()) {
|
if (it == m_rooms.end()) {
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ public:
|
|||||||
RoomIdRole, /**< The room matrix ID. */
|
RoomIdRole, /**< The room matrix ID. */
|
||||||
IsSpaceRole, /**< Whether the room is a space. */
|
IsSpaceRole, /**< Whether the room is a space. */
|
||||||
IsChildSpaceRole, /**< Whether this space is a child of a different 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)
|
Q_ENUM(EventRoles)
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ private Q_SLOTS:
|
|||||||
void doAddRoom(Quotient::Room *room);
|
void doAddRoom(Quotient::Room *room);
|
||||||
void updateRoom(Quotient::Room *room, Quotient::Room *prev);
|
void updateRoom(Quotient::Room *room, Quotient::Room *prev);
|
||||||
void deleteRoom(Quotient::Room *room);
|
void deleteRoom(Quotient::Room *room);
|
||||||
void refresh(NeoChatRoom *room, const QVector<int> &roles = {});
|
void refresh(NeoChatRoom *room, const QList<int> &roles = {});
|
||||||
void refreshNotificationCount();
|
void refreshNotificationCount();
|
||||||
void refreshHighlightCount();
|
void refreshHighlightCount();
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,15 @@
|
|||||||
|
|
||||||
#include <KConfig>
|
#include <KConfig>
|
||||||
#include <KConfigGroup>
|
#include <KConfigGroup>
|
||||||
|
#include <KSharedConfig>
|
||||||
|
|
||||||
ServerListModel::ServerListModel(QObject *parent)
|
ServerListModel::ServerListModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
|
const auto stateConfig = KSharedConfig::openStateConfig();
|
||||||
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
|
const KConfigGroup serverGroup = stateConfig->group(QStringLiteral("Servers"));
|
||||||
|
|
||||||
QString domain = Controller::instance().activeConnection()->domain();
|
QString domain = m_connection->domain();
|
||||||
|
|
||||||
// Add the user's homeserver
|
// Add the user's homeserver
|
||||||
m_servers.append(Server{
|
m_servers.append(Server{
|
||||||
@@ -91,15 +92,15 @@ int ServerListModel::rowCount(const QModelIndex &parent) const
|
|||||||
|
|
||||||
void ServerListModel::checkServer(const QString &url)
|
void ServerListModel::checkServer(const QString &url)
|
||||||
{
|
{
|
||||||
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
|
const auto stateConfig = KSharedConfig::openStateConfig();
|
||||||
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
|
const KConfigGroup serverGroup = stateConfig->group(QStringLiteral("Servers"));
|
||||||
|
|
||||||
if (!serverGroup.hasKey(url)) {
|
if (!serverGroup.hasKey(url)) {
|
||||||
if (Quotient::isJobPending(m_checkServerJob)) {
|
if (Quotient::isJobPending(m_checkServerJob)) {
|
||||||
m_checkServerJob->abandon();
|
m_checkServerJob->abandon();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_checkServerJob = Controller::instance().activeConnection()->callApi<Quotient::QueryPublicRoomsJob>(url, 1);
|
m_checkServerJob = m_connection->callApi<Quotient::QueryPublicRoomsJob>(url, 1);
|
||||||
connect(m_checkServerJob, &Quotient::BaseJob::success, this, [this, url] {
|
connect(m_checkServerJob, &Quotient::BaseJob::success, this, [this, url] {
|
||||||
Q_EMIT serverCheckComplete(url, true);
|
Q_EMIT serverCheckComplete(url, true);
|
||||||
});
|
});
|
||||||
@@ -108,8 +109,8 @@ void ServerListModel::checkServer(const QString &url)
|
|||||||
|
|
||||||
void ServerListModel::addServer(const QString &url)
|
void ServerListModel::addServer(const QString &url)
|
||||||
{
|
{
|
||||||
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
|
const auto stateConfig = KSharedConfig::openStateConfig();
|
||||||
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
|
KConfigGroup serverGroup = stateConfig->group(QStringLiteral("Servers"));
|
||||||
|
|
||||||
if (!serverGroup.hasKey(url)) {
|
if (!serverGroup.hasKey(url)) {
|
||||||
Server newServer = Server{
|
Server newServer = Server{
|
||||||
@@ -125,17 +126,21 @@ void ServerListModel::addServer(const QString &url)
|
|||||||
}
|
}
|
||||||
|
|
||||||
serverGroup.writeEntry(url, url);
|
serverGroup.writeEntry(url, url);
|
||||||
|
stateConfig->sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerListModel::removeServerAtIndex(int row)
|
void ServerListModel::removeServerAtIndex(int row)
|
||||||
{
|
{
|
||||||
KConfig dataResource(QStringLiteral("data"), KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
|
const auto stateConfig = KSharedConfig::openStateConfig();
|
||||||
KConfigGroup serverGroup(&dataResource, QStringLiteral("Servers"));
|
KConfigGroup serverGroup = stateConfig->group(QStringLiteral("Servers"));
|
||||||
|
|
||||||
serverGroup.deleteEntry(data(index(row), UrlRole).toString());
|
serverGroup.deleteEntry(data(index(row), UrlRole).toString());
|
||||||
|
|
||||||
beginRemoveRows(QModelIndex(), row, row);
|
beginRemoveRows(QModelIndex(), row, row);
|
||||||
m_servers.removeAt(row);
|
m_servers.removeAt(row);
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
|
|
||||||
|
stateConfig->sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> ServerListModel::roleNames() const
|
QHash<int, QByteArray> ServerListModel::roleNames() const
|
||||||
@@ -148,4 +153,18 @@ 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"
|
#include "moc_serverlistmodel.cpp"
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
|
class NeoChatConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class ServerListModel
|
* @class ServerListModel
|
||||||
*
|
*
|
||||||
@@ -27,6 +29,8 @@ class ServerListModel : public QAbstractListModel
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
|
|
||||||
|
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Define the data required to represent a server.
|
* @brief Define the data required to represent a server.
|
||||||
@@ -96,10 +100,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE void removeServerAtIndex(int index);
|
Q_INVOKABLE void removeServerAtIndex(int index);
|
||||||
|
|
||||||
|
NeoChatConnection *connection() const;
|
||||||
|
void setConnection(NeoChatConnection *connection);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void serverCheckComplete(QString url, bool valid);
|
void serverCheckComplete(QString url, bool valid);
|
||||||
|
void connectionChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<Server> m_servers;
|
QList<Server> m_servers;
|
||||||
QPointer<Quotient::QueryPublicRoomsJob> m_checkServerJob = nullptr;
|
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