Compare commits
72 Commits
work/test-
...
v25.04.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11ebe5316f | ||
|
|
9b79580c29 | ||
|
|
5327ece769 | ||
|
|
58658d1aa2 | ||
|
|
611fb87376 | ||
|
|
823700eb8e | ||
|
|
fbefaa0638 | ||
|
|
85262c70c3 | ||
|
|
c88e843a34 | ||
|
|
702d17bc4d | ||
|
|
e015cbea07 | ||
|
|
ccf3976a6b | ||
|
|
bfa1f9f053 | ||
|
|
9c4dce53b2 | ||
|
|
baaea57cd9 | ||
|
|
61bb1c5db1 | ||
|
|
9b8c7714d4 | ||
|
|
a020db2e04 | ||
|
|
457b4ee3be | ||
|
|
0237bf048b | ||
|
|
f6183a4689 | ||
|
|
2a2d469d7d | ||
|
|
2212dc4d5e | ||
|
|
6e179562f0 | ||
|
|
b75f8b527c | ||
|
|
0a7fccaa5c | ||
|
|
dd3488efbe | ||
|
|
617eb25bbb | ||
|
|
7cf20a473c | ||
|
|
749b59e5eb | ||
|
|
c8170f5a96 | ||
|
|
142adbeb00 | ||
|
|
a1c213dc46 | ||
|
|
f642b1488a | ||
|
|
3e683eac77 | ||
|
|
299d8e9c40 | ||
|
|
45f9aeb5bf | ||
|
|
6961442090 | ||
|
|
f4b31838bc | ||
|
|
8e3ffd3e9d | ||
|
|
02cfb0df9c | ||
|
|
c95778b3ac | ||
|
|
8e66f635fd | ||
|
|
355b5a33b7 | ||
|
|
e40d8230c0 | ||
|
|
a76d4496da | ||
|
|
4ad1a628b6 | ||
|
|
87ea0ef5b2 | ||
|
|
7ed43044ce | ||
|
|
074e5d4c5a | ||
|
|
12ce1e460e | ||
|
|
74a6cd28eb | ||
|
|
53307f9358 | ||
|
|
c683df2b40 | ||
|
|
3b1e19c740 | ||
|
|
4a5c4559bf | ||
|
|
7d2dc0f9ac | ||
|
|
f5a7fb0d13 | ||
|
|
3e09099958 | ||
|
|
4474efd03f | ||
|
|
8fe4cf3f89 | ||
|
|
e25060c12d | ||
|
|
c56ec01637 | ||
|
|
5e07a07f38 | ||
|
|
dcc184a45f | ||
|
|
790ab54d0f | ||
|
|
606f8a1c99 | ||
|
|
46c706e364 | ||
|
|
32bea56a6d | ||
|
|
661cf22667 | ||
|
|
ad1254fb71 | ||
|
|
7514a8a6f7 |
@@ -2,5 +2,7 @@
|
|||||||
; SPDX-License-Identifier: CC0-1.0
|
; SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
[BlueprintSettings]
|
[BlueprintSettings]
|
||||||
|
kde/frameworks/extra-cmake-modules.version=master
|
||||||
|
kde/unreleased/kirigami-addons.version=master
|
||||||
kde/applications/neochat.packageAppx=True
|
kde/applications/neochat.packageAppx=True
|
||||||
libs/qt.qtMajorVersion=6
|
libs/qt.qtMajorVersion=6
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"id": "org.kde.neochat",
|
"id": "org.kde.neochat",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"runtime": "org.kde.Platform",
|
"runtime": "org.kde.Platform",
|
||||||
"runtime-version": "6.9",
|
"runtime-version": "6.8",
|
||||||
"sdk": "org.kde.Sdk",
|
"sdk": "org.kde.Sdk",
|
||||||
"command": "neochat",
|
"command": "neochat",
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -150,19 +150,22 @@
|
|||||||
"builddir": true
|
"builddir": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "kunifiedpush",
|
"name": "qcoro",
|
||||||
"buildsystem": "cmake-ninja",
|
"buildsystem": "cmake-ninja",
|
||||||
"builddir": true,
|
"config-opts": [
|
||||||
|
"-DQCORO_BUILD_EXAMPLES=OFF",
|
||||||
|
"-DBUILD_TESTING=OFF"
|
||||||
|
],
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://download.kde.org/stable/kunifiedpush/kunifiedpush-1.0.0.tar.xz",
|
"url": "https://github.com/danvratil/qcoro/archive/refs/tags/v0.11.0.tar.gz",
|
||||||
"sha256": "2ddeba21306d0307114ec50a2c38159ec62359f9fc6cdd58da30a369fbd550cf",
|
"sha256": "9942c5b4c533192f6c5954dc6d10178b3829075e6a621b67df73f0a4b74d8297",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "anitya",
|
"type": "anitya",
|
||||||
"project-id": 375055,
|
"project-id": 236236,
|
||||||
"stable-only": true,
|
"stable-only": true,
|
||||||
"url-template": "https://download.kde.org/stable/kunifiedpush/kunifiedpush-$version.tar.xz"
|
"url-template": "https://github.com/danvratil/qcoro/archive/refs/tags/v$version.tar.gz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -3,20 +3,19 @@
|
|||||||
|
|
||||||
include:
|
include:
|
||||||
- project: sysadmin/ci-utilities
|
- project: sysadmin/ci-utilities
|
||||||
ref: work/switch-vm-ci
|
|
||||||
file:
|
file:
|
||||||
#- /gitlab-templates/reuse-lint.yml
|
- /gitlab-templates/reuse-lint.yml
|
||||||
#- /gitlab-templates/json-validation.yml
|
- /gitlab-templates/json-validation.yml
|
||||||
#- /gitlab-templates/xml-lint.yml
|
- /gitlab-templates/xml-lint.yml
|
||||||
#- /gitlab-templates/yaml-lint.yml
|
- /gitlab-templates/yaml-lint.yml
|
||||||
#- /gitlab-templates/android-qt6.yml
|
- /gitlab-templates/android-qt6.yml
|
||||||
- /gitlab-templates/linux-qt6.yml
|
- /gitlab-templates/linux-qt6.yml
|
||||||
- /gitlab-templates/linux-qt6-next.yml
|
# - /gitlab-templates/linux-qt6-next.yml
|
||||||
#- /gitlab-templates/windows-qt6.yml
|
- /gitlab-templates/windows-qt6.yml
|
||||||
#- /gitlab-templates/freebsd-qt6.yml
|
# - /gitlab-templates/freebsd-qt6.yml
|
||||||
- /gitlab-templates/flatpak.yml
|
- /gitlab-templates/flatpak.yml
|
||||||
- /gitlab-templates/snap-snapcraft-lxd.yml
|
- /gitlab-templates/snap-snapcraft-lxd.yml
|
||||||
#- /gitlab-templates/craft-android-qt6-apks.yml
|
- /gitlab-templates/craft-android-qt6-apks.yml
|
||||||
#- /gitlab-templates/craft-appimage-qt6.yml
|
- /gitlab-templates/craft-appimage-qt6.yml
|
||||||
- /gitlab-templates/craft-windows-x86-64-qt6.yml
|
- /gitlab-templates/craft-windows-x86-64-qt6.yml
|
||||||
- /gitlab-templates/craft-windows-appx-qt6.yml
|
- /gitlab-templates/craft-windows-appx-qt6.yml
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ Dependencies:
|
|||||||
'require':
|
'require':
|
||||||
'frameworks/kdbusaddons': '@latest-kf6'
|
'frameworks/kdbusaddons': '@latest-kf6'
|
||||||
'frameworks/purpose': '@latest-kf6'
|
'frameworks/purpose': '@latest-kf6'
|
||||||
'libraries/kunifiedpush': '@latest-kf6'
|
|
||||||
|
|
||||||
- 'on': ['Linux']
|
- 'on': ['Linux']
|
||||||
'require':
|
'require':
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ 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 "25")
|
set(RELEASE_SERVICE_VERSION_MAJOR "25")
|
||||||
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
set(RELEASE_SERVICE_VERSION_MINOR "04")
|
||||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
set(RELEASE_SERVICE_VERSION_MICRO "2")
|
||||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||||
|
|
||||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||||
|
|
||||||
set(KF_MIN_VERSION "6.12")
|
set(KF_MIN_VERSION "6.6")
|
||||||
set(QT_MIN_VERSION "6.5")
|
set(QT_MIN_VERSION "6.5")
|
||||||
|
|
||||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||||
@@ -56,7 +56,7 @@ ecm_setup_version(${PROJECT_VERSION}
|
|||||||
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
|
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Core Quick Gui QuickControls2 Multimedia Svg TextToSpeech WebView)
|
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Core Quick Gui QuickControls2 Multimedia Svg WebView)
|
||||||
set_package_properties(Qt6 PROPERTIES
|
set_package_properties(Qt6 PROPERTIES
|
||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
PURPOSE "Basic application components"
|
PURPOSE "Basic application components"
|
||||||
@@ -75,7 +75,7 @@ set_package_properties(KF6Kirigami PROPERTIES
|
|||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
PURPOSE "Kirigami application UI framework"
|
PURPOSE "Kirigami application UI framework"
|
||||||
)
|
)
|
||||||
find_package(KF6KirigamiAddons 1.6.0 REQUIRED)
|
find_package(KF6KirigamiAddons 0.7.2 REQUIRED)
|
||||||
|
|
||||||
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE)
|
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE)
|
||||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Purpose)
|
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Purpose)
|
||||||
@@ -107,7 +107,7 @@ if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU)
|
|||||||
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
|
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(QuotientQt6 0.9.1)
|
find_package(QuotientQt6 0.9)
|
||||||
set_package_properties(QuotientQt6 PROPERTIES
|
set_package_properties(QuotientQt6 PROPERTIES
|
||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
DESCRIPTION "Qt wrapper around Matrix API"
|
DESCRIPTION "Qt wrapper around Matrix API"
|
||||||
@@ -147,24 +147,16 @@ set_package_properties(KF6DocTools PROPERTIES DESCRIPTION
|
|||||||
TYPE OPTIONAL
|
TYPE OPTIONAL
|
||||||
)
|
)
|
||||||
|
|
||||||
option(WITH_UNIFIEDPUSH "Build with KUnifiedPush support" ON)
|
find_package(KUnifiedPush QUIET)
|
||||||
|
set_package_properties(KUnifiedPush PROPERTIES
|
||||||
if (ANDROID OR APPLE OR WIN32 OR HAIKU)
|
TYPE OPTIONAL
|
||||||
set(WITH_UNIFIEDPUSH OFF)
|
PURPOSE "Push notification support"
|
||||||
endif()
|
URL "https://invent.kde.org/libraries/kunifiedpush"
|
||||||
|
)
|
||||||
if (WITH_UNIFIEDPUSH)
|
|
||||||
find_package(KUnifiedPush)
|
|
||||||
set_package_properties(KUnifiedPush PROPERTIES
|
|
||||||
TYPE REQUIRED
|
|
||||||
PURPOSE "Push notification support"
|
|
||||||
URL "https://invent.kde.org/libraries/kunifiedpush"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
find_package(Sqlite3)
|
find_package(Sqlite3)
|
||||||
set(BUILD_TESTING FALSE)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/android/version.gradle.in ${CMAKE_BINARY_DIR}/version.gradle)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
ki18n_install(po)
|
ki18n_install(po)
|
||||||
@@ -179,9 +171,9 @@ add_definitions(-DQT_NO_FOREACH)
|
|||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
if (BUILD_TESTING)
|
if (BUILD_TESTING)
|
||||||
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test HttpServer)
|
find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test)
|
||||||
add_subdirectory(autotests)
|
add_subdirectory(autotests)
|
||||||
# add_subdirectory(appiumtests)
|
add_subdirectory(appiumtests)
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
add_subdirectory(memorytests)
|
add_subdirectory(memorytests)
|
||||||
endif()
|
endif()
|
||||||
@@ -192,7 +184,7 @@ if(KF6DocTools_FOUND)
|
|||||||
add_subdirectory(doc)
|
add_subdirectory(doc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||||
|
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES src/*.cpp src/*.h)
|
file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES src/*.cpp src/*.h)
|
||||||
|
|||||||
@@ -42,13 +42,13 @@ SPDX-FileCopyrightText = "2021 Carl Schwan <carlschwan@kde.org>"
|
|||||||
SPDX-License-Identifier = "BSD-2-Clause"
|
SPDX-License-Identifier = "BSD-2-Clause"
|
||||||
|
|
||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = "src/app/neochatconfig.kcfg"
|
path = "src/neochatconfig.kcfg"
|
||||||
precedence = "aggregate"
|
precedence = "aggregate"
|
||||||
SPDX-FileCopyrightText = "2020-2021 Carl Schwan <carlschwan@kde.org>, Tobias Fella <tobias.fella@kde.org>"
|
SPDX-FileCopyrightText = "2020-2021 Carl Schwan <carlschwan@kde.org>, Tobias Fella <tobias.fella@kde.org>"
|
||||||
SPDX-License-Identifier = "BSD-2-Clause"
|
SPDX-License-Identifier = "BSD-2-Clause"
|
||||||
|
|
||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = "src/app/neochat.notifyrc"
|
path = "src/neochat.notifyrc"
|
||||||
precedence = "aggregate"
|
precedence = "aggregate"
|
||||||
SPDX-FileCopyrightText = "2020 Tobias Fella <tobias.fella@kde.org>"
|
SPDX-FileCopyrightText = "2020 Tobias Fella <tobias.fella@kde.org>"
|
||||||
SPDX-License-Identifier = "BSD-2-Clause"
|
SPDX-License-Identifier = "BSD-2-Clause"
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ repositories {
|
|||||||
|
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply from: '../ecm-version.gradle'
|
apply from: '../version.gradle'
|
||||||
|
def timestamp = (int)(new Date().getTime()/1000)
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||||
@@ -78,9 +79,9 @@ android {
|
|||||||
targetSdkVersion qtTargetSdkVersion
|
targetSdkVersion qtTargetSdkVersion
|
||||||
applicationId "org.kde.neochat"
|
applicationId "org.kde.neochat"
|
||||||
namespace "org.kde.neochat"
|
namespace "org.kde.neochat"
|
||||||
versionCode ecmVersionCode
|
versionCode timestamp
|
||||||
versionName ecmVersionName
|
versionName projectVersionFull
|
||||||
manifestPlaceholders = [versionName: ecmVersionName, versionCode: ecmVersionCode]
|
manifestPlaceholders = [versionName: projectVersionFull, versionCode: timestamp]
|
||||||
}
|
}
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
|
|||||||
6
android/version.gradle.in
Normal file
6
android/version.gradle.in
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
ext {
|
||||||
|
projectVersionFull = "@NEOCHAT_VERSION@"
|
||||||
|
}
|
||||||
@@ -3,10 +3,6 @@
|
|||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
add_library(neochat_server STATIC server.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(neochat_server PUBLIC Qt::HttpServer QuotientQt6)
|
|
||||||
|
|
||||||
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" )
|
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" )
|
||||||
|
|
||||||
ecm_add_test(
|
ecm_add_test(
|
||||||
@@ -15,11 +11,13 @@ ecm_add_test(
|
|||||||
TEST_NAME neochatroomtest
|
TEST_NAME neochatroomtest
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_add_test(
|
if (NOT $ENV{KDE_CI})
|
||||||
texthandlertest.cpp
|
ecm_add_test(
|
||||||
LINK_LIBRARIES neochat Qt::Test
|
texthandlertest.cpp
|
||||||
TEST_NAME texthandlertest
|
LINK_LIBRARIES neochat Qt::Test
|
||||||
)
|
TEST_NAME texthandlertest
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
ecm_add_test(
|
ecm_add_test(
|
||||||
delegatesizehelpertest.cpp
|
delegatesizehelpertest.cpp
|
||||||
@@ -89,6 +87,6 @@ ecm_add_test(
|
|||||||
|
|
||||||
ecm_add_test(
|
ecm_add_test(
|
||||||
actionstest.cpp
|
actionstest.cpp
|
||||||
LINK_LIBRARIES neochat Qt::Test neochat_server
|
LINK_LIBRARIES neochat Qt::Test
|
||||||
TEST_NAME actionstest
|
TEST_NAME actionstest
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,11 +6,9 @@
|
|||||||
#include <QSignalSpy>
|
#include <QSignalSpy>
|
||||||
#include <QVariantList>
|
#include <QVariantList>
|
||||||
|
|
||||||
#include "accountmanager.h"
|
|
||||||
#include "chatbarcache.h"
|
#include "chatbarcache.h"
|
||||||
#include "models/actionsmodel.h"
|
#include "models/actionsmodel.h"
|
||||||
|
|
||||||
#include "server.h"
|
|
||||||
#include "testutils.h"
|
#include "testutils.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -23,12 +21,10 @@ class ActionsTest : public QObject
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Connection *connection = nullptr;
|
Connection *connection = nullptr;
|
||||||
NeoChatRoom *room = nullptr;
|
TestUtils::TestRoom *room = nullptr;
|
||||||
|
|
||||||
void expectMessage(const QString &actionName, const QString &args, MessageType::Type type, const QString &message);
|
void expectMessage(const QString &actionName, const QString &args, MessageType::Type type, const QString &message);
|
||||||
|
|
||||||
Server server;
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
void testActions();
|
void testActions();
|
||||||
@@ -38,23 +34,8 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
void ActionsTest::initTestCase()
|
void ActionsTest::initTestCase()
|
||||||
{
|
{
|
||||||
Connection::setRoomType<NeoChatRoom>();
|
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||||
server.start();
|
room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-min-sync.json"));
|
||||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
|
||||||
auto accountManager = new AccountManager(true);
|
|
||||||
QSignalSpy spy(accountManager, &AccountManager::connectionAdded);
|
|
||||||
connection = accountManager->accounts()->front();
|
|
||||||
auto roomId = server.createRoom(u"@user:localhost:1234"_s);
|
|
||||||
server.inviteUser(roomId, u"@invited:example.com"_s);
|
|
||||||
server.banUser(roomId, u"@banned:example.com"_s);
|
|
||||||
server.joinUser(roomId, u"@example:example.com"_s);
|
|
||||||
|
|
||||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
|
||||||
// We need to wait for two syncs, as the next one won't have the changes yet
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
|
|
||||||
QVERIFY(room);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActionsTest::testActions_data()
|
void ActionsTest::testActions_data()
|
||||||
@@ -109,7 +90,7 @@ static ActionsModel::Action findAction(const QString &name)
|
|||||||
void ActionsTest::expectMessage(const QString &actionName, const QString &args, MessageType::Type type, const QString &message)
|
void ActionsTest::expectMessage(const QString &actionName, const QString &args, MessageType::Type type, const QString &message)
|
||||||
{
|
{
|
||||||
auto action = findAction(actionName);
|
auto action = findAction(actionName);
|
||||||
QSignalSpy spy(room, &NeoChatRoom::showMessage);
|
QSignalSpy spy(room, &TestUtils::TestRoom::showMessage);
|
||||||
auto result = action.handle(args, room, nullptr);
|
auto result = action.handle(args, room, nullptr);
|
||||||
auto expected = QVariantList {type, message};
|
auto expected = QVariantList {type, message};
|
||||||
auto signal = spy.takeFirst();
|
auto signal = spy.takeFirst();
|
||||||
@@ -125,26 +106,14 @@ void ActionsTest::testInvite()
|
|||||||
QCOMPARE(room->memberState(u"@banned:example.com"_s), Membership::Ban);
|
QCOMPARE(room->memberState(u"@banned:example.com"_s), Membership::Ban);
|
||||||
expectMessage(u"invite"_s, connection->userId(), MessageType::Positive, u"You are already in this room."_s);
|
expectMessage(u"invite"_s, connection->userId(), MessageType::Positive, u"You are already in this room."_s);
|
||||||
QCOMPARE(room->memberState(connection->userId()), Membership::Join);
|
QCOMPARE(room->memberState(connection->userId()), Membership::Join);
|
||||||
expectMessage(u"invite"_s, u"@example:example.com"_s, MessageType::Information, u"@example:example.com is already in this room."_s);
|
expectMessage(u"invite"_s, u"@example:example.org"_s, MessageType::Information, u"@example:example.org is already in this room."_s);
|
||||||
QCOMPARE(room->memberState(u"@example:example.com"_s), Membership::Join);
|
QCOMPARE(room->memberState(u"@example:example.org"_s), Membership::Join);
|
||||||
|
|
||||||
QCOMPARE(room->memberState(u"@user:example.com"_s), Membership::Leave);
|
QCOMPARE(room->memberState(u"@user:example.com"_s), Membership::Leave);
|
||||||
expectMessage(u"invite"_s, u"@user:example.com"_s, MessageType::Positive, u"@user:example.com was invited into this room."_s);
|
expectMessage(u"invite"_s, u"@user:example.com"_s, MessageType::Positive, u"@user:example.com was invited into this room."_s);
|
||||||
|
|
||||||
QSignalSpy spy(room, &NeoChatRoom::changed);
|
//TODO mock server, wait for invite state to change
|
||||||
QVERIFY(spy.wait());
|
//TODO QCOMPARE(room->memberState(u"@user:example.com"_s), Membership::Invite);
|
||||||
|
|
||||||
auto tries = 0;
|
|
||||||
|
|
||||||
while (room->memberState(u"@user:example.com"_s) != Membership::Invite) {
|
|
||||||
QVERIFY(spy.wait());
|
|
||||||
tries += 1;
|
|
||||||
if (tries > 3) {
|
|
||||||
QVERIFY(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QCOMPARE(room->memberState(u"@user:example.com"_s), Membership::Invite);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(ActionsTest)
|
QTEST_MAIN(ActionsTest)
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDNTCCAh2gAwIBAgIUXbyWfTfcvVLrVB1qx36pW/7IkwMwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE
|
|
||||||
CgwTRGVmYXVsdCBDb21wYW55IEx0ZDAgFw0yNDEyMjQxNTAxMDNaGA8yNTcyMDcy
|
|
||||||
NDE1MDEwM1owQjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEc
|
|
||||||
MBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQAD
|
|
||||||
ggEPADCCAQoCggEBAKlxZ540TQ1uUDAR7ZJ9ue0PzcD2dPmblIIddyekvZS59V7X
|
|
||||||
drhamclXpHE2EelR87Sexst0BaHH/jmrHwxCtwbeXHZ8ueJHkGHJ5DLZCCiwfG+Q
|
|
||||||
gml7wlSXxXz37vie2tdlZh2yJSM8yvLAYceHb2zOskaGvul7ZITIS0JrPc3o6VZk
|
|
||||||
+MYGkYtA2JfUsv3jH4oQbxOf7RXqhWNAXbB+3hlwRBwMIdyoBNK6YS9QSrTeS9jj
|
|
||||||
UqgO5QmaQZOVvpaPf1Y/rHHLd2Qa6+a/cCJ1sr2biagb75AihpQFsK/oy6D1PP70
|
|
||||||
zTe7hPWn/efEpmtCV7CQ8ti4cRu0Kjy0T8grtCsCAwEAAaMhMB8wHQYDVR0OBBYE
|
|
||||||
FIFlylzwADNLfgTDNkhFeFelaEDxMA0GCSqGSIb3DQEBCwUAA4IBAQBQ2rw4GLIU
|
|
||||||
v+GY7Qru9LttkrQPd2bZXKxDMd/jT+wjmMVtqS4MAsCuDYwaYLjU1aWyqy0mN+lY
|
|
||||||
A17kD0VjBNBy45sYqkZveY0ks8mCScBemtrIDmjz2tiueecBIEASwEPBOZgv5/MV
|
|
||||||
cz864FiChF+2r8Zl8bhycGy9DEpRjzYKvIQWSDHQ3zpuh3iBnjfoieLHWX2kKCpk
|
|
||||||
ouS3V6485rHNCWsZT5IcCwfBFQkOuWRJpIazpz4AfwZh1TK9+bgiKA5EyZjSNrKw
|
|
||||||
xGQSpMSTRQMB0/FOCL/AixhN9unVFUViqUcdtSfoHE1VyBHv9kDT/cYms/Xl4B0t
|
|
||||||
/ZSQJ/D/Km1+
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCpcWeeNE0NblAw
|
|
||||||
Ee2SfbntD83A9nT5m5SCHXcnpL2UufVe13a4WpnJV6RxNhHpUfO0nsbLdAWhx/45
|
|
||||||
qx8MQrcG3lx2fLniR5BhyeQy2QgosHxvkIJpe8JUl8V89+74ntrXZWYdsiUjPMry
|
|
||||||
wGHHh29szrJGhr7pe2SEyEtCaz3N6OlWZPjGBpGLQNiX1LL94x+KEG8Tn+0V6oVj
|
|
||||||
QF2wft4ZcEQcDCHcqATSumEvUEq03kvY41KoDuUJmkGTlb6Wj39WP6xxy3dkGuvm
|
|
||||||
v3AidbK9m4moG++QIoaUBbCv6Mug9Tz+9M03u4T1p/3nxKZrQlewkPLYuHEbtCo8
|
|
||||||
tE/IK7QrAgMBAAECggEAH9qmeKrra2F4KLlOGNKS//qPGz4Z+ozhi95/NpA1Zb7Z
|
|
||||||
3pUSCBFcROo5i2D3WA4kiymoRLpQjrv60puVcCggoWVvK4VCKsR6Y6/hOx/q9T9M
|
|
||||||
fWrE4ZC3FVEc+uPfZJT0nja9TkrdyXSV0LITD8Ap1eI7yJ9vR5R/bqj64QcpLMrU
|
|
||||||
QeoQIy1oTMR+qdjj33duyRwBZU3Yf8FRB2iW6OILZ8hzFo1jngec7dph9a1RK4e0
|
|
||||||
mEPdc9ywsKlDM7P0Y7zdmjar5XtQn87GiwNhz23f1fzCC2axLtOW0Xm4e4Qumehb
|
|
||||||
WrIi6Vfq8IWMglU7QrBJ7iR0Ls+XoKA5GxomV2IJZQKBgQDoIkOl5YGPQ3iGR+WK
|
|
||||||
e5/2Ml4G/uURzYiOlzSsyfoPXyO4EI2BJd5HkH+EvfgRx4xKkxUZRJdzR7llYPl8
|
|
||||||
BFYcFitvhO8SbD0mNAB5YW7f+3v1pgEN2umzoKd389Zx5WqTZ7YB1VG5RN/Q1JJL
|
|
||||||
2JM0Xgamq2vNtx3roRPxDBeW7QKBgQC63R/bmACJbgIzfaVBX4Zie3NQG0/Hf+gF
|
|
||||||
LnBwUmQDZOR7MY+kSiIUVMn3NuZRiCSCFBVwApruyK8r535JCibTVm5PWjvhFddY
|
|
||||||
LgaPOCKGlm9TLScjoH1pErYgG3uJ4nXeRfXhg4mco6EkrC7RzQywrd0VDoqpuc1Y
|
|
||||||
EKfEsYk8dwKBgE+mSh3nNOBKX1V73+f3aTiZqaeu2DyWkG+UtE9BclrJ40Cp9VPG
|
|
||||||
AZH+o7KRWEgJdzqzYv7riSfWCWgesRv7hOxYMwktzLY+i3DLUQpVAy05ZhwwnJX7
|
|
||||||
ckrfKfc/pGoqNLplUI8qecMfPciy14vMwR2r0Y5orTHFzi9mcqg35PQ1AoGAW2LX
|
|
||||||
OLq+0HdHhk0Va8I+450CSRQCUUvhed87SANTPEG0Z/dWC3/h6NWKrGdh/k+5oxAV
|
|
||||||
Z+EuSkdFPBCLt0bKtCKZ8h7sF+lplotz08kdQXsC2MfFU2wiySdIgK1QHp/tCxZl
|
|
||||||
6LM+sqdnoJrAjwRcB3AQJkMlV1ox7ba/hbdZqYMCgYBS6+JUXSSASpm5ZHd32a8m
|
|
||||||
xwryEZ7H6Hek6lvMHdxmwoKat5dCavxw64nrtyeeGZpg1W3zLLyamF9x/8kMyr6y
|
|
||||||
KKvtBfJ5sCvAbt80o9Pbs6R3yDB3AKiD3s3PQK7lol1nhE/8IbsF2r8JEQVcYd/k
|
|
||||||
oBzkl7MrMyLhhaCqSxwqQQ==
|
|
||||||
-----END PRIVATE KEY-----
|
|
||||||
@@ -8,14 +8,14 @@
|
|||||||
"answers": [
|
"answers": [
|
||||||
{
|
{
|
||||||
"id": "option1",
|
"id": "option1",
|
||||||
"org.matrix.msc1767.text": "option1text"
|
"org.matrix.msc1767.text": "option1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "option2",
|
"id": "option2",
|
||||||
"org.matrix.msc1767.text": "option2text"
|
"org.matrix.msc1767.text": "option2"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"kind": "org.matrix.msc3381.poll.undisclosed",
|
"kind": "org.matrix.msc3381.poll.disclosed",
|
||||||
"max_selections": 1,
|
"max_selections": 1,
|
||||||
"question": {
|
"question": {
|
||||||
"body": "test",
|
"body": "test",
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQuickItem>
|
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
|
||||||
#include "delegatesizehelper.h"
|
#include "delegatesizehelper.h"
|
||||||
@@ -31,7 +30,7 @@ void DelegateSizeHelperTest::risingPercentage_data()
|
|||||||
QTest::addColumn<int>("currentPercentageWidth");
|
QTest::addColumn<int>("currentPercentageWidth");
|
||||||
QTest::addColumn<qreal>("currentWidth");
|
QTest::addColumn<qreal>("currentWidth");
|
||||||
|
|
||||||
QTest::newRow("zero") << qreal(0) << int(100) << qreal(0);
|
QTest::newRow("zero") << qreal(0) << int(0) << qreal(0);
|
||||||
QTest::newRow("one hundred") << qreal(100) << int(0) << qreal(0);
|
QTest::newRow("one hundred") << qreal(100) << int(0) << qreal(0);
|
||||||
QTest::newRow("one fifty") << qreal(150) << int(50) << qreal(75);
|
QTest::newRow("one fifty") << qreal(150) << int(50) << qreal(75);
|
||||||
QTest::newRow("two hundred") << qreal(200) << int(100) << qreal(200);
|
QTest::newRow("two hundred") << qreal(200) << int(100) << qreal(200);
|
||||||
@@ -44,18 +43,16 @@ void DelegateSizeHelperTest::risingPercentage()
|
|||||||
QFETCH(int, currentPercentageWidth);
|
QFETCH(int, currentPercentageWidth);
|
||||||
QFETCH(qreal, currentWidth);
|
QFETCH(qreal, currentWidth);
|
||||||
|
|
||||||
auto item = QQuickItem();
|
|
||||||
item.setWidth(parentWidth);
|
|
||||||
|
|
||||||
DelegateSizeHelper delegateSizeHelper;
|
DelegateSizeHelper delegateSizeHelper;
|
||||||
delegateSizeHelper.setParentItem(&item);
|
|
||||||
delegateSizeHelper.setStartBreakpoint(100);
|
delegateSizeHelper.setStartBreakpoint(100);
|
||||||
delegateSizeHelper.setEndBreakpoint(200);
|
delegateSizeHelper.setEndBreakpoint(200);
|
||||||
delegateSizeHelper.setStartPercentWidth(0);
|
delegateSizeHelper.setStartPercentWidth(0);
|
||||||
delegateSizeHelper.setEndPercentWidth(100);
|
delegateSizeHelper.setEndPercentWidth(100);
|
||||||
|
|
||||||
QCOMPARE(delegateSizeHelper.availablePercentageWidth(), currentPercentageWidth);
|
delegateSizeHelper.setParentWidth(parentWidth);
|
||||||
QCOMPARE(delegateSizeHelper.availableWidth(), currentWidth);
|
|
||||||
|
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||||
|
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DelegateSizeHelperTest::fallingPercentage_data()
|
void DelegateSizeHelperTest::fallingPercentage_data()
|
||||||
@@ -77,18 +74,16 @@ void DelegateSizeHelperTest::fallingPercentage()
|
|||||||
QFETCH(int, currentPercentageWidth);
|
QFETCH(int, currentPercentageWidth);
|
||||||
QFETCH(qreal, currentWidth);
|
QFETCH(qreal, currentWidth);
|
||||||
|
|
||||||
auto item = QQuickItem();
|
|
||||||
item.setWidth(parentWidth);
|
|
||||||
|
|
||||||
DelegateSizeHelper delegateSizeHelper;
|
DelegateSizeHelper delegateSizeHelper;
|
||||||
delegateSizeHelper.setParentItem(&item);
|
|
||||||
delegateSizeHelper.setStartBreakpoint(100);
|
delegateSizeHelper.setStartBreakpoint(100);
|
||||||
delegateSizeHelper.setEndBreakpoint(200);
|
delegateSizeHelper.setEndBreakpoint(200);
|
||||||
delegateSizeHelper.setStartPercentWidth(100);
|
delegateSizeHelper.setStartPercentWidth(100);
|
||||||
delegateSizeHelper.setEndPercentWidth(0);
|
delegateSizeHelper.setEndPercentWidth(0);
|
||||||
|
|
||||||
QCOMPARE(delegateSizeHelper.availablePercentageWidth(), currentPercentageWidth);
|
delegateSizeHelper.setParentWidth(parentWidth);
|
||||||
QCOMPARE(delegateSizeHelper.availableWidth(), currentWidth);
|
|
||||||
|
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||||
|
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DelegateSizeHelperTest::equalPercentage_data()
|
void DelegateSizeHelperTest::equalPercentage_data()
|
||||||
@@ -110,18 +105,16 @@ void DelegateSizeHelperTest::equalPercentage()
|
|||||||
QFETCH(int, currentPercentageWidth);
|
QFETCH(int, currentPercentageWidth);
|
||||||
QFETCH(qreal, currentWidth);
|
QFETCH(qreal, currentWidth);
|
||||||
|
|
||||||
auto item = QQuickItem();
|
|
||||||
item.setWidth(parentWidth);
|
|
||||||
|
|
||||||
DelegateSizeHelper delegateSizeHelper;
|
DelegateSizeHelper delegateSizeHelper;
|
||||||
delegateSizeHelper.setParentItem(&item);
|
|
||||||
delegateSizeHelper.setStartBreakpoint(100);
|
delegateSizeHelper.setStartBreakpoint(100);
|
||||||
delegateSizeHelper.setEndBreakpoint(200);
|
delegateSizeHelper.setEndBreakpoint(200);
|
||||||
delegateSizeHelper.setStartPercentWidth(50);
|
delegateSizeHelper.setStartPercentWidth(50);
|
||||||
delegateSizeHelper.setEndPercentWidth(50);
|
delegateSizeHelper.setEndPercentWidth(50);
|
||||||
|
|
||||||
QCOMPARE(delegateSizeHelper.availablePercentageWidth(), currentPercentageWidth);
|
delegateSizeHelper.setParentWidth(parentWidth);
|
||||||
QCOMPARE(delegateSizeHelper.availableWidth(), currentWidth);
|
|
||||||
|
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||||
|
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DelegateSizeHelperTest::equalBreakpoint_data()
|
void DelegateSizeHelperTest::equalBreakpoint_data()
|
||||||
@@ -131,9 +124,9 @@ void DelegateSizeHelperTest::equalBreakpoint_data()
|
|||||||
QTest::addColumn<int>("currentPercentageWidth");
|
QTest::addColumn<int>("currentPercentageWidth");
|
||||||
QTest::addColumn<qreal>("currentWidth");
|
QTest::addColumn<qreal>("currentWidth");
|
||||||
|
|
||||||
QTest::newRow("start higher") << int(100) << int(0) << int(100) << qreal(1000);
|
QTest::newRow("start higher") << int(100) << int(0) << int(-1) << qreal(0);
|
||||||
QTest::newRow("equal") << int(50) << int(50) << int(50) << qreal(500);
|
QTest::newRow("equal") << int(50) << int(50) << int(50) << qreal(500);
|
||||||
QTest::newRow("end higher") << int(0) << int(100) << int(100) << qreal(1000);
|
QTest::newRow("end higher") << int(0) << int(100) << int(-1) << qreal(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,18 +140,16 @@ void DelegateSizeHelperTest::equalBreakpoint()
|
|||||||
QFETCH(int, currentPercentageWidth);
|
QFETCH(int, currentPercentageWidth);
|
||||||
QFETCH(qreal, currentWidth);
|
QFETCH(qreal, currentWidth);
|
||||||
|
|
||||||
auto item = QQuickItem();
|
|
||||||
item.setWidth(1000);
|
|
||||||
|
|
||||||
DelegateSizeHelper delegateSizeHelper;
|
DelegateSizeHelper delegateSizeHelper;
|
||||||
delegateSizeHelper.setParentItem(&item);
|
|
||||||
delegateSizeHelper.setStartBreakpoint(100);
|
delegateSizeHelper.setStartBreakpoint(100);
|
||||||
delegateSizeHelper.setEndBreakpoint(100);
|
delegateSizeHelper.setEndBreakpoint(100);
|
||||||
delegateSizeHelper.setStartPercentWidth(startPercentageWidth);
|
delegateSizeHelper.setStartPercentWidth(startPercentageWidth);
|
||||||
delegateSizeHelper.setEndPercentWidth(endPercentageWidth);
|
delegateSizeHelper.setEndPercentWidth(endPercentageWidth);
|
||||||
|
|
||||||
QCOMPARE(delegateSizeHelper.availablePercentageWidth(), currentPercentageWidth);
|
delegateSizeHelper.setParentWidth(1000);
|
||||||
QCOMPARE(delegateSizeHelper.availableWidth(), currentWidth);
|
|
||||||
|
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||||
|
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN(DelegateSizeHelperTest)
|
QTEST_GUILESS_MAIN(DelegateSizeHelperTest)
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ private Q_SLOTS:
|
|||||||
void MediaSizeHelperTest::uninitialized()
|
void MediaSizeHelperTest::uninitialized()
|
||||||
{
|
{
|
||||||
MediaSizeHelper mediasizehelper;
|
MediaSizeHelper mediasizehelper;
|
||||||
mediasizehelper.setMaxSize(540, 540);
|
|
||||||
QCOMPARE(mediasizehelper.currentSize(), QSize(540, qRound(qreal(NeoChatConfig::self()->mediaMaxWidth()) / qreal(16.0) * qreal(9.0))));
|
QCOMPARE(mediasizehelper.currentSize(), QSize(540, qRound(qreal(NeoChatConfig::self()->mediaMaxWidth()) / qreal(16.0) * qreal(9.0))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +60,6 @@ void MediaSizeHelperTest::limits()
|
|||||||
QFETCH(QSize, currentSize);
|
QFETCH(QSize, currentSize);
|
||||||
|
|
||||||
MediaSizeHelper mediasizehelper;
|
MediaSizeHelper mediasizehelper;
|
||||||
mediasizehelper.setMaxSize(540, 540);
|
|
||||||
mediasizehelper.setMediaWidth(mediaWidth);
|
mediasizehelper.setMediaWidth(mediaWidth);
|
||||||
mediasizehelper.setMediaHeight(mediaHeight);
|
mediasizehelper.setMediaHeight(mediaHeight);
|
||||||
mediasizehelper.setContentMaxWidth(contentMaxWidth);
|
mediasizehelper.setContentMaxWidth(contentMaxWidth);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include "models/messagecontentmodel.h"
|
#include "models/messagecontentmodel.h"
|
||||||
|
|
||||||
#include "neochatconnection.h"
|
|
||||||
#include "testutils.h"
|
#include "testutils.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -33,7 +32,7 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
void MessageContentModelTest::initTestCase()
|
void MessageContentModelTest::initTestCase()
|
||||||
{
|
{
|
||||||
connection = new NeoChatConnection;
|
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageContentModelTest::missingEvent()
|
void MessageContentModelTest::missingEvent()
|
||||||
|
|||||||
@@ -41,32 +41,29 @@ void PollHandlerTest::nullObject()
|
|||||||
auto pollHandler = PollHandler();
|
auto pollHandler = PollHandler();
|
||||||
|
|
||||||
QCOMPARE(pollHandler.hasEnded(), false);
|
QCOMPARE(pollHandler.hasEnded(), false);
|
||||||
QCOMPARE(pollHandler.numAnswers(), 0);
|
QCOMPARE(pollHandler.answerCount(), 0);
|
||||||
QCOMPARE(pollHandler.question(), QString());
|
QCOMPARE(pollHandler.question(), QString());
|
||||||
QCOMPARE(pollHandler.kind(), PollKind::Disclosed);
|
QCOMPARE(pollHandler.options(), QJsonArray());
|
||||||
|
QCOMPARE(pollHandler.answers(), QJsonObject());
|
||||||
|
QCOMPARE(pollHandler.counts(), QJsonObject());
|
||||||
|
QCOMPARE(pollHandler.kind(), QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PollHandlerTest::poll()
|
void PollHandlerTest::poll()
|
||||||
{
|
{
|
||||||
auto startEvent = eventCast<const PollStartEvent>(room->messageEvents().at(0).get());
|
auto startEvent = eventCast<const PollStartEvent>(room->messageEvents().at(0).get());
|
||||||
auto pollHandler = PollHandler(room, startEvent->id());
|
auto pollHandler = PollHandler(room, startEvent);
|
||||||
|
|
||||||
QList<Quotient::EventContent::Answer> options = {EventContent::Answer{"option1"_L1, "option1"_L1}, EventContent::Answer{"option2"_L1, "option2"_L1}};
|
auto options = QJsonArray{QJsonObject{{"id"_L1, "option1"_L1}, {"org.matrix.msc1767.text"_L1, "option1"_L1}},
|
||||||
|
QJsonObject{{"id"_L1, "option2"_L1}, {"org.matrix.msc1767.text"_L1, "option2"_L1}}};
|
||||||
|
|
||||||
const auto answer0 = pollHandler.answerAtRow(0);
|
|
||||||
const auto answer1 = pollHandler.answerAtRow(1);
|
|
||||||
QCOMPARE(pollHandler.hasEnded(), false);
|
QCOMPARE(pollHandler.hasEnded(), false);
|
||||||
QCOMPARE(pollHandler.numAnswers(), 2);
|
QCOMPARE(pollHandler.answerCount(), 0);
|
||||||
QCOMPARE(pollHandler.question(), u"test"_s);
|
QCOMPARE(pollHandler.question(), u"test"_s);
|
||||||
QCOMPARE(answer0.id, "option1"_L1);
|
QCOMPARE(pollHandler.options(), options);
|
||||||
QCOMPARE(answer1.id, "option2"_L1);
|
QCOMPARE(pollHandler.answers(), QJsonObject());
|
||||||
QCOMPARE(answer0.text, "option1text"_L1);
|
QCOMPARE(pollHandler.counts(), QJsonObject());
|
||||||
QCOMPARE(answer1.text, "option2text"_L1);
|
QCOMPARE(pollHandler.kind(), u"org.matrix.msc3381.poll.disclosed"_s);
|
||||||
QCOMPARE(pollHandler.answerCountAtId(answer0.id), 0);
|
|
||||||
QCOMPARE(pollHandler.answerCountAtId(answer1.id), 0);
|
|
||||||
QCOMPARE(pollHandler.checkMemberSelectedId(connection->userId(), answer0.id), false);
|
|
||||||
QCOMPARE(pollHandler.checkMemberSelectedId(connection->userId(), answer1.id), false);
|
|
||||||
QCOMPARE(pollHandler.kind(), PollKind::Undisclosed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN(PollHandlerTest)
|
QTEST_GUILESS_MAIN(PollHandlerTest)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include <Quotient/events/roommessageevent.h>
|
#include <Quotient/events/roommessageevent.h>
|
||||||
|
|
||||||
#include "models/messagecontentmodel.h"
|
|
||||||
#include "testutils.h"
|
#include "testutils.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|||||||
@@ -1,235 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "server.h"
|
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
#include <QHttpServer>
|
|
||||||
#include <QHttpServerResponder>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QSslCertificate>
|
|
||||||
#include <QSslKey>
|
|
||||||
#include <QSslServer>
|
|
||||||
#include <QUuid>
|
|
||||||
|
|
||||||
#include <Quotient/networkaccessmanager.h>
|
|
||||||
|
|
||||||
using namespace Qt::Literals::StringLiterals;
|
|
||||||
|
|
||||||
QString generateEventId()
|
|
||||||
{
|
|
||||||
return u"$"_s + QString::fromLatin1(QCryptographicHash::hash(QUuid::createUuid().toString().toLatin1(), QCryptographicHash::Sha1).toBase64());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString generateRoomId()
|
|
||||||
{
|
|
||||||
return u"!%1:localhost:1234"_s
|
|
||||||
.arg(QString::fromLatin1(QCryptographicHash::hash(QUuid::createUuid().toString().toLatin1(), QCryptographicHash::Sha1).toBase64()))
|
|
||||||
.replace(u'/', QChar());
|
|
||||||
}
|
|
||||||
|
|
||||||
Server::Server()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::start()
|
|
||||||
{
|
|
||||||
QObject::connect(Quotient::NetworkAccessManager::instance(),
|
|
||||||
&QNetworkAccessManager::sslErrors,
|
|
||||||
Quotient::NetworkAccessManager::instance(),
|
|
||||||
[](QNetworkReply *reply) {
|
|
||||||
reply->ignoreSslErrors();
|
|
||||||
});
|
|
||||||
m_server.route(u"/.well-known/matrix/client"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
|
||||||
responder.write(QJsonDocument(QJsonObject{
|
|
||||||
{u"m.homeserver"_s, QJsonObject{{u"base_url"_s, u"https://localhost:1234"_s}}},
|
|
||||||
}),
|
|
||||||
QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
|
||||||
m_server.route(u"/_matrix/client/versions"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
|
||||||
responder.write(QJsonDocument(QJsonObject{
|
|
||||||
{u"versions"_s,
|
|
||||||
QJsonArray{
|
|
||||||
u"v1.0"_s,
|
|
||||||
u"v1.1"_s,
|
|
||||||
u"v1.2"_s,
|
|
||||||
u"v1.3"_s,
|
|
||||||
u"v1.4"_s,
|
|
||||||
u"v1.5"_s,
|
|
||||||
u"v1.6"_s,
|
|
||||||
u"v1.7"_s,
|
|
||||||
u"v1.8"_s,
|
|
||||||
u"v1.9"_s,
|
|
||||||
u"v1.10"_s,
|
|
||||||
u"v1.11"_s,
|
|
||||||
u"v1.12"_s,
|
|
||||||
u"v1.13"_s,
|
|
||||||
}},
|
|
||||||
}),
|
|
||||||
QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
|
||||||
m_server.route(u"/_matrix/client/v3/capabilities"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
|
||||||
responder.write(
|
|
||||||
QJsonDocument(QJsonObject{{u"capabilities"_s,
|
|
||||||
QJsonObject{
|
|
||||||
{u"m.room_versions"_s, QJsonObject{{u"m.available"_s, QJsonObject{{u"1"_s, u"stable"_s}}}, {u"default"_s, u"1"_s}}},
|
|
||||||
}}}),
|
|
||||||
QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
|
||||||
m_server.route(u"/_matrix/client/v3/account/whoami"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
|
||||||
responder.write(QJsonDocument(QJsonObject{
|
|
||||||
{u"device_id"_s, u"device_id_1234"_s},
|
|
||||||
{u"user_id"_s, u"@user:localhost:1234"_s},
|
|
||||||
}),
|
|
||||||
QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
|
||||||
|
|
||||||
m_server.route(u"/_matrix/client/v3/login"_s, QHttpServerRequest::Method::Post, [](QHttpServerResponder &responder) {
|
|
||||||
// TODO
|
|
||||||
// if data["identifier"]["user"] != "user" or data["password"] != "1234":
|
|
||||||
// abort(403)
|
|
||||||
responder.write(QJsonDocument(QJsonObject{
|
|
||||||
{u"access_token"_s, u"token_login"_s},
|
|
||||||
{u"device_id"_s, u"device_1234"_s},
|
|
||||||
{u"user_id"_s, u"@user:localhost:1234"_s},
|
|
||||||
}),
|
|
||||||
QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
|
||||||
|
|
||||||
m_server.route(u"/_matrix/client/v3/login"_s, QHttpServerRequest::Method::Get, [](QHttpServerResponder &responder) {
|
|
||||||
responder.write(QJsonDocument(QJsonObject{
|
|
||||||
{u"flows"_s, QJsonArray{QJsonObject{{u"type"_s, u"m.login.password"_s}}}},
|
|
||||||
}),
|
|
||||||
QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
|
||||||
|
|
||||||
m_server.route(u"/_matrix/client/v3/rooms/<arg>/invite"_s,
|
|
||||||
QHttpServerRequest::Method::Post,
|
|
||||||
[this](const QString &roomId, QHttpServerResponder &responder, const QHttpServerRequest &request) {
|
|
||||||
m_invitedUsers[roomId] += QJsonDocument::fromJson(request.body()).object()[u"user_id"_s].toString();
|
|
||||||
responder.write(QJsonDocument(QJsonObject{}), QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
|
||||||
|
|
||||||
m_server.route(u"/_matrix/client/r0/sync"_s, QHttpServerRequest::Method::Get, [this](QHttpServerResponder &responder) {
|
|
||||||
QMap<QString, QJsonArray> stateEvents;
|
|
||||||
|
|
||||||
for (const auto &[roomId, matrixId] : m_roomsToCreate) {
|
|
||||||
stateEvents[roomId] += QJsonObject{
|
|
||||||
{u"content"_s, QJsonObject{{u"room_version"_s, u"11"_s}}},
|
|
||||||
{u"event_id"_s, generateEventId()},
|
|
||||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
|
||||||
{u"room_id"_s, roomId},
|
|
||||||
{u"sender"_s, matrixId},
|
|
||||||
{u"state_key"_s, QString()},
|
|
||||||
{u"type"_s, u"m.room.create"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
stateEvents[roomId] += QJsonObject{
|
|
||||||
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
|
|
||||||
{u"event_id"_s, generateEventId()},
|
|
||||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
|
||||||
{u"room_id"_s, roomId},
|
|
||||||
{u"sender"_s, matrixId},
|
|
||||||
{u"state_key"_s, matrixId},
|
|
||||||
{u"type"_s, u"m.room.member"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
m_roomsToCreate.clear();
|
|
||||||
for (const auto &roomId : m_invitedUsers.keys()) {
|
|
||||||
const auto &values = m_invitedUsers[roomId];
|
|
||||||
for (const auto &value : values) {
|
|
||||||
stateEvents[roomId] += QJsonObject{
|
|
||||||
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"invite"_s}}},
|
|
||||||
{u"event_id"_s, generateEventId()},
|
|
||||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
|
||||||
{u"room_id"_s, roomId},
|
|
||||||
{u"sender"_s, u"@user:localhost:1234"_s},
|
|
||||||
{u"state_key"_s, value},
|
|
||||||
{u"type"_s, u"m.room.member"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_invitedUsers.clear();
|
|
||||||
|
|
||||||
for (const auto &roomId : m_bannedUsers.keys()) {
|
|
||||||
const auto &values = m_bannedUsers[roomId];
|
|
||||||
for (const auto &value : values) {
|
|
||||||
stateEvents[roomId] += QJsonObject{
|
|
||||||
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"ban"_s}}},
|
|
||||||
{u"event_id"_s, generateEventId()},
|
|
||||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
|
||||||
{u"room_id"_s, roomId},
|
|
||||||
{u"sender"_s, u"@user:localhost:1234"_s},
|
|
||||||
{u"state_key"_s, value},
|
|
||||||
{u"type"_s, u"m.room.member"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_bannedUsers.clear();
|
|
||||||
|
|
||||||
for (const auto &roomId : m_joinedUsers.keys()) {
|
|
||||||
const auto &values = m_joinedUsers[roomId];
|
|
||||||
for (const auto &value : values) {
|
|
||||||
stateEvents[roomId] += QJsonObject{
|
|
||||||
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
|
|
||||||
{u"event_id"_s, generateEventId()},
|
|
||||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
|
||||||
{u"room_id"_s, roomId},
|
|
||||||
{u"sender"_s, u"@user:localhost:1234"_s},
|
|
||||||
{u"state_key"_s, value},
|
|
||||||
{u"type"_s, u"m.room.member"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_joinedUsers.clear();
|
|
||||||
|
|
||||||
QJsonObject rooms;
|
|
||||||
for (const auto &roomId : stateEvents.keys()) {
|
|
||||||
rooms[roomId] = QJsonObject{{u"state"_s, QJsonObject{{u"events"_s, stateEvents[roomId]}}}};
|
|
||||||
}
|
|
||||||
|
|
||||||
responder.write(QJsonDocument(QJsonObject{{u"rooms"_s, QJsonObject{{u"join"_s, rooms}}}}), QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
|
||||||
|
|
||||||
QSslConfiguration config;
|
|
||||||
QFile key(QStringLiteral(DATA_DIR) + u"/localhost.key"_s);
|
|
||||||
key.open(QFile::ReadOnly);
|
|
||||||
config.setPrivateKey(QSslKey(&key, QSsl::Rsa));
|
|
||||||
config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(DATA_DIR) + u"/localhost.crt"_s).front());
|
|
||||||
m_sslServer.setSslConfiguration(config);
|
|
||||||
if (!m_sslServer.listen(QHostAddress::LocalHost, 1234) || !m_server.bind(&m_sslServer)) {
|
|
||||||
qFatal() << "Server failed to listen on a port.";
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
qWarning() << "Server listening";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Server::createRoom(const QString &matrixId)
|
|
||||||
{
|
|
||||||
auto roomId = generateRoomId();
|
|
||||||
m_roomsToCreate += {roomId, matrixId};
|
|
||||||
return roomId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::inviteUser(const QString &roomId, const QString &matrixId)
|
|
||||||
{
|
|
||||||
m_invitedUsers[roomId] += matrixId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::banUser(const QString &roomId, const QString &matrixId)
|
|
||||||
{
|
|
||||||
m_bannedUsers[roomId] += matrixId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::joinUser(const QString &roomId, const QString &matrixId)
|
|
||||||
{
|
|
||||||
m_joinedUsers[roomId] += matrixId;
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <QHttpServer>
|
|
||||||
#include <QSslServer>
|
|
||||||
|
|
||||||
class Server
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Server();
|
|
||||||
|
|
||||||
void start();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a room and place the user with id matrixId in it.
|
|
||||||
* Returns the room's id
|
|
||||||
*/
|
|
||||||
QString createRoom(const QString &matrixId);
|
|
||||||
|
|
||||||
void inviteUser(const QString &roomId, const QString &matrixId);
|
|
||||||
void banUser(const QString &roomId, const QString &matrixId);
|
|
||||||
void joinUser(const QString &roomId, const QString &matrixId);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QHttpServer m_server;
|
|
||||||
QSslServer m_sslServer;
|
|
||||||
|
|
||||||
QHash<QString, QList<QString>> m_invitedUsers;
|
|
||||||
QHash<QString, QList<QString>> m_bannedUsers;
|
|
||||||
QHash<QString, QList<QString>> m_joinedUsers;
|
|
||||||
|
|
||||||
QList<std::pair<QString, QString>> m_roomsToCreate;
|
|
||||||
};
|
|
||||||
@@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
#include <Quotient/quotient_common.h>
|
#include <Quotient/quotient_common.h>
|
||||||
#include <Quotient/syncdata.h>
|
#include <Quotient/syncdata.h>
|
||||||
|
#include <qnamespace.h>
|
||||||
#include <Kirigami/Platform/PlatformTheme>
|
|
||||||
|
|
||||||
#include "enums/messagecomponenttype.h"
|
#include "enums/messagecomponenttype.h"
|
||||||
#include "models/customemojimodel.h"
|
#include "models/customemojimodel.h"
|
||||||
@@ -44,8 +43,6 @@ private Q_SLOTS:
|
|||||||
void sendCustomEmoji();
|
void sendCustomEmoji();
|
||||||
void sendCustomEmojiCode_data();
|
void sendCustomEmojiCode_data();
|
||||||
void sendCustomEmojiCode();
|
void sendCustomEmojiCode();
|
||||||
void sendCustomTags_data();
|
|
||||||
void sendCustomTags();
|
|
||||||
|
|
||||||
void receiveSpacelessSelfClosingTag();
|
void receiveSpacelessSelfClosingTag();
|
||||||
void receiveStripReply();
|
void receiveStripReply();
|
||||||
@@ -61,7 +58,6 @@ private Q_SLOTS:
|
|||||||
void receiveRichStrikethrough();
|
void receiveRichStrikethrough();
|
||||||
void receiveRichtextIn();
|
void receiveRichtextIn();
|
||||||
void receiveRichMxcUrl();
|
void receiveRichMxcUrl();
|
||||||
void receiveRichPlainUrl_data();
|
|
||||||
void receiveRichPlainUrl();
|
void receiveRichPlainUrl();
|
||||||
void receiveRichEdited_data();
|
void receiveRichEdited_data();
|
||||||
void receiveRichEdited();
|
void receiveRichEdited();
|
||||||
@@ -253,40 +249,6 @@ void TextHandlerTest::sendCustomEmojiCode()
|
|||||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::sendCustomTags_data()
|
|
||||||
{
|
|
||||||
QTest::addColumn<QString>("testInputString");
|
|
||||||
QTest::addColumn<QString>("testOutputString");
|
|
||||||
|
|
||||||
// spoiler
|
|
||||||
QTest::newRow("incomplete spoiler") << u"||test"_s << u"||test"_s;
|
|
||||||
QTest::newRow("complete spoiler") << u"||test||"_s << u"<span data-mx-spoiler>test</span>"_s;
|
|
||||||
QTest::newRow("multiple spoiler") << u"||apple||banana||pear||"_s << u"<span data-mx-spoiler>apple</span>banana<span data-mx-spoiler>pear</span>"_s;
|
|
||||||
QTest::newRow("inside code block spoiler") << u"```||apple||```"_s << u"<code>||apple||</code>"_s;
|
|
||||||
QTest::newRow("outside code block spoiler") << u"||apple|| ```||banana||``` ||pear||"_s
|
|
||||||
<< u"<span data-mx-spoiler>apple</span> <code>||banana||</code> <span data-mx-spoiler>pear</span>"_s;
|
|
||||||
QTest::newRow("complex spoiler") << u"Between `formFactor == Horizontal||Vertical` and `location == top||left||bottom||right`"_s
|
|
||||||
<< u"Between <code>formFactor == Horizontal||Vertical</code> and <code>location == top||left||bottom||right</code>"_s;
|
|
||||||
|
|
||||||
// strikethrough
|
|
||||||
QTest::newRow("incomplete strikethrough") << u"~~test"_s << u"~~test"_s;
|
|
||||||
QTest::newRow("complete strikethrough") << u"~~test~~"_s << u"<del>test</del>"_s;
|
|
||||||
QTest::newRow("inside code block strikethrough") << u"```~~apple~~```"_s << u"<code>~~apple~~</code>"_s;
|
|
||||||
QTest::newRow("outside code block strikethrough") << u"~~apple~~ ```~~banana~~``` ~~pear~~"_s
|
|
||||||
<< u"<del>apple</del> <code>~~banana~~</code> <del>pear</del>"_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextHandlerTest::sendCustomTags()
|
|
||||||
{
|
|
||||||
QFETCH(QString, testInputString);
|
|
||||||
QFETCH(QString, testOutputString);
|
|
||||||
|
|
||||||
TextHandler testTextHandler;
|
|
||||||
testTextHandler.setData(testInputString);
|
|
||||||
|
|
||||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextHandlerTest::receiveSpacelessSelfClosingTag()
|
void TextHandlerTest::receiveSpacelessSelfClosingTag()
|
||||||
{
|
{
|
||||||
const QString testInputString = u"Test...<br/>...ing"_s;
|
const QString testInputString = u"Test...<br/>...ing"_s;
|
||||||
@@ -451,32 +413,6 @@ void TextHandlerTest::receiveRichMxcUrl()
|
|||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(0).get()), testOutputString);
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(0).get()), testOutputString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::receiveRichPlainUrl_data()
|
|
||||||
{
|
|
||||||
QTest::addColumn<QString>("input");
|
|
||||||
QTest::addColumn<QString>("output");
|
|
||||||
|
|
||||||
// This is an actual link that caused trouble which is why it's so long. Keeping
|
|
||||||
// so we can confirm consistent behaviour for complex urls.
|
|
||||||
QTest::addRow("link 1")
|
|
||||||
<< u"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"_s
|
|
||||||
<< u"<a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im</a> <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"_s;
|
|
||||||
|
|
||||||
// Another real case. The linkification wasn't handling it when a single link
|
|
||||||
// contains what looks like and email. It was broken into 3 but needs to
|
|
||||||
// be just single link.
|
|
||||||
QTest::addRow("link 2")
|
|
||||||
<< u"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/"_s
|
|
||||||
<< u"<a href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\">https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>"_s;
|
|
||||||
|
|
||||||
QTest::addRow("email") << uR"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)"_s
|
|
||||||
<< uR"(<a href="mailto:email@example.com">email@example.com</a> <a href="mailto:email@example.com">Link already rich</a>)"_s;
|
|
||||||
QTest::addRow("mxid")
|
|
||||||
<< u"@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>"_s
|
|
||||||
<< u"<b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a></b>"_s;
|
|
||||||
QTest::addRow("mxid with prefix") << u"a @user:kde.org b"_s << u"a <b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> b"_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For when your rich input string has a plain text url left in.
|
* For when your rich input string has a plain text url left in.
|
||||||
*
|
*
|
||||||
@@ -485,13 +421,46 @@ void TextHandlerTest::receiveRichPlainUrl_data()
|
|||||||
*/
|
*/
|
||||||
void TextHandlerTest::receiveRichPlainUrl()
|
void TextHandlerTest::receiveRichPlainUrl()
|
||||||
{
|
{
|
||||||
QFETCH(QString, input);
|
// This is an actual link that caused trouble which is why it's so long. Keeping
|
||||||
QFETCH(QString, output);
|
// so we can confirm consistent behaviour for complex urls.
|
||||||
|
const QString testInputStringLink1 =
|
||||||
|
u"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"_s;
|
||||||
|
const QString testOutputStringLink1 =
|
||||||
|
u"<a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im</a> <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"_s;
|
||||||
|
|
||||||
|
// Another real case. The linkification wasn't handling it when a single link
|
||||||
|
// contains what looks like and email. It was been broken into 3 but needs to
|
||||||
|
// be just single link.
|
||||||
|
const QString testInputStringLink2 = u"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/"_s;
|
||||||
|
const QString testOutputStringLink2 =
|
||||||
|
u"<a href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\">https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>"_s;
|
||||||
|
|
||||||
|
QString testInputStringEmail = uR"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)"_s;
|
||||||
|
QString testOutputStringEmail = uR"(<a href="mailto:email@example.com">email@example.com</a> <a href="mailto:email@example.com">Link already rich</a>)"_s;
|
||||||
|
|
||||||
|
QString testInputStringMxId = u"@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>"_s;
|
||||||
|
QString testOutputStringMxId =
|
||||||
|
u"<b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a></b>"_s;
|
||||||
|
|
||||||
|
QString testInputStringMxIdWithPrefix = u"a @user:kde.org b"_s;
|
||||||
|
QString testOutputStringMxIdWithPrefix = u"a <b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> b"_s;
|
||||||
|
|
||||||
TextHandler testTextHandler;
|
TextHandler testTextHandler;
|
||||||
testTextHandler.setData(input);
|
testTextHandler.setData(testInputStringLink1);
|
||||||
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), output);
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringLink1);
|
||||||
|
|
||||||
|
testTextHandler.setData(testInputStringLink2);
|
||||||
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringLink2);
|
||||||
|
|
||||||
|
testTextHandler.setData(testInputStringEmail);
|
||||||
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringEmail);
|
||||||
|
|
||||||
|
testTextHandler.setData(testInputStringMxId);
|
||||||
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxId);
|
||||||
|
|
||||||
|
testTextHandler.setData(testInputStringMxIdWithPrefix);
|
||||||
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxIdWithPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::receiveRichEdited_data()
|
void TextHandlerTest::receiveRichEdited_data()
|
||||||
@@ -499,12 +468,9 @@ void TextHandlerTest::receiveRichEdited_data()
|
|||||||
QTest::addColumn<QString>("testInputString");
|
QTest::addColumn<QString>("testInputString");
|
||||||
QTest::addColumn<QString>("testOutputString");
|
QTest::addColumn<QString>("testOutputString");
|
||||||
|
|
||||||
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
QTest::newRow("basic") << u"Edited"_s << u"Edited <span style=\"color:#000000\">(edited)</span>"_s;
|
||||||
|
|
||||||
QTest::newRow("basic") << u"Edited"_s << u"Edited <span style=\"color:%1\">(edited)</span>"_s.arg(theme ? theme->disabledTextColor().name() : u"#000000"_s);
|
|
||||||
QTest::newRow("multiple paragraphs") << u"<p>Edited</p>\n<p>Edited</p>"_s
|
QTest::newRow("multiple paragraphs") << u"<p>Edited</p>\n<p>Edited</p>"_s
|
||||||
<< u"<p>Edited</p>\n<p>Edited <span style=\"color:%1\">(edited)</span></p>"_s.arg(
|
<< u"<p>Edited</p>\n<p>Edited <span style=\"color:#000000\">(edited)</span></p>"_s;
|
||||||
theme ? theme->disabledTextColor().name() : u"#000000"_s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::receiveRichEdited()
|
void TextHandlerTest::receiveRichEdited()
|
||||||
@@ -545,6 +511,8 @@ void TextHandlerTest::receiveRichColor()
|
|||||||
TextHandler testTextHandler;
|
TextHandler testTextHandler;
|
||||||
testTextHandler.setData(testInputString);
|
testTextHandler.setData(testInputString);
|
||||||
|
|
||||||
|
qInfo() << testTextHandler.handleRecieveRichText();
|
||||||
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ void TimelineMessageModelTest::switchEmptyRoom()
|
|||||||
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
||||||
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s);
|
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s);
|
||||||
|
|
||||||
QSignalSpy spy(model, SIGNAL(roomChanged(NeoChatRoom *, NeoChatRoom *)));
|
QSignalSpy spy(model, SIGNAL(roomChanged()));
|
||||||
|
|
||||||
QCOMPARE(model->room(), nullptr);
|
QCOMPARE(model->room(), nullptr);
|
||||||
model->setRoom(firstRoom);
|
model->setRoom(firstRoom);
|
||||||
@@ -77,7 +77,7 @@ void TimelineMessageModelTest::switchSyncedRoom()
|
|||||||
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
||||||
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
||||||
|
|
||||||
QSignalSpy spy(model, SIGNAL(roomChanged(NeoChatRoom *, NeoChatRoom *)));
|
QSignalSpy spy(model, SIGNAL(roomChanged()));
|
||||||
|
|
||||||
QCOMPARE(model->room(), nullptr);
|
QCOMPARE(model->room(), nullptr);
|
||||||
model->setRoom(firstRoom);
|
model->setRoom(firstRoom);
|
||||||
@@ -208,7 +208,7 @@ void TimelineMessageModelTest::idToRow()
|
|||||||
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-min-sync.json"_s);
|
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-min-sync.json"_s);
|
||||||
model->setRoom(room);
|
model->setRoom(room);
|
||||||
|
|
||||||
QCOMPARE(model->indexforEventId(u"$153456789:example.org"_s).row(), 0);
|
QCOMPARE(model->eventIdToRow(u"$153456789:example.org"_s), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineMessageModelTest::cleanup()
|
void TimelineMessageModelTest::cleanup()
|
||||||
|
|||||||
@@ -7,19 +7,16 @@ qt_add_executable(timeline-memtest
|
|||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(timeline-memtest PRIVATE neochatplugin Timelineplugin)
|
target_link_libraries(timeline-memtest PRIVATE neochatplugin timelineplugin)
|
||||||
target_link_libraries(timeline-memtest PUBLIC
|
target_link_libraries(timeline-memtest PUBLIC
|
||||||
Qt::Core
|
Qt::Core
|
||||||
Qt::Quick
|
Qt::Quick
|
||||||
Qt::Qml
|
Qt::Qml
|
||||||
Qt::Gui
|
Qt::Gui
|
||||||
Qt::QuickControls2
|
Qt::QuickControls2
|
||||||
Qt::Widgets
|
|
||||||
KF6::I18nQml
|
|
||||||
KF6::Kirigami
|
KF6::Kirigami
|
||||||
QuotientQt6
|
QuotientQt6
|
||||||
LibNeoChat
|
neochat
|
||||||
Timeline
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_add_qml_module(timeline-memtest URI org.kde.neochat.timeline-memtest GENERATE_PLUGIN_SOURCE
|
ecm_add_qml_module(timeline-memtest URI org.kde.neochat.timeline-memtest GENERATE_PLUGIN_SOURCE
|
||||||
@@ -33,5 +30,5 @@ ecm_add_qml_module(timeline-memtest URI org.kde.neochat.timeline-memtest GENERAT
|
|||||||
QtCore
|
QtCore
|
||||||
QtQuick
|
QtQuick
|
||||||
IMPORTS
|
IMPORTS
|
||||||
org.kde.neochat.timeline
|
org.kde.neochat
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ QQC2.ApplicationWindow {
|
|||||||
height: root.height
|
height: root.height
|
||||||
|
|
||||||
contentItem: ListView {
|
contentItem: ListView {
|
||||||
cacheBuffer: 1000000
|
|
||||||
model: messageFilterModel
|
model: messageFilterModel
|
||||||
|
|
||||||
delegate: EventDelegate {
|
delegate: EventDelegate {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
|
|
||||||
#include <KLocalizedQmlContext>
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
#include "memtesttimelinemodel.h"
|
#include "memtesttimelinemodel.h"
|
||||||
@@ -20,15 +19,12 @@ int main(int argc, char **argv)
|
|||||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
|
engine.loadFromModule("org.kde.neochat.timeline-memtest", "Main");
|
||||||
KLocalization::setupLocalizedContext(&engine);
|
|
||||||
|
|
||||||
MemTestTimelineModel *memTestTimelineModel = new MemTestTimelineModel;
|
MemTestTimelineModel *memTestTimelineModel = new MemTestTimelineModel;
|
||||||
MessageFilterModel *messageFilterModel = new MessageFilterModel(nullptr, memTestTimelineModel);
|
MessageFilterModel *messageFilterModel = new MessageFilterModel(nullptr, memTestTimelineModel);
|
||||||
engine.rootContext()->setContextProperty(u"memTestTimelineModel"_s, memTestTimelineModel);
|
engine.rootContext()->setContextProperty(u"memTestTimelineModel"_s, memTestTimelineModel);
|
||||||
engine.rootContext()->setContextProperty(u"messageFilterModel"_s, messageFilterModel);
|
engine.rootContext()->setContextProperty(u"messageFilterModel"_s, messageFilterModel);
|
||||||
|
|
||||||
engine.loadFromModule("org.kde.neochat.timeline-memtest", "Main");
|
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,7 +241,7 @@
|
|||||||
"formatted_body": "This is an example<br>text message",
|
"formatted_body": "This is an example<br>text message",
|
||||||
"msgtype": "m.text"
|
"msgtype": "m.text"
|
||||||
},
|
},
|
||||||
"event_id": 0,
|
"event_id": "$1000000000000:example.org",
|
||||||
"origin_server_ts": 1000000000000,
|
"origin_server_ts": 1000000000000,
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
"sender": "@example:example.org",
|
"sender": "@example:example.org",
|
||||||
@@ -255,7 +255,7 @@
|
|||||||
"body": "This is a highlight @bob:example.org",
|
"body": "This is a highlight @bob:example.org",
|
||||||
"msgtype": "m.text"
|
"msgtype": "m.text"
|
||||||
},
|
},
|
||||||
"event_id": 1,
|
"event_id": "$1000000000001:example.org",
|
||||||
"origin_server_ts": 1000000000001,
|
"origin_server_ts": 1000000000001,
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
"sender": "@example:example.org",
|
"sender": "@example:example.org",
|
||||||
@@ -266,11 +266,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"content": {
|
"content": {
|
||||||
"m.relates_to": {
|
"m.relates_to": {
|
||||||
"event_id": 1,
|
"event_id": "$1000000000001:example.org",
|
||||||
"key": "👍",
|
"key": "👍",
|
||||||
"rel_type": "m.annotation"
|
"rel_type": "m.annotation"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"origin_server_ts": 1000000000002,
|
"origin_server_ts": 1000000000002,
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
"unsigned": {
|
"unsigned": {
|
||||||
"age": 390159120
|
"age": 390159120
|
||||||
},
|
},
|
||||||
"event_id": 2,
|
"event_id": "$1000000000002:example.org",
|
||||||
"age": 390159120
|
"age": 390159120
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -289,7 +289,7 @@
|
|||||||
"formatted_body": "reply",
|
"formatted_body": "reply",
|
||||||
"m.relates_to": {
|
"m.relates_to": {
|
||||||
"m.in_reply_to": {
|
"m.in_reply_to": {
|
||||||
"event_id": 0
|
"event_id": "$1000000000000:example.org"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"msgtype": "m.text"
|
"msgtype": "m.text"
|
||||||
@@ -300,7 +300,7 @@
|
|||||||
"unsigned": {
|
"unsigned": {
|
||||||
"age": 98
|
"age": 98
|
||||||
},
|
},
|
||||||
"event_id": 3,
|
"event_id": "$1000000000003:example.org",
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -317,7 +317,7 @@
|
|||||||
"uri": "geo:51.7035,-1.14394"
|
"uri": "geo:51.7035,-1.14394"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"event_id": 4,
|
"event_id": "$1000000000004:example.org",
|
||||||
"origin_server_ts": 1000000000004,
|
"origin_server_ts": 1000000000004,
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
"sender": "@example:example.org",
|
"sender": "@example:example.org",
|
||||||
@@ -333,7 +333,7 @@
|
|||||||
"formatted_body": "<pre><code class=\"language-cpp\">int main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule("org.kde.neochat.timeline-memtest", "Main");\n\n return app.exec();\n}\n</code></pre>",
|
"formatted_body": "<pre><code class=\"language-cpp\">int main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule("org.kde.neochat.timeline-memtest", "Main");\n\n return app.exec();\n}\n</code></pre>",
|
||||||
"msgtype": "m.text"
|
"msgtype": "m.text"
|
||||||
},
|
},
|
||||||
"event_id": 5,
|
"event_id": "$1000000000005:example.org",
|
||||||
"origin_server_ts": 1000000000005,
|
"origin_server_ts": 1000000000005,
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
"sender": "@bob:example.org",
|
"sender": "@bob:example.org",
|
||||||
@@ -347,7 +347,7 @@
|
|||||||
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
|
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
|
||||||
"msgtype": "m.text"
|
"msgtype": "m.text"
|
||||||
},
|
},
|
||||||
"event_id": 6,
|
"event_id": "$1000000000006:example.org",
|
||||||
"origin_server_ts": 1000000000006,
|
"origin_server_ts": 1000000000006,
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
"sender": "@example:example.org",
|
"sender": "@example:example.org",
|
||||||
@@ -363,7 +363,7 @@
|
|||||||
"formatted_body": "<blockquote>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat.</p>\n</blockquote>",
|
"formatted_body": "<blockquote>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat.</p>\n</blockquote>",
|
||||||
"msgtype": "m.text"
|
"msgtype": "m.text"
|
||||||
},
|
},
|
||||||
"event_id": 7,
|
"event_id": "$1000000000007:example.org",
|
||||||
"origin_server_ts": 1000000000007,
|
"origin_server_ts": 1000000000007,
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
"sender": "@example:example.org",
|
"sender": "@example:example.org",
|
||||||
@@ -371,6 +371,282 @@
|
|||||||
"unsigned": {
|
"unsigned": {
|
||||||
"age": 1232
|
"age": 1232
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "This is an example text message",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "This is an example<br>text message",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000008:example.org",
|
||||||
|
"origin_server_ts": 1000000000008,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1232
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "This is a highlight @bob:example.org",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000009:example.org",
|
||||||
|
"origin_server_ts": 1000000000009,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1233
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"m.relates_to": {
|
||||||
|
"event_id": "$1000000000009:example.org",
|
||||||
|
"key": "👍",
|
||||||
|
"rel_type": "m.annotation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"origin_server_ts": 1000000000010,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@alice:example.org",
|
||||||
|
"type": "m.reaction",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 390159120
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000010:example.org",
|
||||||
|
"age": 390159120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "reply",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "reply",
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "$1000000000008:example.org"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"origin_server_ts": 1000000000011,
|
||||||
|
"sender": "@alice:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 98
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000011: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": "$1000000000012:example.org",
|
||||||
|
"origin_server_ts": 1000000000012,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 96845207
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "```cpp\nint main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral(\"neochat\"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule(\"org.kde.neochat.timeline-memtest\", \"Main\");\n\n return app.exec();\n}\n```",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<pre><code class=\"language-cpp\">int main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule("org.kde.neochat.timeline-memtest", "Main");\n\n return app.exec();\n}\n</code></pre>",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000013:example.org",
|
||||||
|
"origin_server_ts": 1000000000013,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@bob:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1233
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000014:example.org",
|
||||||
|
"origin_server_ts": 1000000000014,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1232
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<blockquote>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat.</p>\n</blockquote>",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000015:example.org",
|
||||||
|
"origin_server_ts": 1000000000015,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1232
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "This is an example text message",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "This is an example<br>text message",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000016:example.org",
|
||||||
|
"origin_server_ts": 1000000000016,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1232
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "This is a highlight @bob:example.org",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000017:example.org",
|
||||||
|
"origin_server_ts": 1000000000017,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1233
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"m.relates_to": {
|
||||||
|
"event_id": "$1000000000017:example.org",
|
||||||
|
"key": "👍",
|
||||||
|
"rel_type": "m.annotation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"origin_server_ts": 1000000000018,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@alice:example.org",
|
||||||
|
"type": "m.reaction",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 390159120
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000018:example.org",
|
||||||
|
"age": 390159120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "reply",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "reply",
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "$1000000000016:example.org"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"origin_server_ts": 1000000000019,
|
||||||
|
"sender": "@alice:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 98
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000019: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": "$1000000000020:example.org",
|
||||||
|
"origin_server_ts": 1000000000020,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 96845207
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "```cpp\nint main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral(\"neochat\"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule(\"org.kde.neochat.timeline-memtest\", \"Main\");\n\n return app.exec();\n}\n```",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<pre><code class=\"language-cpp\">int main(int argc, char **argv)\n{\n QApplication app(argc, argv);\n\n KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));\n\n QQmlApplicationEngine engine;\n engine.loadFromModule("org.kde.neochat.timeline-memtest", "Main");\n\n return app.exec();\n}\n</code></pre>",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000021:example.org",
|
||||||
|
"origin_server_ts": 1000000000021,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@bob:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1233
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000022:example.org",
|
||||||
|
"origin_server_ts": 1000000000022,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1232
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat. ",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<blockquote>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sed fringilla risus, eget lacinia risus. Suspendisse at magna id justo sagittis suscipit. Maecenas eros quam, pulvinar a consequat sed, varius vitae risus. Cras congue est eget felis porttitor lobortis. Nam cursus, nulla ut finibus suscipit, tellus eros tincidunt ante, a volutpat velit lectus sit amet turpis. Morbi leo justo, fringilla sed rutrum a, suscipit a quam. Proin rhoncus neque eget ligula ullamcorper pellentesque. Mauris volutpat malesuada nunc. Nullam finibus enim eu nibh placerat imperdiet. Nullam in mi in diam luctus scelerisque dignissim non erat.</p>\n</blockquote>",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$1000000000023:example.org",
|
||||||
|
"origin_server_ts": 1000000000023,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1232
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"limited": true,
|
"limited": true,
|
||||||
|
|||||||
@@ -39,52 +39,10 @@ public:
|
|||||||
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
|
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
|
||||||
testSyncFile.open(QIODevice::ReadOnly);
|
testSyncFile.open(QIODevice::ReadOnly);
|
||||||
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll()).object();
|
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll()).object();
|
||||||
auto timelineJson = testSyncJson["timeline"_L1].toObject();
|
|
||||||
timelineJson["events"_L1] = multiplyEvents(timelineJson["events"_L1].toArray(), 100);
|
|
||||||
testSyncJson["timeline"_L1] = timelineJson;
|
|
||||||
Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson);
|
Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson);
|
||||||
update(std::move(roomData));
|
update(std::move(roomData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray multiplyEvents(QJsonArray events, int factor)
|
|
||||||
{
|
|
||||||
QJsonArray newArray;
|
|
||||||
int eventNum = 0;
|
|
||||||
int ts = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < factor; ++i) {
|
|
||||||
for (const auto &event : events) {
|
|
||||||
auto eventObject = event.toObject();
|
|
||||||
auto contentJson = eventObject["content"_L1].toObject();
|
|
||||||
if (contentJson.contains("m.relates_to"_L1)) {
|
|
||||||
auto relatesToJson = contentJson["m.relates_to"_L1].toObject();
|
|
||||||
if (relatesToJson.contains("m.in_reply_to"_L1)) {
|
|
||||||
auto replyJson = relatesToJson["m.in_reply_to"_L1].toObject();
|
|
||||||
const auto currentId = eventObject["event_id"_L1].toInt();
|
|
||||||
const auto currentReplyId = replyJson["event_id"_L1].toInt();
|
|
||||||
replyJson["event_id"_L1] = "$%1:example.org"_L1.arg(QString::number(eventNum - (currentId - currentReplyId)));
|
|
||||||
relatesToJson["m.in_reply_to"_L1] = replyJson;
|
|
||||||
} else if (relatesToJson.contains("event_id"_L1)) {
|
|
||||||
const auto currentId = eventObject["event_id"_L1].toInt();
|
|
||||||
const auto currentRelationId = relatesToJson["event_id"_L1].toInt();
|
|
||||||
relatesToJson["event_id"_L1] = "$%1:example.org"_L1.arg(QString::number(eventNum - (currentId - currentRelationId)));
|
|
||||||
}
|
|
||||||
contentJson["m.relates_to"_L1] = relatesToJson;
|
|
||||||
eventObject["content"_L1] = contentJson;
|
|
||||||
}
|
|
||||||
eventObject["event_id"_L1] = "$%1:example.org"_L1.arg(QString::number(eventNum));
|
|
||||||
eventObject["origin_server_ts"_L1] = ts;
|
|
||||||
auto unsignedJson = eventObject["unsigned"_L1].toObject();
|
|
||||||
unsignedJson["age"_L1] = ts;
|
|
||||||
eventObject["unsigned"_L1] = unsignedJson;
|
|
||||||
newArray.append(eventObject);
|
|
||||||
++eventNum;
|
|
||||||
++ts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newArray;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -477,7 +477,6 @@
|
|||||||
<content_attribute id="social-chat">intense</content_attribute>
|
<content_attribute id="social-chat">intense</content_attribute>
|
||||||
</content_rating>
|
</content_rating>
|
||||||
<releases>
|
<releases>
|
||||||
<release version="25.04.3" date="2025-07-03"/>
|
|
||||||
<release version="25.04.2" date="2025-06-05"/>
|
<release version="25.04.2" date="2025-06-05"/>
|
||||||
<release version="25.04.1" date="2025-05-08"/>
|
<release version="25.04.1" date="2025-05-08"/>
|
||||||
<release version="25.04.0" date="2025-04-17"/>
|
<release version="25.04.0" date="2025-04-17"/>
|
||||||
|
|||||||
7277
po/ar/neochat.po
7277
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
7030
po/ast/neochat.po
7030
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
7984
po/az/neochat.po
7984
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
7344
po/ca/neochat.po
7344
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
7319
po/cs/neochat.po
7319
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
7694
po/da/neochat.po
7694
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
7715
po/de/neochat.po
7715
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
7692
po/el/neochat.po
7692
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
7641
po/en_GB/neochat.po
7641
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
7469
po/eo/neochat.po
7469
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
7349
po/es/neochat.po
7349
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
7423
po/eu/neochat.po
7423
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
7394
po/fi/neochat.po
7394
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
7519
po/fr/neochat.po
7519
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
7404
po/gl/neochat.po
7404
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
7244
po/he/neochat.po
7244
po/he/neochat.po
File diff suppressed because it is too large
Load Diff
7570
po/hi/neochat.po
7570
po/hi/neochat.po
File diff suppressed because it is too large
Load Diff
7834
po/hu/neochat.po
7834
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
7457
po/ia/neochat.po
7457
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
7914
po/id/neochat.po
7914
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
7692
po/ie/neochat.po
7692
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
7454
po/it/neochat.po
7454
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
7018
po/ja/neochat.po
7018
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
7367
po/ka/neochat.po
7367
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
7332
po/ko/neochat.po
7332
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
6950
po/lt/neochat.po
6950
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
7379
po/lv/neochat.po
7379
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
7446
po/nl/neochat.po
7446
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
7433
po/nn/neochat.po
7433
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
7966
po/pa/neochat.po
7966
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
7580
po/pl/neochat.po
7580
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
7942
po/pt/neochat.po
7942
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
7977
po/pt_BR/neochat.po
7977
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
7472
po/ru/neochat.po
7472
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
7530
po/sa/neochat.po
7530
po/sa/neochat.po
File diff suppressed because it is too large
Load Diff
7907
po/sk/neochat.po
7907
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
7305
po/sl/neochat.po
7305
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
7407
po/sv/neochat.po
7407
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
7490
po/ta/neochat.po
7490
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
7529
po/tok/neochat.po
7529
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
7405
po/tr/neochat.po
7405
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
7375
po/uk/neochat.po
7375
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
7175
po/zh_CN/neochat.po
7175
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
7266
po/zh_TW/neochat.po
7266
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -101,7 +101,7 @@ parts:
|
|||||||
- olm
|
- olm
|
||||||
- qtkeychain
|
- qtkeychain
|
||||||
source: https://github.com/quotient-im/libQuotient.git
|
source: https://github.com/quotient-im/libQuotient.git
|
||||||
source-tag: 0.9.2
|
source-tag: 0.9.1
|
||||||
source-depth: 1
|
source-depth: 1
|
||||||
plugin: cmake
|
plugin: cmake
|
||||||
build-environment:
|
build-environment:
|
||||||
|
|||||||
@@ -1,18 +1,586 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
|
# SPDX-FileCopyrightText: 2020-2021 Carl Schwan <carl@carlschwan.eu>
|
||||||
|
# SPDX-FileCopyrightText: 2020-2021 Nicolas Fella <nicolas.fella@gmx.de>
|
||||||
|
# SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE)
|
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE)
|
||||||
add_subdirectory(purpose)
|
add_subdirectory(purpose)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(libneochat)
|
add_library(neochat STATIC
|
||||||
add_subdirectory(login)
|
controller.cpp
|
||||||
add_subdirectory(rooms)
|
controller.h
|
||||||
add_subdirectory(roominfo)
|
models/emojimodel.cpp
|
||||||
add_subdirectory(messagecontent)
|
models/emojimodel.h
|
||||||
add_subdirectory(timeline)
|
emojitones.cpp
|
||||||
add_subdirectory(spaces)
|
emojitones.h
|
||||||
add_subdirectory(chatbar)
|
models/customemojimodel.cpp
|
||||||
|
models/customemojimodel.h
|
||||||
|
clipboard.cpp
|
||||||
|
clipboard.h
|
||||||
|
models/timelinemessagemodel.cpp
|
||||||
|
models/timelinemessagemodel.h
|
||||||
|
models/messagefiltermodel.cpp
|
||||||
|
models/messagefiltermodel.h
|
||||||
|
models/roomlistmodel.cpp
|
||||||
|
models/roomlistmodel.h
|
||||||
|
models/sortfilterspacelistmodel.cpp
|
||||||
|
models/sortfilterspacelistmodel.h
|
||||||
|
models/accountemoticonmodel.cpp
|
||||||
|
models/accountemoticonmodel.h
|
||||||
|
spacehierarchycache.cpp
|
||||||
|
spacehierarchycache.h
|
||||||
|
roommanager.cpp
|
||||||
|
roommanager.h
|
||||||
|
neochatroom.cpp
|
||||||
|
neochatroom.h
|
||||||
|
models/userlistmodel.cpp
|
||||||
|
models/userlistmodel.h
|
||||||
|
models/userfiltermodel.cpp
|
||||||
|
models/userfiltermodel.h
|
||||||
|
models/publicroomlistmodel.cpp
|
||||||
|
models/publicroomlistmodel.h
|
||||||
|
models/spacechildrenmodel.cpp
|
||||||
|
models/spacechildrenmodel.h
|
||||||
|
models/spacechildsortfiltermodel.cpp
|
||||||
|
models/spacechildsortfiltermodel.h
|
||||||
|
models/spacetreeitem.cpp
|
||||||
|
models/spacetreeitem.h
|
||||||
|
models/userdirectorylistmodel.cpp
|
||||||
|
models/userdirectorylistmodel.h
|
||||||
|
models/pushrulemodel.cpp
|
||||||
|
models/pushrulemodel.h
|
||||||
|
models/emoticonfiltermodel.cpp
|
||||||
|
models/emoticonfiltermodel.h
|
||||||
|
notificationsmanager.cpp
|
||||||
|
notificationsmanager.h
|
||||||
|
models/sortfilterroomlistmodel.cpp
|
||||||
|
models/sortfilterroomlistmodel.h
|
||||||
|
models/roomtreemodel.cpp
|
||||||
|
models/roomtreemodel.h
|
||||||
|
chatdocumenthandler.cpp
|
||||||
|
chatdocumenthandler.h
|
||||||
|
models/devicesmodel.cpp
|
||||||
|
models/devicesmodel.h
|
||||||
|
models/devicesproxymodel.cpp
|
||||||
|
filetype.cpp
|
||||||
|
filetype.h
|
||||||
|
login.cpp
|
||||||
|
login.h
|
||||||
|
models/webshortcutmodel.cpp
|
||||||
|
models/webshortcutmodel.h
|
||||||
|
blurhash.cpp
|
||||||
|
blurhash.h
|
||||||
|
blurhashimageprovider.cpp
|
||||||
|
blurhashimageprovider.h
|
||||||
|
models/mediamessagefiltermodel.cpp
|
||||||
|
models/mediamessagefiltermodel.h
|
||||||
|
urlhelper.cpp
|
||||||
|
urlhelper.h
|
||||||
|
windowcontroller.cpp
|
||||||
|
windowcontroller.h
|
||||||
|
linkpreviewer.cpp
|
||||||
|
linkpreviewer.h
|
||||||
|
models/completionmodel.cpp
|
||||||
|
models/completionmodel.h
|
||||||
|
models/completionproxymodel.cpp
|
||||||
|
models/completionproxymodel.h
|
||||||
|
models/actionsmodel.cpp
|
||||||
|
models/actionsmodel.h
|
||||||
|
models/serverlistmodel.cpp
|
||||||
|
models/serverlistmodel.h
|
||||||
|
models/statemodel.cpp
|
||||||
|
models/statemodel.h
|
||||||
|
models/statefiltermodel.cpp
|
||||||
|
models/statefiltermodel.h
|
||||||
|
filetransferpseudojob.cpp
|
||||||
|
filetransferpseudojob.h
|
||||||
|
models/searchmodel.cpp
|
||||||
|
models/searchmodel.h
|
||||||
|
texthandler.cpp
|
||||||
|
texthandler.h
|
||||||
|
logger.cpp
|
||||||
|
logger.h
|
||||||
|
models/stickermodel.cpp
|
||||||
|
models/stickermodel.h
|
||||||
|
models/imagepacksmodel.cpp
|
||||||
|
models/imagepacksmodel.h
|
||||||
|
events/imagepackevent.cpp
|
||||||
|
events/imagepackevent.h
|
||||||
|
models/reactionmodel.cpp
|
||||||
|
models/reactionmodel.h
|
||||||
|
delegatesizehelper.cpp
|
||||||
|
delegatesizehelper.h
|
||||||
|
models/livelocationsmodel.cpp
|
||||||
|
models/livelocationsmodel.h
|
||||||
|
models/locationsmodel.cpp
|
||||||
|
models/locationsmodel.h
|
||||||
|
locationhelper.cpp
|
||||||
|
locationhelper.h
|
||||||
|
events/pollevent.cpp
|
||||||
|
pollhandler.cpp
|
||||||
|
utils.h
|
||||||
|
utils.cpp
|
||||||
|
registration.cpp
|
||||||
|
neochatconnection.cpp
|
||||||
|
neochatconnection.h
|
||||||
|
jobs/neochatgetcommonroomsjob.cpp
|
||||||
|
jobs/neochatgetcommonroomsjob.h
|
||||||
|
mediasizehelper.cpp
|
||||||
|
mediasizehelper.h
|
||||||
|
eventhandler.cpp
|
||||||
|
enums/delegatetype.h
|
||||||
|
roomlastmessageprovider.cpp
|
||||||
|
roomlastmessageprovider.h
|
||||||
|
chatbarcache.cpp
|
||||||
|
chatbarcache.h
|
||||||
|
colorschemer.cpp
|
||||||
|
colorschemer.h
|
||||||
|
models/notificationsmodel.cpp
|
||||||
|
models/notificationsmodel.h
|
||||||
|
models/timelinemodel.cpp
|
||||||
|
models/timelinemodel.h
|
||||||
|
enums/pushrule.h
|
||||||
|
models/itinerarymodel.cpp
|
||||||
|
models/itinerarymodel.h
|
||||||
|
proxycontroller.cpp
|
||||||
|
proxycontroller.h
|
||||||
|
models/linemodel.cpp
|
||||||
|
models/linemodel.h
|
||||||
|
events/locationbeaconevent.h
|
||||||
|
events/widgetevent.h
|
||||||
|
enums/messagecomponenttype.h
|
||||||
|
models/messagecontentmodel.cpp
|
||||||
|
models/messagecontentmodel.h
|
||||||
|
enums/neochatroomtype.h
|
||||||
|
models/sortfilterroomtreemodel.cpp
|
||||||
|
models/sortfilterroomtreemodel.h
|
||||||
|
mediamanager.cpp
|
||||||
|
mediamanager.h
|
||||||
|
models/statekeysmodel.cpp
|
||||||
|
models/statekeysmodel.h
|
||||||
|
sharehandler.cpp
|
||||||
|
sharehandler.h
|
||||||
|
models/roomtreeitem.cpp
|
||||||
|
models/roomtreeitem.h
|
||||||
|
foreigntypes.h
|
||||||
|
models/threepidmodel.cpp
|
||||||
|
models/threepidmodel.h
|
||||||
|
threepidaddhelper.cpp
|
||||||
|
threepidaddhelper.h
|
||||||
|
identityserverhelper.cpp
|
||||||
|
identityserverhelper.h
|
||||||
|
enums/powerlevel.cpp
|
||||||
|
enums/powerlevel.h
|
||||||
|
models/permissionsmodel.cpp
|
||||||
|
models/permissionsmodel.h
|
||||||
|
threepidbindhelper.cpp
|
||||||
|
threepidbindhelper.h
|
||||||
|
models/readmarkermodel.cpp
|
||||||
|
models/readmarkermodel.h
|
||||||
|
neochatroommember.cpp
|
||||||
|
neochatroommember.h
|
||||||
|
models/threadmodel.cpp
|
||||||
|
models/threadmodel.h
|
||||||
|
enums/messagetype.h
|
||||||
|
messagecomponent.h
|
||||||
|
enums/roomsortparameter.cpp
|
||||||
|
enums/roomsortparameter.h
|
||||||
|
models/roomsortparametermodel.cpp
|
||||||
|
models/roomsortparametermodel.h
|
||||||
|
models/messagemodel.cpp
|
||||||
|
models/messagemodel.h
|
||||||
|
models/messagecontentfiltermodel.cpp
|
||||||
|
models/messagecontentfiltermodel.h
|
||||||
|
models/pinnedmessagemodel.cpp
|
||||||
|
models/pinnedmessagemodel.h
|
||||||
|
models/commonroomsmodel.cpp
|
||||||
|
models/commonroomsmodel.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||||
|
QT_QML_SINGLETON_TYPE TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
if(ANDROID OR WIN32)
|
||||||
|
set_source_files_properties(qml/ShareActionStub.qml PROPERTIES
|
||||||
|
QT_QML_SOURCE_TYPENAME ShareAction
|
||||||
|
)
|
||||||
|
set_source_files_properties(qml/GlobalMenuStub.qml PROPERTIES
|
||||||
|
QT_QML_SOURCE_TYPENAME GlobalMenu
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
||||||
|
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
|
||||||
|
QML_FILES
|
||||||
|
qml/Main.qml
|
||||||
|
qml/AccountMenu.qml
|
||||||
|
qml/ExploreComponent.qml
|
||||||
|
qml/ExploreComponentMobile.qml
|
||||||
|
qml/RoomContextMenu.qml
|
||||||
|
qml/CollapsedRoomDelegate.qml
|
||||||
|
qml/RoomDelegate.qml
|
||||||
|
qml/RoomListPage.qml
|
||||||
|
qml/SpaceListContextMenu.qml
|
||||||
|
qml/UserInfo.qml
|
||||||
|
qml/UserInfoDesktop.qml
|
||||||
|
qml/RoomPage.qml
|
||||||
|
qml/ExploreRoomsPage.qml
|
||||||
|
qml/ManualRoomDialog.qml
|
||||||
|
qml/ExplorerDelegate.qml
|
||||||
|
qml/InviteUserPage.qml
|
||||||
|
qml/ImageEditorPage.qml
|
||||||
|
qml/NeochatMaximizeComponent.qml
|
||||||
|
qml/TypingPane.qml
|
||||||
|
qml/QuickSwitcher.qml
|
||||||
|
qml/HoverActions.qml
|
||||||
|
qml/AttachmentPane.qml
|
||||||
|
qml/QuickFormatBar.qml
|
||||||
|
qml/UserDetailDialog.qml
|
||||||
|
qml/CreateRoomDialog.qml
|
||||||
|
qml/OpenFileDialog.qml
|
||||||
|
qml/KeyVerificationDialog.qml
|
||||||
|
qml/ConfirmLogoutDialog.qml
|
||||||
|
qml/PowerLevelDialog.qml
|
||||||
|
qml/Message.qml
|
||||||
|
qml/EmojiItem.qml
|
||||||
|
qml/EmojiRow.qml
|
||||||
|
qml/EmojiSas.qml
|
||||||
|
qml/ConfirmDeactivateAccountDialog.qml
|
||||||
|
qml/VerificationCanceled.qml
|
||||||
|
qml/MessageDelegateContextMenu.qml
|
||||||
|
qml/FileDelegateContextMenu.qml
|
||||||
|
qml/MessageSourceSheet.qml
|
||||||
|
qml/ConfirmEncryptionDialog.qml
|
||||||
|
qml/RoomSearchPage.qml
|
||||||
|
qml/RoomPinnedMessagesPage.qml
|
||||||
|
qml/LocationChooser.qml
|
||||||
|
qml/TimelineView.qml
|
||||||
|
qml/InvitationView.qml
|
||||||
|
qml/AvatarTabButton.qml
|
||||||
|
qml/SpaceDrawer.qml
|
||||||
|
qml/OsmLocationPlugin.qml
|
||||||
|
qml/FullScreenMap.qml
|
||||||
|
qml/LocationsPage.qml
|
||||||
|
qml/LocationMapItem.qml
|
||||||
|
qml/RoomDrawer.qml
|
||||||
|
qml/RoomDrawerPage.qml
|
||||||
|
qml/DirectChatDrawerHeader.qml
|
||||||
|
qml/GroupChatDrawerHeader.qml
|
||||||
|
qml/RoomInformation.qml
|
||||||
|
qml/RoomMedia.qml
|
||||||
|
qml/ChooseRoomDialog.qml
|
||||||
|
qml/SpaceHomePage.qml
|
||||||
|
qml/SpaceHierarchyDelegate.qml
|
||||||
|
qml/RemoveChildDialog.qml
|
||||||
|
qml/SelectParentDialog.qml
|
||||||
|
qml/QrCodeMaximizeComponent.qml
|
||||||
|
qml/SelectSpacesDialog.qml
|
||||||
|
qml/NotificationsView.qml
|
||||||
|
qml/SearchPage.qml
|
||||||
|
qml/ServerComboBox.qml
|
||||||
|
qml/UserSearchPage.qml
|
||||||
|
qml/ManualUserDialog.qml
|
||||||
|
qml/RecommendedSpaceDialog.qml
|
||||||
|
qml/RoomTreeSection.qml
|
||||||
|
qml/DelegateContextMenu.qml
|
||||||
|
qml/ShareDialog.qml
|
||||||
|
qml/UnlockSSSSDialog.qml
|
||||||
|
qml/QrScannerPage.qml
|
||||||
|
qml/JoinRoomDialog.qml
|
||||||
|
qml/ConfirmUrlDialog.qml
|
||||||
|
qml/AccountSwitchDialog.qml
|
||||||
|
qml/ConfirmLeaveDialog.qml
|
||||||
|
qml/CodeMaximizeComponent.qml
|
||||||
|
qml/EditStateDialog.qml
|
||||||
|
qml/ConsentDialog.qml
|
||||||
|
qml/AskDirectChatConfirmation.qml
|
||||||
|
qml/HoverLinkIndicator.qml
|
||||||
|
qml/AvatarNotification.qml
|
||||||
|
qml/ReasonDialog.qml
|
||||||
|
DEPENDENCIES
|
||||||
|
QtCore
|
||||||
|
QtQuick
|
||||||
|
IMPORTS
|
||||||
|
org.kde.neochat.timeline
|
||||||
|
org.kde.neochat.settings
|
||||||
|
org.kde.neochat.devtools
|
||||||
|
org.kde.neochat.login
|
||||||
|
org.kde.neochat.chatbar
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(settings)
|
add_subdirectory(settings)
|
||||||
|
add_subdirectory(timeline)
|
||||||
add_subdirectory(devtools)
|
add_subdirectory(devtools)
|
||||||
add_subdirectory(app)
|
add_subdirectory(login)
|
||||||
|
add_subdirectory(chatbar)
|
||||||
|
|
||||||
|
if(NOT ANDROID AND NOT WIN32)
|
||||||
|
qt_target_qml_sources(neochat QML_FILES
|
||||||
|
qml/ShareAction.qml
|
||||||
|
qml/GlobalMenu.qml
|
||||||
|
qml/EditMenu.qml
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
qt_target_qml_sources(neochat QML_FILES
|
||||||
|
qml/ShareActionStub.qml
|
||||||
|
qml/GlobalMenuStub.qml
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(config-neochat.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-neochat.h)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set_target_properties(neochat PROPERTIES OUTPUT_NAME "neochatlib")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
ecm_qt_declare_logging_category(neochat
|
||||||
|
HEADER "messagemodel_logging.h"
|
||||||
|
IDENTIFIER "Message"
|
||||||
|
CATEGORY_NAME "org.kde.neochat.messagemodel"
|
||||||
|
DESCRIPTION "Neochat: messagemodel"
|
||||||
|
DEFAULT_SEVERITY Info
|
||||||
|
EXPORT NEOCHAT
|
||||||
|
)
|
||||||
|
|
||||||
|
ecm_qt_declare_logging_category(neochat
|
||||||
|
HEADER "publicroomlist_logging.h"
|
||||||
|
IDENTIFIER "PublicRoomList"
|
||||||
|
CATEGORY_NAME "org.kde.neochat.publicroomlistmodel"
|
||||||
|
DESCRIPTION "Neochat: publicroomlistmodel"
|
||||||
|
DEFAULT_SEVERITY Info
|
||||||
|
EXPORT NEOCHAT
|
||||||
|
)
|
||||||
|
|
||||||
|
ecm_qt_declare_logging_category(neochat
|
||||||
|
HEADER "eventhandler_logging.h"
|
||||||
|
IDENTIFIER "EventHandling"
|
||||||
|
CATEGORY_NAME "org.kde.neochat.eventhandler"
|
||||||
|
DEFAULT_SEVERITY Info
|
||||||
|
)
|
||||||
|
|
||||||
|
ecm_qt_declare_logging_category(neochat
|
||||||
|
HEADER "chatdocumenthandler_logging.h"
|
||||||
|
IDENTIFIER "ChatDocumentHandling"
|
||||||
|
CATEGORY_NAME "org.kde.neochat.chatdocumenthandler"
|
||||||
|
DEFAULT_SEVERITY Info
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(neochat-app
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(TARGET Qt::WebView)
|
||||||
|
target_link_libraries(neochat-app PUBLIC Qt::WebView)
|
||||||
|
target_compile_definitions(neochat-app PUBLIC -DHAVE_WEBVIEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(neochat-app PRIVATE ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
|
target_link_libraries(neochat-app PRIVATE
|
||||||
|
neochat
|
||||||
|
)
|
||||||
|
|
||||||
|
ecm_add_app_icon(NEOCHAT_ICON ICONS ${CMAKE_SOURCE_DIR}/128-logo.png)
|
||||||
|
|
||||||
|
target_sources(neochat-app PRIVATE ${NEOCHAT_ICON})
|
||||||
|
|
||||||
|
if(NOT ANDROID)
|
||||||
|
if (NOT WIN32 AND NOT APPLE)
|
||||||
|
target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h)
|
||||||
|
target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem)
|
||||||
|
else()
|
||||||
|
target_sources(neochat PRIVATE trayicon.cpp trayicon.h)
|
||||||
|
endif()
|
||||||
|
target_link_libraries(neochat PUBLIC KF6::WindowSystem ICU::uc)
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_WINDOWSYSTEM)
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_ICU)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU)
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_RUNNER)
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_X11=1)
|
||||||
|
target_sources(neochat PRIVATE runner.cpp)
|
||||||
|
|
||||||
|
if (TARGET KUnifiedPush)
|
||||||
|
target_sources(neochat PRIVATE fakerunner.cpp)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_X11=0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
|
||||||
|
target_link_libraries(neochat PRIVATE settingsplugin timelineplugin devtoolsplugin loginplugin chatbarplugin)
|
||||||
|
target_link_libraries(neochat PUBLIC
|
||||||
|
Qt::Core
|
||||||
|
Qt::Quick
|
||||||
|
Qt::Qml
|
||||||
|
Qt::Gui
|
||||||
|
Qt::Multimedia
|
||||||
|
Qt::Network
|
||||||
|
Qt::QuickControls2
|
||||||
|
KF6::I18n
|
||||||
|
KF6::Kirigami
|
||||||
|
KF6::Notifications
|
||||||
|
KF6::ConfigCore
|
||||||
|
KF6::ConfigGui
|
||||||
|
KF6::CoreAddons
|
||||||
|
KF6::SonnetCore
|
||||||
|
KF6::IconThemes
|
||||||
|
KF6::ColorScheme
|
||||||
|
KF6::ItemModels
|
||||||
|
QuotientQt6
|
||||||
|
cmark::cmark
|
||||||
|
QCoro::Core
|
||||||
|
QCoro::Network
|
||||||
|
)
|
||||||
|
|
||||||
|
if (TARGET KF6::Crash)
|
||||||
|
target_link_libraries(neochat PUBLIC KF6::Crash)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
kconfig_target_kcfg_file(neochat FILE neochatconfig.kcfg CLASS_NAME NeoChatConfig MUTATORS GENERATE_PROPERTIES DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR SINGLETON GENERATE_MOC QML_REGISTRATION)
|
||||||
|
|
||||||
|
if(NEOCHAT_FLATPAK)
|
||||||
|
target_compile_definitions(neochat PUBLIC NEOCHAT_FLATPAK)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
target_sources(neochat PRIVATE notifyrc.qrc)
|
||||||
|
target_link_libraries(neochat PRIVATE Qt::Svg OpenSSL::SSL)
|
||||||
|
if(SQLite3_FOUND)
|
||||||
|
target_link_libraries(neochat-app PRIVATE SQLite::SQLite3)
|
||||||
|
endif()
|
||||||
|
target_sources(neochat-app PRIVATE notifyrc.qrc)
|
||||||
|
target_link_libraries(neochat PUBLIC Qt::Svg OpenSSL::SSL)
|
||||||
|
kirigami_package_breeze_icons(ICONS
|
||||||
|
"arrow-down-symbolic"
|
||||||
|
"arrow-up-symbolic"
|
||||||
|
"arrow-up-double-symbolic"
|
||||||
|
"arrow-left-symbolic"
|
||||||
|
"arrow-right-symbolic"
|
||||||
|
"checkmark"
|
||||||
|
"help-about"
|
||||||
|
"im-user"
|
||||||
|
"im-invisible-user"
|
||||||
|
"im-kick-user"
|
||||||
|
"mail-attachment"
|
||||||
|
"dialog-cancel"
|
||||||
|
"preferences-desktop-emoticons"
|
||||||
|
"preferences-security"
|
||||||
|
"document-open"
|
||||||
|
"document-save"
|
||||||
|
"document-send"
|
||||||
|
"dialog-close"
|
||||||
|
"edit-delete-remove"
|
||||||
|
"code-context"
|
||||||
|
"document-edit"
|
||||||
|
"list-user-add"
|
||||||
|
"list-add-user"
|
||||||
|
"user-others"
|
||||||
|
"media-playback-pause"
|
||||||
|
"media-playback-start"
|
||||||
|
"media-playback-stop"
|
||||||
|
"go-previous"
|
||||||
|
"go-up"
|
||||||
|
"go-down"
|
||||||
|
"list-add"
|
||||||
|
"irc-join-channel"
|
||||||
|
"settings-configure"
|
||||||
|
"configure"
|
||||||
|
"rating"
|
||||||
|
"rating-unrated"
|
||||||
|
"search"
|
||||||
|
"mail-replied-symbolic"
|
||||||
|
"edit-clear"
|
||||||
|
"edit-copy"
|
||||||
|
"gtk-quit"
|
||||||
|
"compass"
|
||||||
|
"computer"
|
||||||
|
"network-connect"
|
||||||
|
"list-remove-user"
|
||||||
|
"org.kde.neochat"
|
||||||
|
"org.kde.neochat.tray"
|
||||||
|
"preferences-system-users"
|
||||||
|
"preferences-desktop-theme-global"
|
||||||
|
"notifications"
|
||||||
|
"notifications-disabled"
|
||||||
|
"audio-volume-high"
|
||||||
|
"audio-volume-muted"
|
||||||
|
"draw-highlight"
|
||||||
|
"zoom-in"
|
||||||
|
"zoom-out"
|
||||||
|
"image-rotate-left-symbolic"
|
||||||
|
"image-rotate-right-symbolic"
|
||||||
|
"channel-secure-symbolic"
|
||||||
|
"download"
|
||||||
|
"smiley"
|
||||||
|
"tools-check-spelling"
|
||||||
|
"username-copy"
|
||||||
|
"system-switch-user"
|
||||||
|
"bookmark-new"
|
||||||
|
"bookmark-remove"
|
||||||
|
"favorite"
|
||||||
|
"window-new"
|
||||||
|
"globe"
|
||||||
|
"visibility"
|
||||||
|
"home"
|
||||||
|
"preferences-desktop-notification"
|
||||||
|
"computer-symbolic"
|
||||||
|
"gps"
|
||||||
|
"system-users-symbolic"
|
||||||
|
"map-flat"
|
||||||
|
"documentinfo"
|
||||||
|
"view-list-details"
|
||||||
|
"go-previous"
|
||||||
|
"mail-forward-symbolic"
|
||||||
|
"dialog-warning-symbolic"
|
||||||
|
"object-rotate-left"
|
||||||
|
"object-rotate-right"
|
||||||
|
"add-subtitle"
|
||||||
|
"security-high"
|
||||||
|
"security-low"
|
||||||
|
"security-low-symbolic"
|
||||||
|
"kde"
|
||||||
|
"list-remove-symbolic"
|
||||||
|
"edit-delete"
|
||||||
|
"user-home-symbolic"
|
||||||
|
"pin-symbolic"
|
||||||
|
"kt-restore-defaults-symbolic"
|
||||||
|
"user-symbolic"
|
||||||
|
)
|
||||||
|
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
|
||||||
|
else()
|
||||||
|
target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets KF6::SyntaxHighlighting)
|
||||||
|
install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT ANDROID)
|
||||||
|
set_target_properties(neochat-app PROPERTIES OUTPUT_NAME "neochat")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TARGET KF6::DBusAddons AND NOT WIN32)
|
||||||
|
target_link_libraries(neochat PUBLIC KF6::DBusAddons)
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_KDBUSADDONS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (TARGET KF6::KIOWidgets)
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_KIO)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (TARGET KUnifiedPush)
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_KUNIFIEDPUSH)
|
||||||
|
target_link_libraries(neochat PUBLIC KUnifiedPush)
|
||||||
|
|
||||||
|
if (NOT ANDROID)
|
||||||
|
configure_file(org.kde.neochat.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.service)
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.service DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS neochat-app ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||||
|
|
||||||
|
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||||
|
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -1,366 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2020-2021 Carl Schwan <carl@carlschwan.eu>
|
|
||||||
# SPDX-FileCopyrightText: 2020-2021 Nicolas Fella <nicolas.fella@gmx.de>
|
|
||||||
# SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
|
|
||||||
add_library(neochat STATIC
|
|
||||||
controller.cpp
|
|
||||||
controller.h
|
|
||||||
roommanager.cpp
|
|
||||||
roommanager.h
|
|
||||||
models/userdirectorylistmodel.cpp
|
|
||||||
models/userdirectorylistmodel.h
|
|
||||||
notificationsmanager.cpp
|
|
||||||
notificationsmanager.h
|
|
||||||
blurhash.cpp
|
|
||||||
blurhash.h
|
|
||||||
blurhashimageprovider.cpp
|
|
||||||
blurhashimageprovider.h
|
|
||||||
windowcontroller.cpp
|
|
||||||
windowcontroller.h
|
|
||||||
models/serverlistmodel.cpp
|
|
||||||
models/serverlistmodel.h
|
|
||||||
models/notificationsmodel.cpp
|
|
||||||
models/notificationsmodel.h
|
|
||||||
proxycontroller.cpp
|
|
||||||
proxycontroller.h
|
|
||||||
mediamanager.cpp
|
|
||||||
mediamanager.h
|
|
||||||
sharehandler.cpp
|
|
||||||
sharehandler.h
|
|
||||||
foreigntypes.h
|
|
||||||
identityserverhelper.cpp
|
|
||||||
identityserverhelper.h
|
|
||||||
models/commonroomsmodel.cpp
|
|
||||||
models/commonroomsmodel.h
|
|
||||||
texttospeechhelper.h
|
|
||||||
texttospeechhelper.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
|
||||||
QT_QML_SINGLETON_TYPE TRUE
|
|
||||||
)
|
|
||||||
|
|
||||||
if(ANDROID OR WIN32)
|
|
||||||
set_source_files_properties(qml/ShareActionStub.qml PROPERTIES
|
|
||||||
QT_QML_SOURCE_TYPENAME ShareAction
|
|
||||||
)
|
|
||||||
set_source_files_properties(qml/GlobalMenuStub.qml PROPERTIES
|
|
||||||
QT_QML_SOURCE_TYPENAME GlobalMenu
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
|
||||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
|
|
||||||
QML_FILES
|
|
||||||
qml/Main.qml
|
|
||||||
qml/AccountMenu.qml
|
|
||||||
qml/CollapsedRoomDelegate.qml
|
|
||||||
qml/RoomPage.qml
|
|
||||||
qml/ManualRoomDialog.qml
|
|
||||||
qml/ExplorerDelegate.qml
|
|
||||||
qml/NeochatMaximizeComponent.qml
|
|
||||||
qml/QuickSwitcher.qml
|
|
||||||
qml/AttachmentPane.qml
|
|
||||||
qml/QuickFormatBar.qml
|
|
||||||
qml/UserDetailDialog.qml
|
|
||||||
qml/OpenFileDialog.qml
|
|
||||||
qml/KeyVerificationDialog.qml
|
|
||||||
qml/ConfirmLogoutDialog.qml
|
|
||||||
qml/VerificationMessage.qml
|
|
||||||
qml/EmojiItem.qml
|
|
||||||
qml/EmojiRow.qml
|
|
||||||
qml/EmojiSas.qml
|
|
||||||
qml/VerificationCanceled.qml
|
|
||||||
qml/MessageSourceSheet.qml
|
|
||||||
qml/LocationChooser.qml
|
|
||||||
qml/InvitationView.qml
|
|
||||||
qml/AvatarTabButton.qml
|
|
||||||
qml/OsmLocationPlugin.qml
|
|
||||||
qml/FullScreenMap.qml
|
|
||||||
qml/ChooseRoomDialog.qml
|
|
||||||
qml/QrCodeMaximizeComponent.qml
|
|
||||||
qml/NotificationsView.qml
|
|
||||||
qml/ServerComboBox.qml
|
|
||||||
qml/UserSearchPage.qml
|
|
||||||
qml/ManualUserDialog.qml
|
|
||||||
qml/RecommendedSpaceDialog.qml
|
|
||||||
qml/ShareDialog.qml
|
|
||||||
qml/UnlockSSSSDialog.qml
|
|
||||||
qml/QrScannerPage.qml
|
|
||||||
qml/JoinRoomDialog.qml
|
|
||||||
qml/ConfirmUrlDialog.qml
|
|
||||||
qml/AccountSwitchDialog.qml
|
|
||||||
qml/ConfirmLeaveDialog.qml
|
|
||||||
qml/CodeMaximizeComponent.qml
|
|
||||||
qml/EditStateDialog.qml
|
|
||||||
qml/ConsentDialog.qml
|
|
||||||
qml/AskDirectChatConfirmation.qml
|
|
||||||
qml/HoverLinkIndicator.qml
|
|
||||||
qml/AvatarNotification.qml
|
|
||||||
qml/ReasonDialog.qml
|
|
||||||
qml/NewPollDialog.qml
|
|
||||||
qml/UserMenu.qml
|
|
||||||
DEPENDENCIES
|
|
||||||
QtCore
|
|
||||||
QtQuick
|
|
||||||
IMPORTS
|
|
||||||
org.kde.neochat.libneochat
|
|
||||||
org.kde.neochat.rooms
|
|
||||||
org.kde.neochat.roominfo
|
|
||||||
org.kde.neochat.messagecontent
|
|
||||||
org.kde.neochat.timeline
|
|
||||||
org.kde.neochat.spaces
|
|
||||||
org.kde.neochat.settings
|
|
||||||
org.kde.neochat.devtools
|
|
||||||
org.kde.neochat.login
|
|
||||||
org.kde.neochat.chatbar
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT ANDROID AND NOT WIN32)
|
|
||||||
qt_target_qml_sources(neochat QML_FILES
|
|
||||||
qml/ShareAction.qml
|
|
||||||
qml/GlobalMenu.qml
|
|
||||||
qml/EditMenu.qml
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
qt_target_qml_sources(neochat QML_FILES
|
|
||||||
qml/ShareActionStub.qml
|
|
||||||
qml/GlobalMenuStub.qml
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
set_target_properties(neochat PROPERTIES OUTPUT_NAME "neochatlib")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_executable(neochat-app
|
|
||||||
main.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
if(TARGET Qt::WebView)
|
|
||||||
target_link_libraries(neochat-app PUBLIC Qt::WebView)
|
|
||||||
target_compile_definitions(neochat-app PUBLIC -DHAVE_WEBVIEW)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_include_directories(neochat-app PRIVATE ${CMAKE_BINARY_DIR})
|
|
||||||
|
|
||||||
target_link_libraries(neochat-app PRIVATE
|
|
||||||
neochat
|
|
||||||
)
|
|
||||||
|
|
||||||
ecm_add_app_icon(NEOCHAT_ICON ICONS ${CMAKE_SOURCE_DIR}/128-logo.png)
|
|
||||||
|
|
||||||
target_sources(neochat-app PRIVATE ${NEOCHAT_ICON})
|
|
||||||
|
|
||||||
if(NOT ANDROID)
|
|
||||||
if (NOT WIN32 AND NOT APPLE)
|
|
||||||
target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h)
|
|
||||||
target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem)
|
|
||||||
else()
|
|
||||||
target_sources(neochat PRIVATE trayicon.cpp trayicon.h)
|
|
||||||
endif()
|
|
||||||
target_link_libraries(neochat PUBLIC KF6::WindowSystem)
|
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_WINDOWSYSTEM)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU)
|
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_RUNNER)
|
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_X11=1)
|
|
||||||
target_sources(neochat PRIVATE runner.cpp)
|
|
||||||
|
|
||||||
if (TARGET KUnifiedPush)
|
|
||||||
target_sources(neochat PRIVATE fakerunner.cpp)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_X11=0)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models)
|
|
||||||
target_link_libraries(neochat PRIVATE Loginplugin Roomsplugin RoomInfoplugin MessageContentplugin Timelineplugin Spacesplugin Chatbarplugin Settingsplugin Devtoolsplugin)
|
|
||||||
target_link_libraries(neochat PUBLIC
|
|
||||||
LibNeoChat
|
|
||||||
Timeline
|
|
||||||
Settings
|
|
||||||
Qt::Core
|
|
||||||
Qt::Quick
|
|
||||||
Qt::Qml
|
|
||||||
Qt::Gui
|
|
||||||
Qt::Multimedia
|
|
||||||
Qt::Network
|
|
||||||
Qt::QuickControls2
|
|
||||||
Qt::TextToSpeech
|
|
||||||
KF6::I18n
|
|
||||||
KF6::Kirigami
|
|
||||||
KF6::Notifications
|
|
||||||
KF6::ConfigCore
|
|
||||||
KF6::ConfigGui
|
|
||||||
KF6::CoreAddons
|
|
||||||
KF6::SonnetCore
|
|
||||||
KF6::IconThemes
|
|
||||||
KF6::ItemModels
|
|
||||||
QuotientQt6
|
|
||||||
Login
|
|
||||||
Rooms
|
|
||||||
MessageContent
|
|
||||||
Spaces
|
|
||||||
)
|
|
||||||
|
|
||||||
if (TARGET KF6::Crash)
|
|
||||||
target_link_libraries(neochat PUBLIC KF6::Crash)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
kconfig_target_kcfg_file(neochat FILE neochatconfig.kcfg CLASS_NAME NeoChatConfig MUTATORS GENERATE_PROPERTIES DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR SINGLETON GENERATE_MOC QML_REGISTRATION)
|
|
||||||
|
|
||||||
if(NEOCHAT_FLATPAK)
|
|
||||||
target_compile_definitions(neochat PUBLIC NEOCHAT_FLATPAK)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(ANDROID)
|
|
||||||
target_sources(neochat PRIVATE notifyrc.qrc)
|
|
||||||
target_link_libraries(neochat PRIVATE Qt::Svg OpenSSL::SSL)
|
|
||||||
if(SQLite3_FOUND)
|
|
||||||
target_link_libraries(neochat-app PRIVATE SQLite::SQLite3)
|
|
||||||
endif()
|
|
||||||
target_sources(neochat-app PRIVATE notifyrc.qrc)
|
|
||||||
target_link_libraries(neochat PUBLIC Qt::Svg OpenSSL::SSL)
|
|
||||||
kirigami_package_breeze_icons(ICONS
|
|
||||||
"arrow-down-symbolic"
|
|
||||||
"arrow-up-symbolic"
|
|
||||||
"arrow-up-double-symbolic"
|
|
||||||
"arrow-left-symbolic"
|
|
||||||
"arrow-right-symbolic"
|
|
||||||
"checkmark"
|
|
||||||
"help-about"
|
|
||||||
"im-user"
|
|
||||||
"im-invisible-user"
|
|
||||||
"im-kick-user"
|
|
||||||
"mail-attachment"
|
|
||||||
"dialog-cancel"
|
|
||||||
"preferences-desktop-emoticons"
|
|
||||||
"preferences-security"
|
|
||||||
"document-open"
|
|
||||||
"document-save"
|
|
||||||
"document-send"
|
|
||||||
"dialog-close"
|
|
||||||
"edit-delete-remove"
|
|
||||||
"code-context"
|
|
||||||
"document-edit"
|
|
||||||
"list-user-add"
|
|
||||||
"list-add-user"
|
|
||||||
"user-others"
|
|
||||||
"media-playback-pause"
|
|
||||||
"media-playback-start"
|
|
||||||
"media-playback-stop"
|
|
||||||
"go-previous"
|
|
||||||
"go-up"
|
|
||||||
"go-down"
|
|
||||||
"list-add"
|
|
||||||
"irc-join-channel"
|
|
||||||
"settings-configure"
|
|
||||||
"configure"
|
|
||||||
"rating"
|
|
||||||
"rating-unrated"
|
|
||||||
"search"
|
|
||||||
"mail-replied-symbolic"
|
|
||||||
"edit-clear"
|
|
||||||
"edit-copy"
|
|
||||||
"gtk-quit"
|
|
||||||
"compass"
|
|
||||||
"computer"
|
|
||||||
"network-connect"
|
|
||||||
"list-remove-user"
|
|
||||||
"org.kde.neochat"
|
|
||||||
"org.kde.neochat.tray"
|
|
||||||
"preferences-system-users"
|
|
||||||
"preferences-desktop-theme-global"
|
|
||||||
"notifications"
|
|
||||||
"notifications-disabled"
|
|
||||||
"audio-volume-high"
|
|
||||||
"audio-volume-muted"
|
|
||||||
"draw-highlight"
|
|
||||||
"zoom-in"
|
|
||||||
"zoom-out"
|
|
||||||
"image-rotate-left-symbolic"
|
|
||||||
"image-rotate-right-symbolic"
|
|
||||||
"channel-secure-symbolic"
|
|
||||||
"download"
|
|
||||||
"smiley"
|
|
||||||
"tools-check-spelling"
|
|
||||||
"username-copy"
|
|
||||||
"system-switch-user"
|
|
||||||
"bookmark-new"
|
|
||||||
"bookmark-remove"
|
|
||||||
"favorite"
|
|
||||||
"window-new"
|
|
||||||
"globe"
|
|
||||||
"visibility"
|
|
||||||
"home"
|
|
||||||
"preferences-desktop-notification"
|
|
||||||
"computer-symbolic"
|
|
||||||
"gps"
|
|
||||||
"system-users-symbolic"
|
|
||||||
"map-flat"
|
|
||||||
"documentinfo"
|
|
||||||
"view-list-details"
|
|
||||||
"go-previous"
|
|
||||||
"mail-forward-symbolic"
|
|
||||||
"dialog-warning-symbolic"
|
|
||||||
"object-rotate-left"
|
|
||||||
"object-rotate-right"
|
|
||||||
"add-subtitle"
|
|
||||||
"security-high"
|
|
||||||
"security-low"
|
|
||||||
"security-low-symbolic"
|
|
||||||
"kde"
|
|
||||||
"list-remove-symbolic"
|
|
||||||
"edit-delete"
|
|
||||||
"user-home-symbolic"
|
|
||||||
"pin-symbolic"
|
|
||||||
"kt-restore-defaults-symbolic"
|
|
||||||
"user-symbolic"
|
|
||||||
"mark-location-symbolic"
|
|
||||||
|
|
||||||
${KIRIGAMI_ADDONS_ICONS}
|
|
||||||
)
|
|
||||||
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
|
|
||||||
else()
|
|
||||||
target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets)
|
|
||||||
install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT ANDROID)
|
|
||||||
set_target_properties(neochat-app PROPERTIES OUTPUT_NAME "neochat")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(TARGET KF6::DBusAddons AND NOT WIN32)
|
|
||||||
target_link_libraries(neochat PUBLIC KF6::DBusAddons)
|
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_KDBUSADDONS)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (TARGET KF6::KIOWidgets)
|
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_KIO)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (TARGET KUnifiedPush)
|
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_KUNIFIEDPUSH)
|
|
||||||
target_link_libraries(neochat PUBLIC KUnifiedPush)
|
|
||||||
|
|
||||||
if (NOT ANDROID)
|
|
||||||
configure_file(org.kde.neochat.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.service)
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.service DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
install(TARGETS neochat-app ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
|
||||||
|
|
||||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
|
||||||
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
set_target_properties(neochat-app PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.neochat")
|
|
||||||
set_target_properties(neochat-app PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "NeoChat")
|
|
||||||
set_target_properties(neochat-app PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING ${RELEASE_SERVICE_VERSION})
|
|
||||||
set_target_properties(neochat-app PROPERTIES MACOSX_BUNDLE_BUNDLE_VERSION ${RELEASE_SERVICE_VERSION})
|
|
||||||
endif ()
|
|
||||||
@@ -1,415 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org>
|
|
||||||
// SPDX-FileCopyrightText: 2020 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
#include "controller.h"
|
|
||||||
|
|
||||||
#include <Quotient/connection.h>
|
|
||||||
#include <qt6keychain/keychain.h>
|
|
||||||
|
|
||||||
#include <KLocalizedString>
|
|
||||||
|
|
||||||
#include <QGuiApplication>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include <Quotient/csapi/notifications.h>
|
|
||||||
#include <Quotient/events/roommemberevent.h>
|
|
||||||
#include <Quotient/qt_connection_util.h>
|
|
||||||
#include <Quotient/settings.h>
|
|
||||||
|
|
||||||
#include "accountmanager.h"
|
|
||||||
#include "enums/roomsortparameter.h"
|
|
||||||
#include "mediasizehelper.h"
|
|
||||||
#include "models/actionsmodel.h"
|
|
||||||
#include "models/messagemodel.h"
|
|
||||||
#include "models/pushrulemodel.h"
|
|
||||||
#include "models/roomlistmodel.h"
|
|
||||||
#include "models/roomtreemodel.h"
|
|
||||||
#include "neochatconfig.h"
|
|
||||||
#include "neochatconnection.h"
|
|
||||||
#include "neochatroom.h"
|
|
||||||
#include "notificationsmanager.h"
|
|
||||||
#include "proxycontroller.h"
|
|
||||||
#include "roommanager.h"
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
|
||||||
#include "trayicon.h"
|
|
||||||
#elif !defined(Q_OS_ANDROID)
|
|
||||||
#include "trayicon_sni.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
|
||||||
#ifndef Q_OS_ANDROID
|
|
||||||
#include <QDBusConnection>
|
|
||||||
#include <QDBusInterface>
|
|
||||||
#include <QDBusMessage>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_KUNIFIEDPUSH
|
|
||||||
#include <kunifiedpush/connector.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace Quotient;
|
|
||||||
|
|
||||||
static std::function<bool(const Quotient::RoomEvent *)> hiddenEventFilter = [](const RoomEvent *event) -> bool {
|
|
||||||
if (event->isStateEvent() && !NeoChatConfig::showStateEvent()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (auto roomMemberEvent = eventCast<const RoomMemberEvent>(event)) {
|
|
||||||
if ((roomMemberEvent->isJoin() || roomMemberEvent->isLeave()) && !NeoChatConfig::showLeaveJoinEvent()) {
|
|
||||||
return true;
|
|
||||||
} else if (roomMemberEvent->isRename() && !roomMemberEvent->isJoin() && !roomMemberEvent->isLeave() && !NeoChatConfig::showRename()) {
|
|
||||||
return true;
|
|
||||||
} else if (roomMemberEvent->isAvatarUpdate() && !roomMemberEvent->isJoin() && !roomMemberEvent->isLeave() && !NeoChatConfig::showAvatarUpdate()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
Controller::Controller(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
Connection::setRoomType<NeoChatRoom>();
|
|
||||||
|
|
||||||
Connection::setDirectChatEncryptionDefault(NeoChatConfig::preferUsingEncryption());
|
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::PreferUsingEncryptionChanged, this, [] {
|
|
||||||
Connection::setDirectChatEncryptionDefault(NeoChatConfig::preferUsingEncryption());
|
|
||||||
});
|
|
||||||
|
|
||||||
NeoChatConnection::setGlobalUrlPreviewDefault(NeoChatConfig::showLinkPreview());
|
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::ShowLinkPreviewChanged, this, [this] {
|
|
||||||
NeoChatConnection::setGlobalUrlPreviewDefault(NeoChatConfig::showLinkPreview());
|
|
||||||
Q_EMIT globalUrlPreviewDefaultChanged();
|
|
||||||
});
|
|
||||||
|
|
||||||
NeoChatConnection::setKeywordPushRuleDefault(static_cast<PushRuleAction::Action>(NeoChatConfig::keywordPushRuleDefault()));
|
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::KeywordPushRuleDefaultChanged, this, [] {
|
|
||||||
NeoChatConnection::setKeywordPushRuleDefault(static_cast<PushRuleAction::Action>(NeoChatConfig::keywordPushRuleDefault()));
|
|
||||||
});
|
|
||||||
|
|
||||||
ActionsModel::setAllowQuickEdit(NeoChatConfig::allowQuickEdit());
|
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::AllowQuickEditChanged, this, []() {
|
|
||||||
ActionsModel::setAllowQuickEdit(NeoChatConfig::allowQuickEdit());
|
|
||||||
});
|
|
||||||
|
|
||||||
MessageModel::setHiddenFilter(hiddenEventFilter);
|
|
||||||
RoomListModel::setHiddenFilter(hiddenEventFilter);
|
|
||||||
RoomTreeModel::setHiddenFilter(hiddenEventFilter);
|
|
||||||
NeoChatRoom::setHiddenFilter(hiddenEventFilter);
|
|
||||||
|
|
||||||
MediaSizeHelper::setMaxSize(NeoChatConfig::mediaMaxWidth(), NeoChatConfig::mediaMaxHeight());
|
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::MediaMaxWidthChanged, this, []() {
|
|
||||||
MediaSizeHelper::setMaxSize(NeoChatConfig::mediaMaxWidth(), NeoChatConfig::mediaMaxHeight());
|
|
||||||
});
|
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::MediaMaxHeightChanged, this, []() {
|
|
||||||
MediaSizeHelper::setMaxSize(NeoChatConfig::mediaMaxWidth(), NeoChatConfig::mediaMaxHeight());
|
|
||||||
});
|
|
||||||
|
|
||||||
RoomSortParameter::setSortOrder(static_cast<RoomSortOrder::Order>(NeoChatConfig::sortOrder()));
|
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::SortOrderChanged, this, []() {
|
|
||||||
RoomSortParameter::setSortOrder(static_cast<RoomSortOrder::Order>(NeoChatConfig::sortOrder()));
|
|
||||||
});
|
|
||||||
|
|
||||||
QList<RoomSortParameter::Parameter> configParamList;
|
|
||||||
const auto intList = NeoChatConfig::customSortOrder();
|
|
||||||
std::transform(intList.constBegin(), intList.constEnd(), std::back_inserter(configParamList), [](int param) {
|
|
||||||
return static_cast<RoomSortParameter::Parameter>(param);
|
|
||||||
});
|
|
||||||
RoomSortParameter::setCustomSortOrder(configParamList);
|
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::CustomSortOrderChanged, this, []() {
|
|
||||||
QList<RoomSortParameter::Parameter> configParamList;
|
|
||||||
const auto intList = NeoChatConfig::customSortOrder();
|
|
||||||
std::transform(intList.constBegin(), intList.constEnd(), std::back_inserter(configParamList), [](int param) {
|
|
||||||
return static_cast<RoomSortParameter::Parameter>(param);
|
|
||||||
});
|
|
||||||
RoomSortParameter::setCustomSortOrder(configParamList);
|
|
||||||
});
|
|
||||||
|
|
||||||
ProxyController::instance().setApplicationProxy();
|
|
||||||
|
|
||||||
#ifndef Q_OS_ANDROID
|
|
||||||
setQuitOnLastWindowClosed();
|
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::SystemTrayChanged, this, &Controller::setQuitOnLastWindowClosed);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [this] {
|
|
||||||
delete m_trayIcon;
|
|
||||||
NeoChatConfig::self()->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
#ifndef Q_OS_WINDOWS
|
|
||||||
const auto unixExitHandler = [](int) -> void {
|
|
||||||
QCoreApplication::quit();
|
|
||||||
};
|
|
||||||
|
|
||||||
const int quitSignals[] = {SIGQUIT, SIGINT, SIGTERM, SIGHUP};
|
|
||||||
|
|
||||||
sigset_t blockingMask;
|
|
||||||
sigemptyset(&blockingMask);
|
|
||||||
for (const auto sig : quitSignals) {
|
|
||||||
sigaddset(&blockingMask, sig);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sigaction sa;
|
|
||||||
sa.sa_handler = unixExitHandler;
|
|
||||||
sa.sa_mask = blockingMask;
|
|
||||||
sa.sa_flags = 0;
|
|
||||||
|
|
||||||
for (auto sig : quitSignals) {
|
|
||||||
sigaction(sig, &sa, nullptr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_KUNIFIEDPUSH
|
|
||||||
auto connector = new KUnifiedPush::Connector(u"org.kde.neochat"_s);
|
|
||||||
connect(connector, &KUnifiedPush::Connector::endpointChanged, this, [this](const QString &endpoint) {
|
|
||||||
if (!m_accountManager) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_endpoint = endpoint;
|
|
||||||
for (auto "ientConnection : m_accountManager->accounts()->accounts()) {
|
|
||||||
auto connection = dynamic_cast<NeoChatConnection *>(quotientConnection);
|
|
||||||
connection->setupPushNotifications(endpoint);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connector->registerClient(
|
|
||||||
i18nc("The reason for using push notifications, as in: '[Push notifications are used for] Receiving notifications for new messages'",
|
|
||||||
"Receiving notifications for new messages"));
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller &Controller::instance()
|
|
||||||
{
|
|
||||||
static Controller _instance;
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::setAccountManager(AccountManager *manager)
|
|
||||||
{
|
|
||||||
if (manager == m_accountManager) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_accountManager) {
|
|
||||||
m_accountManager->disconnect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_accountManager = manager;
|
|
||||||
|
|
||||||
if (m_accountManager) {
|
|
||||||
connect(m_accountManager, &AccountManager::errorOccured, this, &Controller::errorOccured);
|
|
||||||
connect(m_accountManager, &AccountManager::accountsLoadingChanged, this, &Controller::accountsLoadingChanged);
|
|
||||||
connect(m_accountManager, &AccountManager::connectionAdded, this, &Controller::initConnection);
|
|
||||||
connect(m_accountManager, &AccountManager::connectionDropped, this, &Controller::teardownConnection);
|
|
||||||
connect(m_accountManager, &AccountManager::activeConnectionChanged, this, &Controller::initActiveConnection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::initConnection(NeoChatConnection *connection)
|
|
||||||
{
|
|
||||||
if (!connection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(
|
|
||||||
connection,
|
|
||||||
&NeoChatConnection::syncDone,
|
|
||||||
this,
|
|
||||||
[this, connection] {
|
|
||||||
if (!m_endpoint.isEmpty()) {
|
|
||||||
connection->setupPushNotifications(m_endpoint);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Qt::SingleShotConnection);
|
|
||||||
connect(connection, &NeoChatConnection::syncDone, this, [this, connection]() {
|
|
||||||
m_notificationsManager.handleNotifications(connection);
|
|
||||||
});
|
|
||||||
connect(this, &Controller::globalUrlPreviewDefaultChanged, connection, &NeoChatConnection::globalUrlPreviewEnabledChanged);
|
|
||||||
connect(connection, &NeoChatConnection::roomAboutToBeLeft, &RoomManager::instance(), &RoomManager::roomLeft);
|
|
||||||
Q_EMIT connectionAdded(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::teardownConnection(NeoChatConnection *connection)
|
|
||||||
{
|
|
||||||
if (!connection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connection->disconnect(this);
|
|
||||||
Q_EMIT connectionDropped(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::initActiveConnection(NeoChatConnection *oldConnection, NeoChatConnection *newConnection)
|
|
||||||
{
|
|
||||||
if (oldConnection) {
|
|
||||||
oldConnection->disconnect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newConnection) {
|
|
||||||
connect(newConnection, &NeoChatConnection::errorOccured, this, &Controller::errorOccured);
|
|
||||||
connect(newConnection, &NeoChatConnection::badgeNotificationCountChanged, this, &Controller::updateBadgeNotificationCount);
|
|
||||||
newConnection->refreshBadgeNotificationCount();
|
|
||||||
}
|
|
||||||
Q_EMIT activeConnectionChanged(newConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Controller::supportSystemTray() const
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
auto de = QString::fromLatin1(qgetenv("XDG_CURRENT_DESKTOP"));
|
|
||||||
return de != u"GNOME"_s && de != u"Pantheon"_s;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::setQuitOnLastWindowClosed()
|
|
||||||
{
|
|
||||||
#ifndef Q_OS_ANDROID
|
|
||||||
if (supportSystemTray() && NeoChatConfig::self()->systemTray()) {
|
|
||||||
m_trayIcon = new TrayIcon(this);
|
|
||||||
m_trayIcon->show();
|
|
||||||
} else {
|
|
||||||
if (m_trayIcon) {
|
|
||||||
delete m_trayIcon;
|
|
||||||
m_trayIcon = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
NeoChatConnection *Controller::activeConnection() const
|
|
||||||
{
|
|
||||||
if (!m_accountManager) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return m_accountManager->activeConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::setActiveConnection(NeoChatConnection *connection)
|
|
||||||
{
|
|
||||||
if (!m_accountManager) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_accountManager->setActiveConnection(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList Controller::accountsLoading() const
|
|
||||||
{
|
|
||||||
if (!m_accountManager) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return m_accountManager->accountsLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::listenForNotifications()
|
|
||||||
{
|
|
||||||
#ifdef HAVE_KUNIFIEDPUSH
|
|
||||||
auto connector = new KUnifiedPush::Connector(u"org.kde.neochat"_s);
|
|
||||||
|
|
||||||
auto timer = new QTimer();
|
|
||||||
connect(timer, &QTimer::timeout, qGuiApp, &QGuiApplication::quit);
|
|
||||||
|
|
||||||
connect(connector, &KUnifiedPush::Connector::messageReceived, [timer](const QByteArray &data) {
|
|
||||||
instance().m_notificationsManager.postPushNotification(data);
|
|
||||||
timer->stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Wait five seconds to see if we received any messages or this happened to be an erroneous activation.
|
|
||||||
// Otherwise, messageReceived is never activated, and this daemon could stick around forever.
|
|
||||||
timer->start(5000);
|
|
||||||
|
|
||||||
connector->registerClient(i18n("Receiving push notifications"));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::clearInvitationNotification(const QString &roomId)
|
|
||||||
{
|
|
||||||
m_notificationsManager.clearInvitationNotification(roomId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::updateBadgeNotificationCount(int count)
|
|
||||||
{
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
|
||||||
#ifndef Q_OS_ANDROID
|
|
||||||
// copied from Telegram desktop
|
|
||||||
const auto launcherUrl = "application://org.kde.neochat.desktop"_L1;
|
|
||||||
// Gnome requires that count is a 64bit integer
|
|
||||||
const qint64 counterSlice = std::min(count, 9999);
|
|
||||||
QVariantMap dbusUnityProperties;
|
|
||||||
|
|
||||||
if (counterSlice > 0) {
|
|
||||||
dbusUnityProperties["count"_L1] = counterSlice;
|
|
||||||
dbusUnityProperties["count-visible"_L1] = true;
|
|
||||||
} else {
|
|
||||||
dbusUnityProperties["count-visible"_L1] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto signal = QDBusMessage::createSignal("/com/canonical/unity/launcherentry/neochat"_L1, "com.canonical.Unity.LauncherEntry"_L1, "Update"_L1);
|
|
||||||
|
|
||||||
signal.setArguments({launcherUrl, dbusUnityProperties});
|
|
||||||
|
|
||||||
QDBusConnection::sessionBus().send(signal);
|
|
||||||
#endif // Q_OS_ANDROID
|
|
||||||
#else
|
|
||||||
qGuiApp->setBadgeNumber(count);
|
|
||||||
#endif // QT_VERSION_CHECK(6, 6, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Controller::isFlatpak() const
|
|
||||||
{
|
|
||||||
#ifdef NEOCHAT_FLATPAK
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
AccountRegistry *Controller::accounts()
|
|
||||||
{
|
|
||||||
return m_accountManager->accounts();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Controller::loadFileContent(const QString &path) const
|
|
||||||
{
|
|
||||||
QUrl url(path);
|
|
||||||
QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString());
|
|
||||||
file.open(QFile::ReadOnly);
|
|
||||||
return QString::fromLatin1(file.readAll());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::removeConnection(const QString &userId)
|
|
||||||
{
|
|
||||||
m_accountManager->dropConnection(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::revertToDefaultConfig()
|
|
||||||
{
|
|
||||||
const auto config = NeoChatConfig::self();
|
|
||||||
config->setDefaults();
|
|
||||||
config->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Controller::isImageShown(const QString &eventId)
|
|
||||||
{
|
|
||||||
return m_shownImages.contains(eventId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::markImageShown(const QString &eventId)
|
|
||||||
{
|
|
||||||
m_shownImages.append(eventId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::markImageHidden(const QString &eventId)
|
|
||||||
{
|
|
||||||
m_shownImages.removeAll(eventId);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_controller.cpp"
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
import QtQuick.Layouts
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property NeoChatRoom currentRoom
|
|
||||||
readonly property var invitingMember: currentRoom.qmlSafeMember(currentRoom.invitingUserId)
|
|
||||||
readonly property string inviteTimestamp: root.currentRoom.inviteTimestamp.toLocaleString(Qt.locale(), Locale.ShortFormat)
|
|
||||||
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
}
|
|
||||||
|
|
||||||
KirigamiComponents.Avatar {
|
|
||||||
id: avatar
|
|
||||||
Layout.preferredWidth: Kirigami.Units.iconSizes.huge
|
|
||||||
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
name: root.invitingMember.displayName
|
|
||||||
source: NeoChatConfig.hideImages ? undefined : root.invitingMember.avatarUrl
|
|
||||||
color: root.invitingMember.color
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
active: !root.currentRoom.isDirectChat()
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
sourceComponent: ColumnLayout {
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
QQC2.Label {
|
|
||||||
text: i18nc("@info:label 'Username' has invited you to this room at 'timestamp'.", "%1 has invited you to this room at %2.", root.invitingMember.displayName, root.inviteTimestamp)
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Kirigami.Heading {
|
|
||||||
text: root.currentRoom.displayName
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
active: root.currentRoom.isDirectChat()
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
sourceComponent: ColumnLayout {
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Kirigami.Heading {
|
|
||||||
text: root.currentRoom.displayName
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Label {
|
|
||||||
text: i18nc("@info:label This user invited you to chat at 'timestamp'", "This user invited you to chat at %1.", root.inviteTimestamp)
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FormCard.FormCard {
|
|
||||||
Layout.topMargin: Kirigami.Units.largeSpacing * 4
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
|
||||||
id: acceptInviteDelegate
|
|
||||||
|
|
||||||
icon.name: "dialog-ok-symbolic"
|
|
||||||
text: i18nc("@action:button Accept this invite", "Accept Invite")
|
|
||||||
focus: true
|
|
||||||
|
|
||||||
onClicked: root.currentRoom.acceptInvitation()
|
|
||||||
}
|
|
||||||
|
|
||||||
FormCard.FormDelegateSeparator {
|
|
||||||
above: acceptInviteDelegate
|
|
||||||
below: rejectInviteDelegate
|
|
||||||
}
|
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
|
||||||
id: rejectInviteDelegate
|
|
||||||
|
|
||||||
icon.name: "dialog-cancel-symbolic"
|
|
||||||
text: i18nc("@action:button Reject this invite", "Reject Invite")
|
|
||||||
|
|
||||||
onClicked: root.currentRoom.forget()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FormCard.FormCard {
|
|
||||||
id: blockUserCard
|
|
||||||
|
|
||||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
|
||||||
icon.name: "list-remove-symbolic"
|
|
||||||
text: i18nc("@action:button Block the user", "Block %1", root.invitingMember.displayName)
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.currentRoom.forget()
|
|
||||||
root.currentRoom.connection.addToIgnoredUsers(root.currentRoom.invitingUserId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
visible: root.currentRoom.connection.canCheckMutualRooms
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Layout.topMargin: Kirigami.Units.largeSpacing * 2
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Kirigami.Icon {
|
|
||||||
source: "help-hint-symbolic"
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
|
|
||||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
|
||||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Label {
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
text: i18nc("@info:label", "You can reject invitations from unknown users under Security settings.")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
// + 5 to prevent it from wrapping unnecessarily
|
|
||||||
Layout.maximumWidth: implicitWidth + 5
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
import QtQuick.Layouts
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
|
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
|
||||||
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
|
||||||
import org.kde.kirigamiaddons.delegates as Delegates
|
|
||||||
|
|
||||||
import Quotient
|
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
|
|
||||||
Kirigami.Dialog {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property NeoChatRoom room
|
|
||||||
|
|
||||||
standardButtons: Kirigami.Dialog.Cancel
|
|
||||||
|
|
||||||
customFooterActions: [
|
|
||||||
Kirigami.Action {
|
|
||||||
enabled: optionModel.allValuesSet && questionTextField.text.length > 0
|
|
||||||
text: i18nc("@action:button", "Send")
|
|
||||||
icon.name: "document-send"
|
|
||||||
onTriggered: {
|
|
||||||
root.room.postPoll(pollTypeCombo.currentValue, questionTextField.text, optionModel.values())
|
|
||||||
root.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
|
|
||||||
title: i18nc("@title: create new poll in the room", "Create Poll")
|
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
FormCard.FormComboBoxDelegate {
|
|
||||||
id: pollTypeCombo
|
|
||||||
|
|
||||||
text: i18n("Poll type:")
|
|
||||||
currentIndex: 0
|
|
||||||
textRole: "text"
|
|
||||||
valueRole: "value"
|
|
||||||
model: [
|
|
||||||
{ value: PollKind.Disclosed, text: i18n("Open poll") },
|
|
||||||
{ value: PollKind.Undisclosed, text: i18n("Closed poll") }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
FormCard.FormTextDelegate {
|
|
||||||
verticalPadding: 0
|
|
||||||
text: pollTypeCombo.currentValue == 0 ? i18n("Voters can see the result as soon as they have voted") : i18n("Results are revealed only after the poll has closed")
|
|
||||||
}
|
|
||||||
FormCard.FormTextFieldDelegate {
|
|
||||||
id: questionTextField
|
|
||||||
label: i18n("Question:")
|
|
||||||
}
|
|
||||||
Repeater {
|
|
||||||
id: optionRepeater
|
|
||||||
|
|
||||||
model: ListModel {
|
|
||||||
id: optionModel
|
|
||||||
|
|
||||||
readonly property bool allValuesSet: {
|
|
||||||
for( var i = 0; i < optionModel.rowCount(); i++ ) {
|
|
||||||
if (optionModel.get(i).optionText.length <= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ListElement {
|
|
||||||
optionText: ""
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
optionText: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
function values() {
|
|
||||||
let textValues = []
|
|
||||||
for( var i = 0; i < optionModel.rowCount(); i++ ) {
|
|
||||||
textValues.push(optionModel.get(i).optionText);
|
|
||||||
}
|
|
||||||
return textValues;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delegate: FormCard.AbstractFormDelegate {
|
|
||||||
id: optionDelegate
|
|
||||||
|
|
||||||
required property int index
|
|
||||||
required property string optionText
|
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
|
||||||
QQC2.Label {
|
|
||||||
id: optionLabel
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: i18nc("As in first answer option to the poll", "Option %1:", optionDelegate.index + 1)
|
|
||||||
elide: Text.ElideRight
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
Accessible.ignored: true
|
|
||||||
}
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
QQC2.TextField {
|
|
||||||
id: textField
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Accessible.name: optionLabel.text
|
|
||||||
onTextChanged: {
|
|
||||||
optionModel.set(optionDelegate.index, {optionText: text})
|
|
||||||
optionModel.allValuesSetChanged()
|
|
||||||
}
|
|
||||||
placeholderText: i18n("Enter option")
|
|
||||||
}
|
|
||||||
QQC2.ToolButton {
|
|
||||||
display: QQC2.AbstractButton.IconOnly
|
|
||||||
action: Kirigami.Action {
|
|
||||||
id: removeOptionAction
|
|
||||||
text: i18nc("@action:button", "Remove option")
|
|
||||||
icon.name: "edit-delete-remove"
|
|
||||||
onTriggered: optionModel.remove(optionDelegate.index)
|
|
||||||
}
|
|
||||||
QQC2.ToolTip {
|
|
||||||
text: removeOptionAction.text
|
|
||||||
delay: Kirigami.Units.toolTipDelay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
background: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Delegates.RoundedItemDelegate {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
horizontalPadding: Kirigami.Units.largeSpacing * 2
|
|
||||||
leftInset: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
|
||||||
rightInset: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
highlighted: true
|
|
||||||
|
|
||||||
icon.name: "list-add"
|
|
||||||
text: i18nc("@action:button", "Add option")
|
|
||||||
|
|
||||||
onClicked: optionModel.append({optionText: ""})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
import QtQuick.Layouts
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
import org.kde.neochat.settings
|
|
||||||
import org.kde.neochat.devtools
|
|
||||||
|
|
||||||
KirigamiComponents.ConvergentContextMenu {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property Kirigami.ApplicationWindow window
|
|
||||||
required property var author
|
|
||||||
|
|
||||||
headerContentItem: RowLayout {
|
|
||||||
id: detailRow
|
|
||||||
|
|
||||||
spacing: Kirigami.Units.largeSpacing
|
|
||||||
|
|
||||||
KirigamiComponents.Avatar {
|
|
||||||
id: avatar
|
|
||||||
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
|
|
||||||
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
|
|
||||||
|
|
||||||
name: root.author.displayName
|
|
||||||
source: root.author.avatarUrl
|
|
||||||
color: root.author.color
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Kirigami.Heading {
|
|
||||||
level: 1
|
|
||||||
Layout.fillWidth: true
|
|
||||||
font.bold: true
|
|
||||||
|
|
||||||
elide: Text.ElideRight
|
|
||||||
wrapMode: Text.NoWrap
|
|
||||||
text: root.author.displayName
|
|
||||||
textFormat: Text.PlainText
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Label {
|
|
||||||
id: idLabel
|
|
||||||
textFormat: TextEdit.PlainText
|
|
||||||
text: root.author.id
|
|
||||||
elide: Qt.ElideRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Action {
|
|
||||||
text: i18nc("@action:button", "Open Profile")
|
|
||||||
icon.name: "im-user-symbolic"
|
|
||||||
onTriggered: RoomManager.resolveResource(root.author.uri)
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Action {
|
|
||||||
text: i18nc("@action:button", "Mention")
|
|
||||||
icon.name: "username-copy-symbolic"
|
|
||||||
onTriggered: {
|
|
||||||
RoomManager.currentRoom.mainCache.mentionAdded(root.author.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Ritchie Frodomar <ritchie@kde.org>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#include "texttospeechhelper.h"
|
|
||||||
|
|
||||||
void TextToSpeechHelper::speak(const QString &textToSpeak)
|
|
||||||
{
|
|
||||||
if (!m_speech) {
|
|
||||||
m_speech = new QTextToSpeech();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_speech->say(textToSpeak);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_texttospeechhelper.cpp"
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Ritchie Frodomar <ritchie@kde.org>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QQmlEngine>
|
|
||||||
#include <QtTextToSpeech>
|
|
||||||
|
|
||||||
class TextToSpeechHelper : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
QML_ELEMENT
|
|
||||||
QML_SINGLETON
|
|
||||||
|
|
||||||
public:
|
|
||||||
Q_INVOKABLE void speak(const QString &textToSpeak);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QTextToSpeech *m_speech = nullptr;
|
|
||||||
};
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
# SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
# SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
qt_add_library(Chatbar STATIC)
|
qt_add_library(chatbar STATIC)
|
||||||
ecm_add_qml_module(Chatbar GENERATE_PLUGIN_SOURCE
|
ecm_add_qml_module(chatbar GENERATE_PLUGIN_SOURCE
|
||||||
URI org.kde.neochat.chatbar
|
URI org.kde.neochat.chatbar
|
||||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/chatbar
|
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/chatbar
|
||||||
QML_FILES
|
QML_FILES
|
||||||
@@ -15,5 +15,4 @@ ecm_add_qml_module(Chatbar GENERATE_PLUGIN_SOURCE
|
|||||||
EmojiPicker.qml
|
EmojiPicker.qml
|
||||||
EmojiDialog.qml
|
EmojiDialog.qml
|
||||||
EmojiTonesPicker.qml
|
EmojiTonesPicker.qml
|
||||||
ImageEditorPage.qml
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ import QtQuick.Controls as QQC2
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
import org.kde.neochat.libneochat as LibNeoChat
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A component for typing and sending chat messages.
|
* @brief A component for typing and sending chat messages.
|
||||||
@@ -55,19 +53,6 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: currentRoom.mainCache
|
|
||||||
|
|
||||||
function onMentionAdded(mention: string): void {
|
|
||||||
// add mention text
|
|
||||||
textField.append(mention + " ");
|
|
||||||
// move cursor to the end
|
|
||||||
textField.cursorPosition = textField.text.length;
|
|
||||||
// move the focus back to the chat bar
|
|
||||||
textField.forceActiveFocus(Qt.OtherFocusReason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The list of actions in the ChatBar.
|
* @brief The list of actions in the ChatBar.
|
||||||
*
|
*
|
||||||
@@ -116,7 +101,7 @@ QQC2.Control {
|
|||||||
},
|
},
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
id: mapButton
|
id: mapButton
|
||||||
icon.name: "mark-location-symbolic"
|
icon.name: "globe"
|
||||||
property bool isBusy: false
|
property bool isBusy: false
|
||||||
text: i18n("Send a Location")
|
text: i18n("Send a Location")
|
||||||
displayHint: QQC2.AbstractButton.IconOnly
|
displayHint: QQC2.AbstractButton.IconOnly
|
||||||
@@ -128,20 +113,6 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
tooltip: text
|
tooltip: text
|
||||||
},
|
},
|
||||||
Kirigami.Action {
|
|
||||||
id: pollButton
|
|
||||||
icon.name: "amarok_playcount"
|
|
||||||
property bool isBusy: false
|
|
||||||
text: i18nc("@action:button", "Create a Poll")
|
|
||||||
displayHint: QQC2.AbstractButton.IconOnly
|
|
||||||
|
|
||||||
onTriggered: {
|
|
||||||
newPollDialog.createObject(QQC2.Overlay.overlay, {
|
|
||||||
room: root.currentRoom
|
|
||||||
}).open();
|
|
||||||
}
|
|
||||||
tooltip: text
|
|
||||||
},
|
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
id: sendAction
|
id: sendAction
|
||||||
|
|
||||||
@@ -160,6 +131,11 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A message has been sent from the chat bar.
|
||||||
|
*/
|
||||||
|
signal messageSent
|
||||||
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||||
@@ -175,7 +151,7 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
|
|
||||||
leftPadding: rightPadding
|
leftPadding: rightPadding
|
||||||
rightPadding: (root.width - chatBarSizeHelper.availableWidth) / 2
|
rightPadding: (root.width - chatBarSizeHelper.currentWidth) / 2
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
|
|
||||||
@@ -187,26 +163,15 @@ QQC2.Control {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
Loader {
|
Loader {
|
||||||
id: replyLoader
|
id: paneLoader
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: Kirigami.Units.largeSpacing
|
Layout.margins: Kirigami.Units.largeSpacing
|
||||||
Layout.preferredHeight: active ? item.implicitHeight : 0
|
Layout.preferredHeight: active ? item.implicitHeight : 0
|
||||||
|
|
||||||
active: visible
|
active: visible
|
||||||
visible: root.currentRoom.mainCache.replyId.length > 0
|
visible: root.currentRoom.mainCache.replyId.length > 0 || root.currentRoom.mainCache.attachmentPath.length > 0
|
||||||
sourceComponent: replyPane
|
sourceComponent: root.currentRoom.mainCache.replyId.length > 0 ? replyPane : attachmentPane
|
||||||
}
|
|
||||||
Loader {
|
|
||||||
id: attachLoader
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.margins: Kirigami.Units.largeSpacing
|
|
||||||
Layout.preferredHeight: active ? item.implicitHeight : 0
|
|
||||||
|
|
||||||
active: visible
|
|
||||||
visible: root.currentRoom.mainCache.attachmentPath.length > 0
|
|
||||||
sourceComponent: attachmentPane
|
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
QQC2.ScrollView {
|
QQC2.ScrollView {
|
||||||
@@ -365,14 +330,15 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LibNeoChat.DelegateSizeHelper {
|
DelegateSizeHelper {
|
||||||
id: chatBarSizeHelper
|
id: chatBarSizeHelper
|
||||||
parentItem: root
|
|
||||||
startBreakpoint: Kirigami.Units.gridUnit * 46
|
startBreakpoint: Kirigami.Units.gridUnit * 46
|
||||||
endBreakpoint: Kirigami.Units.gridUnit * 66
|
endBreakpoint: Kirigami.Units.gridUnit * 66
|
||||||
startPercentWidth: 100
|
startPercentWidth: 100
|
||||||
endPercentWidth: NeoChatConfig.compactLayout ? 100 : 85
|
endPercentWidth: NeoChatConfig.compactLayout ? 100 : 85
|
||||||
maxWidth: NeoChatConfig.compactLayout ? root.width - Kirigami.Units.largeSpacing * 2 : Kirigami.Units.gridUnit * 60
|
maxWidth: NeoChatConfig.compactLayout ? -1 : Kirigami.Units.gridUnit * 60
|
||||||
|
|
||||||
|
parentWidth: root.width
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
@@ -384,11 +350,8 @@ QQC2.Control {
|
|||||||
id: replyComponent
|
id: replyComponent
|
||||||
replyEventId: _private.chatBarCache.replyId
|
replyEventId: _private.chatBarCache.replyId
|
||||||
replyAuthor: _private.chatBarCache.relationAuthor
|
replyAuthor: _private.chatBarCache.relationAuthor
|
||||||
replyContentModel: ContentProvider.contentModelForEvent(root.currentRoom, _private.chatBarCache.replyId, true)
|
replyContentModel: _private.chatBarCache.relationEventContentModel
|
||||||
Message.maxContentWidth: replyLoader.item.width
|
maxContentWidth: paneLoader.item.width
|
||||||
|
|
||||||
// When the user replies to a message and the preview is loaded, make sure the text field is focused again
|
|
||||||
Component.onCompleted: textField.forceActiveFocus(Qt.OtherFocusReason)
|
|
||||||
}
|
}
|
||||||
QQC2.Button {
|
QQC2.Button {
|
||||||
id: cancelButton
|
id: cancelButton
|
||||||
@@ -431,6 +394,7 @@ QQC2.Control {
|
|||||||
repeatTimer.stop();
|
repeatTimer.stop();
|
||||||
root.currentRoom.markAllMessagesAsRead();
|
root.currentRoom.markAllMessagesAsRead();
|
||||||
textField.clear();
|
textField.clear();
|
||||||
|
messageSent();
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatText(format, selectionStart, selectionEnd) {
|
function formatText(format, selectionStart, selectionEnd) {
|
||||||
@@ -519,11 +483,6 @@ QQC2.Control {
|
|||||||
LocationChooser {}
|
LocationChooser {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
|
||||||
id: newPollDialog
|
|
||||||
NewPollDialog {}
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletionMenu {
|
CompletionMenu {
|
||||||
id: completionMenu
|
id: completionMenu
|
||||||
chatDocumentHandler: documentHandler
|
chatDocumentHandler: documentHandler
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ QQC2.Popup {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
chatDocumentHandler.completionModel.roomListModel = RoomManager.roomListModel;
|
chatDocumentHandler.completionModel.roomListModel = RoomManager.roomListModel;
|
||||||
chatDocumentHandler.completionModel.userListModel = RoomManager.userListModel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function incrementIndex() {
|
function incrementIndex() {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ QQC2.Popup {
|
|||||||
property bool includeCustom: false
|
property bool includeCustom: false
|
||||||
property bool closeOnChosen: true
|
property bool closeOnChosen: true
|
||||||
property bool showQuickReaction: false
|
property bool showQuickReaction: false
|
||||||
property bool showStickers: true
|
|
||||||
|
|
||||||
signal chosen(string emoji)
|
signal chosen(string emoji)
|
||||||
|
|
||||||
@@ -72,7 +71,6 @@ QQC2.Popup {
|
|||||||
currentRoom: root.currentRoom
|
currentRoom: root.currentRoom
|
||||||
includeCustom: root.includeCustom
|
includeCustom: root.includeCustom
|
||||||
showQuickReaction: root.showQuickReaction
|
showQuickReaction: root.showQuickReaction
|
||||||
showStickers: root.showStickers
|
|
||||||
onChosen: emoji => {
|
onChosen: emoji => {
|
||||||
root.chosen(emoji);
|
root.chosen(emoji);
|
||||||
if (root.closeOnChosen) {
|
if (root.closeOnChosen) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ ColumnLayout {
|
|||||||
|
|
||||||
property bool includeCustom: false
|
property bool includeCustom: false
|
||||||
property bool showQuickReaction: false
|
property bool showQuickReaction: false
|
||||||
property bool showStickers: true
|
|
||||||
|
|
||||||
readonly property var currentEmojiModel: {
|
readonly property var currentEmojiModel: {
|
||||||
if (includeCustom) {
|
if (includeCustom) {
|
||||||
@@ -44,7 +43,6 @@ ColumnLayout {
|
|||||||
id: types
|
id: types
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||||
visible: root.showStickers
|
|
||||||
|
|
||||||
background: null
|
background: null
|
||||||
actions: [
|
actions: [
|
||||||
@@ -207,7 +205,7 @@ ColumnLayout {
|
|||||||
padding: Kirigami.Units.largeSpacing
|
padding: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
contentItem: Image {
|
contentItem: Image {
|
||||||
source: model.url
|
source: model.avatarUrl
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
sourceSize.width: width
|
sourceSize.width: width
|
||||||
sourceSize.height: height
|
sourceSize.height: height
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <Quotient/roommember.h>
|
#include <Quotient/roommember.h>
|
||||||
|
|
||||||
|
#include "chatdocumenthandler.h"
|
||||||
#include "eventhandler.h"
|
#include "eventhandler.h"
|
||||||
#include "models/actionsmodel.h"
|
#include "models/actionsmodel.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
@@ -87,6 +88,7 @@ void ChatBarCache::setReplyId(const QString &replyId)
|
|||||||
m_relationType = Reply;
|
m_relationType = Reply;
|
||||||
}
|
}
|
||||||
m_attachmentPath = QString();
|
m_attachmentPath = QString();
|
||||||
|
delete m_relationContentModel;
|
||||||
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
||||||
Q_EMIT attachmentPathChanged();
|
Q_EMIT attachmentPathChanged();
|
||||||
}
|
}
|
||||||
@@ -116,6 +118,7 @@ void ChatBarCache::setEditId(const QString &editId)
|
|||||||
m_relationType = Edit;
|
m_relationType = Edit;
|
||||||
}
|
}
|
||||||
m_attachmentPath = QString();
|
m_attachmentPath = QString();
|
||||||
|
delete m_relationContentModel;
|
||||||
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
||||||
Q_EMIT attachmentPathChanged();
|
Q_EMIT attachmentPathChanged();
|
||||||
}
|
}
|
||||||
@@ -158,6 +161,28 @@ QString ChatBarCache::relationMessage() const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageContentModel *ChatBarCache::relationEventContentModel()
|
||||||
|
{
|
||||||
|
if (parent() == nullptr) {
|
||||||
|
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (m_relationId.isEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (m_relationContentModel != nullptr) {
|
||||||
|
return m_relationContentModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 nullptr;
|
||||||
|
}
|
||||||
|
m_relationContentModel = new MessageContentModel(room, m_relationId, true);
|
||||||
|
return m_relationContentModel;
|
||||||
|
}
|
||||||
|
|
||||||
bool ChatBarCache::isThreaded() const
|
bool ChatBarCache::isThreaded() const
|
||||||
{
|
{
|
||||||
return !m_threadId.isEmpty();
|
return !m_threadId.isEmpty();
|
||||||
@@ -188,18 +213,11 @@ void ChatBarCache::setAttachmentPath(const QString &attachmentPath)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_attachmentPath = attachmentPath;
|
m_attachmentPath = attachmentPath;
|
||||||
Q_EMIT attachmentPathChanged();
|
|
||||||
|
|
||||||
#if (Quotient_VERSION_MINOR < 10 && Quotient_VERSION_PATCH < 3) || Quotient_VERSION_MINOR < 9
|
|
||||||
m_relationType = None;
|
m_relationType = None;
|
||||||
const auto oldEventId = std::exchange(m_relationId, QString());
|
const auto oldEventId = std::exchange(m_relationId, QString());
|
||||||
|
delete m_relationContentModel;
|
||||||
|
Q_EMIT attachmentPathChanged();
|
||||||
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
||||||
#else
|
|
||||||
if (m_relationType == Edit) {
|
|
||||||
const auto oldEventId = std::exchange(m_relationId, QString());
|
|
||||||
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatBarCache::clearRelations()
|
void ChatBarCache::clearRelations()
|
||||||
@@ -207,6 +225,7 @@ void ChatBarCache::clearRelations()
|
|||||||
const auto oldEventId = std::exchange(m_relationId, QString());
|
const auto oldEventId = std::exchange(m_relationId, QString());
|
||||||
const auto oldThreadId = std::exchange(m_threadId, QString());
|
const auto oldThreadId = std::exchange(m_threadId, QString());
|
||||||
m_attachmentPath = QString();
|
m_attachmentPath = QString();
|
||||||
|
delete m_relationContentModel;
|
||||||
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
Q_EMIT relationIdChanged(oldEventId, m_relationId);
|
||||||
Q_EMIT threadIdChanged(oldThreadId, m_threadId);
|
Q_EMIT threadIdChanged(oldThreadId, m_threadId);
|
||||||
Q_EMIT attachmentPathChanged();
|
Q_EMIT attachmentPathChanged();
|
||||||
@@ -217,6 +236,54 @@ QList<Mention> *ChatBarCache::mentions()
|
|||||||
return &m_mentions;
|
return &m_mentions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatBarCache::updateMentions(QQuickTextDocument *document, ChatDocumentHandler *documentHandler)
|
||||||
|
{
|
||||||
|
documentHandler->setDocument(document);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto event = room->findInTimeline(m_relationId); event != room->historyEdge()) {
|
||||||
|
if (const auto &roomMessageEvent = &*event->viewAs<Quotient::RoomMessageEvent>()) {
|
||||||
|
// Replaces the mentions that are baked into the HTML but plaintext in the original markdown
|
||||||
|
const QRegularExpression re(uR"lit(<a\shref="https:\/\/matrix.to\/#\/([\S]*)"\s?>([\S]*)<\/a>)lit"_s);
|
||||||
|
|
||||||
|
m_mentions.clear();
|
||||||
|
|
||||||
|
int linkSize = 0;
|
||||||
|
auto matches = re.globalMatch(EventHandler::rawMessageBody(*roomMessageEvent));
|
||||||
|
while (matches.hasNext()) {
|
||||||
|
const QRegularExpressionMatch match = matches.next();
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
const QString id = match.captured(1);
|
||||||
|
const QString name = match.captured(2);
|
||||||
|
|
||||||
|
const int position = match.capturedStart(0) - linkSize;
|
||||||
|
const int end = position + name.length();
|
||||||
|
linkSize += match.capturedLength(0) - name.length();
|
||||||
|
|
||||||
|
QTextCursor cursor(documentHandler->document()->textDocument());
|
||||||
|
cursor.setPosition(position);
|
||||||
|
cursor.setPosition(end, QTextCursor::KeepAnchor);
|
||||||
|
cursor.setKeepPositionOnInsert(true);
|
||||||
|
|
||||||
|
m_mentions.push_back(Mention{.cursor = cursor, .text = name, .start = position, .position = end, .id = id});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString ChatBarCache::savedText() const
|
QString ChatBarCache::savedText() const
|
||||||
{
|
{
|
||||||
return m_savedText;
|
return m_savedText;
|
||||||
@@ -235,19 +302,8 @@ void ChatBarCache::postMessage()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isReply = !replyId().isEmpty();
|
|
||||||
std::optional<Quotient::EventRelation> relatesTo = std::nullopt;
|
|
||||||
|
|
||||||
if (!threadId().isEmpty()) {
|
|
||||||
relatesTo = Quotient::EventRelation::replyInThread(threadId(), !isReply, isReply ? replyId() : threadId());
|
|
||||||
} else if (!editId().isEmpty()) {
|
|
||||||
relatesTo = Quotient::EventRelation::replace(editId());
|
|
||||||
} else if (isReply) {
|
|
||||||
relatesTo = Quotient::EventRelation::replyTo(replyId());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!attachmentPath().isEmpty()) {
|
if (!attachmentPath().isEmpty()) {
|
||||||
room->uploadFile(QUrl(attachmentPath()), sendText(), relatesTo);
|
room->uploadFile(QUrl(attachmentPath()), sendText());
|
||||||
clearCache();
|
clearCache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -265,12 +321,22 @@ void ChatBarCache::postMessage()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isReply = !replyId().isEmpty();
|
||||||
const auto replyIt = room->findInTimeline(replyId());
|
const auto replyIt = room->findInTimeline(replyId());
|
||||||
if (replyIt == room->historyEdge()) {
|
if (replyIt == room->historyEdge()) {
|
||||||
isReply = false;
|
isReply = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto content = std::make_unique<Quotient::EventContent::TextContent>(sendText, u"text/html"_s);
|
auto content = std::make_unique<Quotient::EventContent::TextContent>(sendText, u"text/html"_s);
|
||||||
|
std::optional<Quotient::EventRelation> relatesTo = std::nullopt;
|
||||||
|
|
||||||
|
if (!threadId().isEmpty()) {
|
||||||
|
relatesTo = Quotient::EventRelation::replyInThread(threadId(), !isReply, isReply ? replyId() : threadId());
|
||||||
|
} else if (!editId().isEmpty()) {
|
||||||
|
relatesTo = Quotient::EventRelation::replace(editId());
|
||||||
|
} else if (isReply) {
|
||||||
|
relatesTo = Quotient::EventRelation::replyTo(replyId());
|
||||||
|
}
|
||||||
|
|
||||||
room->post<Quotient::RoomMessageEvent>(text(), *std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result), std::move(content), relatesTo);
|
room->post<Quotient::RoomMessageEvent>(text(), *std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result), std::move(content), relatesTo);
|
||||||
clearCache();
|
clearCache();
|
||||||
@@ -8,11 +8,16 @@
|
|||||||
#include <QQuickTextDocument>
|
#include <QQuickTextDocument>
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
|
|
||||||
|
#include "models/messagecontentmodel.h"
|
||||||
|
|
||||||
|
class ChatDocumentHandler;
|
||||||
|
|
||||||
namespace Quotient
|
namespace Quotient
|
||||||
{
|
{
|
||||||
class RoomMember;
|
class RoomMember;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Defines a user mention in the current chat or edit text.
|
* @brief Defines a user mention in the current chat or edit text.
|
||||||
*/
|
*/
|
||||||
@@ -106,6 +111,13 @@ class ChatBarCache : public QObject
|
|||||||
*/
|
*/
|
||||||
Q_PROPERTY(QString relationMessage READ relationMessage NOTIFY relationIdChanged)
|
Q_PROPERTY(QString relationMessage READ relationMessage NOTIFY relationIdChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The MessageContentModel for the related message.
|
||||||
|
*
|
||||||
|
* Will be nullptr if no related message.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(MessageContentModel *relationEventContentModel READ relationEventContentModel NOTIFY relationIdChanged)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the chat bar is replying in a thread.
|
* @brief Whether the chat bar is replying in a thread.
|
||||||
*/
|
*/
|
||||||
@@ -155,6 +167,7 @@ public:
|
|||||||
Quotient::RoomMember relationAuthor() const;
|
Quotient::RoomMember relationAuthor() const;
|
||||||
|
|
||||||
QString relationMessage() const;
|
QString relationMessage() const;
|
||||||
|
MessageContentModel *relationEventContentModel();
|
||||||
|
|
||||||
bool isThreaded() const;
|
bool isThreaded() const;
|
||||||
QString threadId() const;
|
QString threadId() const;
|
||||||
@@ -175,6 +188,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
QList<Mention> *mentions();
|
QList<Mention> *mentions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the mentions in @p document when editing a message.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void updateMentions(QQuickTextDocument *document, ChatDocumentHandler *documentHandler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the saved chat bar text.
|
* @brief Get the saved chat bar text.
|
||||||
*/
|
*/
|
||||||
@@ -195,7 +213,6 @@ Q_SIGNALS:
|
|||||||
void relationIdChanged(const QString &oldEventId, const QString &newEventId);
|
void relationIdChanged(const QString &oldEventId, const QString &newEventId);
|
||||||
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
|
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
|
||||||
void attachmentPathChanged();
|
void attachmentPathChanged();
|
||||||
void mentionAdded(const QString &mention);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_text = QString();
|
QString m_text = QString();
|
||||||
@@ -208,5 +225,7 @@ private:
|
|||||||
QList<Mention> m_mentions;
|
QList<Mention> m_mentions;
|
||||||
QString m_savedText;
|
QString m_savedText;
|
||||||
|
|
||||||
|
QPointer<MessageContentModel> m_relationContentModel;
|
||||||
|
|
||||||
void clearCache();
|
void clearCache();
|
||||||
};
|
};
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
#include <Sonnet/Settings>
|
#include <Sonnet/Settings>
|
||||||
|
|
||||||
#include "chatdocumenthandler_logging.h"
|
#include "chatdocumenthandler_logging.h"
|
||||||
#include "eventhandler.h"
|
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
@@ -361,43 +360,4 @@ void ChatDocumentHandler::setErrorColor(const QColor &color)
|
|||||||
Q_EMIT errorColorChanged();
|
Q_EMIT errorColorChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatDocumentHandler::updateMentions(QQuickTextDocument *document, const QString &editId)
|
|
||||||
{
|
|
||||||
setDocument(document);
|
|
||||||
|
|
||||||
if (editId.isEmpty() || !m_chatBarCache || !m_room) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto event = m_room->findInTimeline(editId); event != m_room->historyEdge()) {
|
|
||||||
if (const auto &roomMessageEvent = &*event->viewAs<Quotient::RoomMessageEvent>()) {
|
|
||||||
// Replaces the mentions that are baked into the HTML but plaintext in the original markdown
|
|
||||||
const QRegularExpression re(uR"lit(<a\shref="https:\/\/matrix.to\/#\/([\S]*)"\s?>([\S]*)<\/a>)lit"_s);
|
|
||||||
|
|
||||||
m_chatBarCache->mentions()->clear();
|
|
||||||
|
|
||||||
int linkSize = 0;
|
|
||||||
auto matches = re.globalMatch(EventHandler::rawMessageBody(*roomMessageEvent));
|
|
||||||
while (matches.hasNext()) {
|
|
||||||
const QRegularExpressionMatch match = matches.next();
|
|
||||||
if (match.hasMatch()) {
|
|
||||||
const QString id = match.captured(1);
|
|
||||||
const QString name = match.captured(2);
|
|
||||||
|
|
||||||
const int position = match.capturedStart(0) - linkSize;
|
|
||||||
const int end = position + name.length();
|
|
||||||
linkSize += match.capturedLength(0) - name.length();
|
|
||||||
|
|
||||||
QTextCursor cursor(this->document()->textDocument());
|
|
||||||
cursor.setPosition(position);
|
|
||||||
cursor.setPosition(end, QTextCursor::KeepAnchor);
|
|
||||||
cursor.setKeepPositionOnInsert(true);
|
|
||||||
|
|
||||||
pushMention(Mention{.cursor = cursor, .text = name, .start = position, .position = end, .id = id});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_chatdocumenthandler.cpp"
|
#include "moc_chatdocumenthandler.cpp"
|
||||||
@@ -141,11 +141,6 @@ public:
|
|||||||
[[nodiscard]] QColor errorColor() const;
|
[[nodiscard]] QColor errorColor() const;
|
||||||
void setErrorColor(const QColor &color);
|
void setErrorColor(const QColor &color);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Update the mentions in @p document when editing a message.
|
|
||||||
*/
|
|
||||||
Q_INVOKABLE void updateMentions(QQuickTextDocument *document, const QString &editId);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void documentChanged();
|
void documentChanged();
|
||||||
void cursorPositionChanged();
|
void cursorPositionChanged();
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
ColorSchemer::ColorSchemer(QObject *parent)
|
ColorSchemer::ColorSchemer(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
KColorSchemeManager::instance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorSchemer::~ColorSchemer()
|
ColorSchemer::~ColorSchemer()
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user