Compare commits
1 Commits
release/25
...
work/nvrwh
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df53e15a57 |
@@ -1,2 +0,0 @@
|
|||||||
[General]
|
|
||||||
disableUnqualifiedAccess = "i18nc,xi18nc,i18ncp,i18n"
|
|
||||||
@@ -2,5 +2,7 @@
|
|||||||
; SPDX-License-Identifier: CC0-1.0
|
; SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
[BlueprintSettings]
|
[BlueprintSettings]
|
||||||
|
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.7",
|
||||||
"sdk": "org.kde.Sdk",
|
"sdk": "org.kde.Sdk",
|
||||||
"command": "neochat",
|
"command": "neochat",
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -20,52 +20,18 @@
|
|||||||
"--talk-name=org.kde.kwalletd5",
|
"--talk-name=org.kde.kwalletd5",
|
||||||
"--talk-name=org.kde.StatusNotifierWatcher",
|
"--talk-name=org.kde.StatusNotifierWatcher",
|
||||||
"--talk-name=org.freedesktop.secrets",
|
"--talk-name=org.freedesktop.secrets",
|
||||||
"--talk-name=org.kde.kuiserver",
|
|
||||||
"--own-name=org.kde.StatusNotifierItem-2-2"
|
"--own-name=org.kde.StatusNotifierItem-2-2"
|
||||||
],
|
],
|
||||||
"cleanup": [
|
|
||||||
"/include",
|
|
||||||
"/lib/*.a",
|
|
||||||
"/lib/cmake",
|
|
||||||
"/lib/pkgconfig",
|
|
||||||
"/share/ndk-modules"
|
|
||||||
],
|
|
||||||
"modules": [
|
"modules": [
|
||||||
{
|
{
|
||||||
"name": "kirigamiaddons",
|
"name": "kirigamiaddons",
|
||||||
"config-opts": [
|
"config-opts": [ "-DBUILD_TESTING=OFF" ],
|
||||||
"-DBUILD_TESTING=OFF"
|
|
||||||
],
|
|
||||||
"buildsystem": "cmake-ninja",
|
"buildsystem": "cmake-ninja",
|
||||||
"sources": [
|
"sources": [ { "type": "git", "url": "https://invent.kde.org/libraries/kirigami-addons.git", "commit": "34d311219e8b7209746a98b3a29b91ded05ff936" } ]
|
||||||
{
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://invent.kde.org/libraries/kirigami-addons.git"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "opencv",
|
|
||||||
"config-opts": [
|
|
||||||
"-DBUILD_TESTS=OFF",
|
|
||||||
"-DWITH_GTK=OFF",
|
|
||||||
"-DBUILD_LIST=core,imgproc"
|
|
||||||
],
|
|
||||||
"buildsystem": "cmake-ninja",
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/opencv/opencv"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"builddir": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "kquickimageeditor",
|
"name": "kquickimageeditor",
|
||||||
"config-opts": [
|
"config-opts": [ "-DBUILD_WITH_QT6=ON" ],
|
||||||
"-DBUILD_WITH_QT6=ON",
|
|
||||||
"-DBUILD_TESTING=OFF"
|
|
||||||
],
|
|
||||||
"buildsystem": "cmake-ninja",
|
"buildsystem": "cmake-ninja",
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
@@ -77,19 +43,17 @@
|
|||||||
{
|
{
|
||||||
"name": "olm",
|
"name": "olm",
|
||||||
"buildsystem": "cmake-ninja",
|
"buildsystem": "cmake-ninja",
|
||||||
"config-opts": [
|
"config-opts": [ "-DOLM_TESTS=OFF" ],
|
||||||
"-DOLM_TESTS=OFF"
|
|
||||||
],
|
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitlab.matrix.org/matrix-org/olm.git",
|
"url": "https://gitlab.matrix.org/matrix-org/olm.git",
|
||||||
"tag": "3.2.16",
|
"tag": "3.2.10",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"tag-pattern": "^([\\d.]+)$"
|
"tag-pattern": "^([\\d.]+)$"
|
||||||
},
|
},
|
||||||
"commit": "7e0c8277032e40308987257b711b38af8d77cc69"
|
"commit": "9908862979147a71dc6abaecd521be526ae77be1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -101,13 +65,13 @@
|
|||||||
"-Dvapi=false",
|
"-Dvapi=false",
|
||||||
"-Dgtk_doc=false",
|
"-Dgtk_doc=false",
|
||||||
"-Dintrospection=false",
|
"-Dintrospection=false",
|
||||||
"-Dcrypto=disabled"
|
"-Dgcrypt=false"
|
||||||
],
|
],
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.7.tar.xz",
|
"url": "https://download.gnome.org/sources/libsecret/0.20/libsecret-0.20.5.tar.xz",
|
||||||
"sha256": "6b452e4750590a2b5617adc40026f28d2f4903de15f1250e1d1c40bfd68ed55e",
|
"sha256": "3fb3ce340fcd7db54d87c893e69bfc2b1f6e4d4b279065ffe66dac9f0fd12b4d",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "gnome",
|
"type": "gnome",
|
||||||
"name": "libsecret",
|
"name": "libsecret",
|
||||||
@@ -122,13 +86,13 @@
|
|||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://github.com/frankosterfeld/qtkeychain/archive/refs/tags/0.15.0.tar.gz",
|
"url": "https://github.com/frankosterfeld/qtkeychain/archive/0.14.2.tar.gz",
|
||||||
"sha256": "f4254dc8f0933b06d90672d683eab08ef770acd8336e44dfa030ce041dc2ca22",
|
"sha256": "cf2e972b783ba66334a79a30f6b3a1ea794a1dc574d6c3bebae5ffd2f0399571",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "anitya",
|
"type": "anitya",
|
||||||
"project-id": 4138,
|
"project-id": 4138,
|
||||||
"stable-only": true,
|
"stable-only": true,
|
||||||
"url-template": "https://github.com/frankosterfeld/qtkeychain/archive/refs/tags/$version.tar.gz"
|
"url-template": "https://github.com/frankosterfeld/qtkeychain/archive/v$version.tar.gz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -136,8 +100,7 @@
|
|||||||
"-DBUILD_WITH_QT6=ON",
|
"-DBUILD_WITH_QT6=ON",
|
||||||
"-DCMAKE_INSTALL_LIBDIR=/app/lib",
|
"-DCMAKE_INSTALL_LIBDIR=/app/lib",
|
||||||
"-DLIB_INSTALL_DIR=/app/lib",
|
"-DLIB_INSTALL_DIR=/app/lib",
|
||||||
"-DBUILD_TRANSLATIONS=NO",
|
"-DBUILD_TRANSLATIONS=NO"
|
||||||
"-DBUILD_TESTING=OFF"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -147,7 +110,7 @@
|
|||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/quotient-im/libQuotient.git",
|
"url": "https://github.com/quotient-im/libQuotient.git",
|
||||||
"branch": "0.9.6.1",
|
"branch": "dev",
|
||||||
"disable-submodules": true
|
"disable-submodules": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -160,37 +123,34 @@
|
|||||||
{
|
{
|
||||||
"name": "cmark",
|
"name": "cmark",
|
||||||
"buildsystem": "cmake-ninja",
|
"buildsystem": "cmake-ninja",
|
||||||
"config-opts": [
|
"config-opts": [ "-DCMARK_TESTS=OFF" ],
|
||||||
"-DCMARK_TESTS=OFF",
|
|
||||||
"-DCMAKE_BUILD_TYPE=Release",
|
|
||||||
"-DCMAKE_INSTALL_PREFIX=/app"
|
|
||||||
],
|
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/commonmark/cmark.git"
|
"url": "https://github.com/commonmark/cmark.git"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"config-opts": [
|
||||||
|
"-DCMARK_TESTS=OFF",
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
|
"-DCMAKE_INSTALL_PREFIX=/app"
|
||||||
|
],
|
||||||
"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" ],
|
||||||
"config-opts": [
|
|
||||||
"-DENABLE_TESTING=OFF",
|
|
||||||
"-DKUNIFIEDPUSH_CLIENT_ONLY=ON"
|
|
||||||
],
|
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://download.kde.org/stable/release-service/25.08.0/src/kunifiedpush-25.08.0.tar.xz",
|
"url": "https://github.com/danvratil/qcoro/archive/refs/tags/v0.7.0.tar.gz",
|
||||||
"sha256": "846db6ffc7d93f6afea7ce0d5a9f10b52792157ceb593856542279f4197f3518",
|
"sha256": "23ef0217926e67c8d2eb861cf91617da2f7d8d5a9ae6c62321b21448b1669210",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "anitya",
|
"type": "anitya",
|
||||||
"project-id": 8763,
|
"project-id": 236236,
|
||||||
"stable-only": true,
|
"stable-only": true,
|
||||||
"url-template": "https://download.kde.org/stable/release-service/$version/src/kunifiedpush-$version.tar.xz"
|
"url-template": "https://github.com/danvratil/qcoro/archive/refs/tags/v$version.tar.gz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -198,15 +158,14 @@
|
|||||||
{
|
{
|
||||||
"name": "neochat",
|
"name": "neochat",
|
||||||
"buildsystem": "cmake-ninja",
|
"buildsystem": "cmake-ninja",
|
||||||
"config-opts": [
|
|
||||||
"-DBUILD_TESTING=OFF",
|
|
||||||
"-DNEOCHAT_FLATPAK=ON"
|
|
||||||
],
|
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "dir",
|
"type": "dir",
|
||||||
"path": "."
|
"path": "."
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"config-opts": [
|
||||||
|
"-DNEOCHAT_FLATPAK=ON"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,14 +5,10 @@ include:
|
|||||||
- project: sysadmin/ci-utilities
|
- project: sysadmin/ci-utilities
|
||||||
file:
|
file:
|
||||||
- /gitlab-templates/reuse-lint.yml
|
- /gitlab-templates/reuse-lint.yml
|
||||||
- /gitlab-templates/json-validation.yml
|
|
||||||
- /gitlab-templates/xml-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/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
|
||||||
|
|||||||
72
.kde-ci.yml
72
.kde-ci.yml
@@ -2,44 +2,42 @@
|
|||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
- 'on': ['Linux', 'Android', 'FreeBSD', 'Windows']
|
- 'on': ['Linux', 'Android', 'FreeBSD', 'Windows']
|
||||||
'require':
|
'require':
|
||||||
'frameworks/extra-cmake-modules': '@latest-kf6'
|
'frameworks/extra-cmake-modules': '@latest-kf6'
|
||||||
'frameworks/kcoreaddons': '@latest-kf6'
|
'frameworks/kcoreaddons': '@latest-kf6'
|
||||||
'frameworks/kirigami': '@latest-kf6'
|
'frameworks/kirigami': '@latest-kf6'
|
||||||
'frameworks/ki18n': '@latest-kf6'
|
'frameworks/ki18n': '@latest-kf6'
|
||||||
'frameworks/kconfig': '@latest-kf6'
|
'frameworks/kconfig': '@latest-kf6'
|
||||||
'frameworks/syntax-highlighting': '@latest-kf6'
|
'frameworks/syntax-highlighting': '@latest-kf6'
|
||||||
'frameworks/kiconthemes': '@latest-kf6'
|
'frameworks/kitemmodels': '@latest-kf6'
|
||||||
'frameworks/kitemmodels': '@latest-kf6'
|
'frameworks/kquickcharts': '@latest-kf6'
|
||||||
'frameworks/kquickcharts': '@latest-kf6'
|
'frameworks/knotifications': '@latest-kf6'
|
||||||
'frameworks/knotifications': '@latest-kf6'
|
'frameworks/kcolorscheme': '@latest-kf6'
|
||||||
'frameworks/kcolorscheme': '@latest-kf6'
|
'libraries/kquickimageeditor': '@latest-kf6'
|
||||||
'libraries/kquickimageeditor': '@latest-kf6'
|
'frameworks/sonnet': '@latest-kf6'
|
||||||
'frameworks/sonnet': '@latest-kf6'
|
'frameworks/prison': '@latest-kf6'
|
||||||
'frameworks/prison': '@latest-kf6'
|
'libraries/kirigami-addons': '@latest-kf6'
|
||||||
'libraries/kirigami-addons': '@latest-kf6'
|
'third-party/libquotient': '@latest'
|
||||||
'third-party/libquotient': '@latest'
|
'third-party/qtkeychain': '@latest'
|
||||||
'third-party/qtkeychain': '@latest'
|
'third-party/cmark': '@latest'
|
||||||
'third-party/cmark': '@latest'
|
'third-party/qcoro': '@latest'
|
||||||
'third-party/qcoro': '@latest'
|
- 'on': ['Windows', 'Linux', 'FreeBSD']
|
||||||
- 'on': ['Windows', 'Linux', 'FreeBSD']
|
'require':
|
||||||
'require':
|
'frameworks/qqc2-desktop-style': '@latest-kf6'
|
||||||
'frameworks/qqc2-desktop-style': '@latest-kf6'
|
'frameworks/kio': '@latest-kf6'
|
||||||
'frameworks/kio': '@latest-kf6'
|
'frameworks/kwindowsystem': '@latest-kf6'
|
||||||
'frameworks/kwindowsystem': '@latest-kf6'
|
'frameworks/kstatusnotifieritem': '@latest-kf6'
|
||||||
'frameworks/kstatusnotifieritem': '@latest-kf6'
|
'frameworks/kcrash': '@latest-kf6'
|
||||||
- 'on': ['Linux', 'FreeBSD']
|
- 'on': ['Linux', 'FreeBSD']
|
||||||
'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':
|
||||||
'sdk/selenium-webdriver-at-spi': '@latest-kf6'
|
'sdk/selenium-webdriver-at-spi': '@latest-kf6'
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
per-test-timeout: 90
|
per-test-timeout: 90
|
||||||
require-passing-tests-on: ['Linux', 'Android', 'FreeBSD', 'Windows']
|
require-passing-tests-on: [ 'Linux', 'Android', 'FreeBSD', 'Windows' ]
|
||||||
run-qmllint: True
|
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ 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 "12")
|
set(RELEASE_SERVICE_VERSION_MINOR "03")
|
||||||
set(RELEASE_SERVICE_VERSION_MICRO "3")
|
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||||
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.17")
|
set(KF_MIN_VERSION "6.6")
|
||||||
set(QT_MIN_VERSION "6.9")
|
set(QT_MIN_VERSION "6.5")
|
||||||
|
|
||||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
|||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
set(KDE_COMPILERSETTINGS_LEVEL 6.17)
|
set(KDE_COMPILERSETTINGS_LEVEL 6.0)
|
||||||
|
|
||||||
include(FeatureSummary)
|
include(FeatureSummary)
|
||||||
include(ECMSetupVersion)
|
include(ECMSetupVersion)
|
||||||
@@ -39,7 +39,6 @@ include(ECMCheckOutboundLicense)
|
|||||||
include(ECMQtDeclareLoggingCategory)
|
include(ECMQtDeclareLoggingCategory)
|
||||||
include(ECMAddAndroidApk)
|
include(ECMAddAndroidApk)
|
||||||
include(ECMQmlModule)
|
include(ECMQmlModule)
|
||||||
include(ECMDeprecationSettings)
|
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
include(ECMGenerateHeaders)
|
include(ECMGenerateHeaders)
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
@@ -52,14 +51,12 @@ endif()
|
|||||||
|
|
||||||
set(QUOTIENT_FORCE_NAMESPACED_INCLUDES TRUE)
|
set(QUOTIENT_FORCE_NAMESPACED_INCLUDES TRUE)
|
||||||
|
|
||||||
ecm_set_disabled_deprecation_versions(Qt 6.9.0 KF 6.17.0)
|
|
||||||
|
|
||||||
ecm_setup_version(${PROJECT_VERSION}
|
ecm_setup_version(${PROJECT_VERSION}
|
||||||
VARIABLE_PREFIX NEOCHAT
|
VARIABLE_PREFIX NEOCHAT
|
||||||
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"
|
||||||
@@ -69,7 +66,7 @@ if (QT_KNOWN_POLICY_QTP0004)
|
|||||||
qt_policy(SET QTP0004 NEW)
|
qt_policy(SET QTP0004 NEW)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme IconThemes)
|
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
|
||||||
set_package_properties(KF6 PROPERTIES
|
set_package_properties(KF6 PROPERTIES
|
||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
PURPOSE "Basic application components"
|
PURPOSE "Basic application components"
|
||||||
@@ -78,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.10.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)
|
||||||
@@ -92,7 +89,7 @@ if(ANDROID)
|
|||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
|
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
|
||||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem)
|
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem Crash)
|
||||||
find_package(KF6SyntaxHighlighting ${KF_MIN_VERSION} REQUIRED)
|
find_package(KF6SyntaxHighlighting ${KF_MIN_VERSION} REQUIRED)
|
||||||
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
|
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
|
||||||
TYPE RUNTIME
|
TYPE RUNTIME
|
||||||
@@ -110,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.3)
|
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"
|
||||||
@@ -150,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)
|
||||||
@@ -182,12 +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)
|
|
||||||
add_subdirectory(memorytests)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(KF6DocTools_FOUND)
|
if(KF6DocTools_FOUND)
|
||||||
@@ -195,7 +181,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)
|
||||||
|
|||||||
16
REUSE.toml
16
REUSE.toml
@@ -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"
|
||||||
@@ -82,15 +82,3 @@ path = "src/purpose/purposeplugin.json"
|
|||||||
precedence = "aggregate"
|
precedence = "aggregate"
|
||||||
SPDX-FileCopyrightText = "2023 Tobias Fella <tobias.fella@kde.org>"
|
SPDX-FileCopyrightText = "2023 Tobias Fella <tobias.fella@kde.org>"
|
||||||
SPDX-License-Identifier = "BSD-2-Clause"
|
SPDX-License-Identifier = "BSD-2-Clause"
|
||||||
|
|
||||||
[[annotations]]
|
|
||||||
path = "memorytests/memtest-sync.json"
|
|
||||||
precedence = "aggregate"
|
|
||||||
SPDX-FileCopyrightText = "2024 James Graham <james.h.graham@protonmail.com>"
|
|
||||||
SPDX-License-Identifier = "BSD-2-Clause"
|
|
||||||
|
|
||||||
[[annotations]]
|
|
||||||
path = ".contextProperties.ini"
|
|
||||||
precedence = "aggregate"
|
|
||||||
SPDX-FileCopyrightText = "2025 Tobias Fella <tobias.fella@kde.org>"
|
|
||||||
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,18 +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
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_add_test(
|
|
||||||
servernoticestest.cpp
|
|
||||||
LINK_LIBRARIES neochat Qt::Test neochat_server
|
|
||||||
TEST_NAME servernoticestest
|
|
||||||
)
|
|
||||||
|
|
||||||
ecm_add_test(
|
|
||||||
roommanagertest.cpp
|
|
||||||
LINK_LIBRARIES neochat Qt::Test neochat_server
|
|
||||||
TEST_NAME roommanagertest
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -63,7 +44,7 @@ void ActionsTest::testActions_data()
|
|||||||
QTest::addColumn<std::optional<QString>>("resultText");
|
QTest::addColumn<std::optional<QString>>("resultText");
|
||||||
QTest::addColumn<std::optional<Quotient::RoomMessageEvent::MsgType>>("type");
|
QTest::addColumn<std::optional<Quotient::RoomMessageEvent::MsgType>>("type");
|
||||||
|
|
||||||
QTest::newRow("shrug") << u"/shrug Hello"_s << std::make_optional(u"¯\\\\\\_(ツ)\\_/¯ Hello"_s)
|
QTest::newRow("shrug") << u"/shrug Hello"_s << std::make_optional(u"¯\\\\_(ツ)_/¯ Hello"_s)
|
||||||
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||||
QTest::newRow("lenny") << u"/lenny Hello"_s << std::make_optional(u"( ͡° ͜ʖ ͡°) Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
QTest::newRow("lenny") << u"/lenny Hello"_s << std::make_optional(u"( ͡° ͜ʖ ͡°) Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||||
QTest::newRow("tableflip") << u"/tableflip Hello"_s << std::make_optional(u"(╯°□°)╯︵ ┻━┻ Hello"_s)
|
QTest::newRow("tableflip") << u"/tableflip Hello"_s << std::make_optional(u"(╯°□°)╯︵ ┻━┻ Hello"_s)
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
|
||||||
#include <QSignalSpy>
|
|
||||||
#include <Quotient/roommember.h>
|
#include <Quotient/roommember.h>
|
||||||
#include <Quotient/syncdata.h>
|
#include <Quotient/syncdata.h>
|
||||||
#include <qtestcase.h>
|
#include <qtestcase.h>
|
||||||
@@ -33,7 +32,6 @@ private Q_SLOTS:
|
|||||||
void noRoom();
|
void noRoom();
|
||||||
void badParent();
|
void badParent();
|
||||||
void reply();
|
void reply();
|
||||||
void replyMissingUser();
|
|
||||||
void edit();
|
void edit();
|
||||||
void attachment();
|
void attachment();
|
||||||
};
|
};
|
||||||
@@ -104,33 +102,6 @@ void ChatBarCacheTest::reply()
|
|||||||
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
|
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
|
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||||
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatBarCacheTest::replyMissingUser()
|
|
||||||
{
|
|
||||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
|
||||||
chatBarCache->setText(u"some text"_s);
|
|
||||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
|
||||||
chatBarCache->setReplyId(u"$153456789:example.org"_s);
|
|
||||||
|
|
||||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
|
||||||
QCOMPARE(chatBarCache->isReplying(), true);
|
|
||||||
QCOMPARE(chatBarCache->replyId(), u"$153456789:example.org"_s);
|
|
||||||
QCOMPARE(chatBarCache->isEditing(), false);
|
|
||||||
QCOMPARE(chatBarCache->editId(), QString());
|
|
||||||
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
|
|
||||||
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
|
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
|
||||||
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
|
|
||||||
|
|
||||||
QSignalSpy relationAuthorIsPresentSpy(chatBarCache.get(), &ChatBarCache::relationAuthorIsPresentChanged);
|
|
||||||
|
|
||||||
// sync again, which will simulate the reply user leaving the room
|
|
||||||
room->syncNewEvents(u"test-min-sync-extra-sync.json"_s);
|
|
||||||
|
|
||||||
QTRY_COMPARE(relationAuthorIsPresentSpy.count(), 1);
|
|
||||||
QCOMPARE(chatBarCache->relationAuthorIsPresent(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatBarCacheTest::edit()
|
void ChatBarCacheTest::edit()
|
||||||
|
|||||||
@@ -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-----
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"state": {
|
|
||||||
"events": [
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"membership": "leave"
|
|
||||||
},
|
|
||||||
"event_id": "$1432735824666PhrSA:example.org",
|
|
||||||
"origin_server_ts": 1432735824666,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "@example:example.org",
|
|
||||||
"state_key": "@example:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"replaces_state": "$143273582443PhrSn:example.org"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -130,8 +130,7 @@ void EventHandlerTest::timeString()
|
|||||||
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().time(), QLocale::ShortFormat));
|
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().time(), QLocale::ShortFormat));
|
||||||
QCOMPARE(EventHandler::timeString(room, event, true),
|
QCOMPARE(EventHandler::timeString(room, event, true),
|
||||||
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().date(), QLocale::ShortFormat));
|
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().date(), QLocale::ShortFormat));
|
||||||
QCOMPARE(EventHandler::timeString(room, event, u"hh:mm"_s),
|
QCOMPARE(EventHandler::timeString(room, event, u"hh:mm"_s), QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toString(u"hh:mm"_s));
|
||||||
QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::LocalTime)).toString(u"hh:mm"_s));
|
|
||||||
|
|
||||||
const auto txID = room->postJson("m.room.message"_L1, event->fullJson());
|
const auto txID = room->postJson("m.room.message"_L1, event->fullJson());
|
||||||
QCOMPARE(room->pendingEvents().size(), 1);
|
QCOMPARE(room->pendingEvents().size(), 1);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -10,9 +10,8 @@
|
|||||||
#include <Quotient/roommember.h>
|
#include <Quotient/roommember.h>
|
||||||
#include <Quotient/syncdata.h>
|
#include <Quotient/syncdata.h>
|
||||||
|
|
||||||
#include "models/eventmessagecontentmodel.h"
|
#include "models/messagecontentmodel.h"
|
||||||
|
|
||||||
#include "neochatconnection.h"
|
|
||||||
#include "testutils.h"
|
#include "testutils.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -33,23 +32,23 @@ 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()
|
||||||
{
|
{
|
||||||
auto room = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
auto room = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
||||||
auto model1 = EventMessageContentModel(room, u"$153456789:example.org"_s);
|
auto model1 = MessageContentModel(room, u"$153456789:example.org"_s);
|
||||||
|
|
||||||
QCOMPARE(model1.rowCount(), 1);
|
QCOMPARE(model1.rowCount(), 1);
|
||||||
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
||||||
QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading…"_s);
|
QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading"_s);
|
||||||
|
|
||||||
auto model2 = EventMessageContentModel(room, u"$153456789:example.org"_s, true);
|
auto model2 = MessageContentModel(room, u"$153456789:example.org"_s, true);
|
||||||
|
|
||||||
QCOMPARE(model2.rowCount(), 1);
|
QCOMPARE(model2.rowCount(), 1);
|
||||||
QCOMPARE(model2.data(model2.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
QCOMPARE(model2.data(model2.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
||||||
QCOMPARE(model2.data(model2.index(0), MessageContentModel::DisplayRole), u"Loading reply…"_s);
|
QCOMPARE(model2.data(model2.index(0), MessageContentModel::DisplayRole), u"Loading reply"_s);
|
||||||
|
|
||||||
room->syncNewEvents(u"test-min-sync.json"_s);
|
room->syncNewEvents(u"test-min-sync.json"_s);
|
||||||
QCOMPARE(model1.rowCount(), 2);
|
QCOMPARE(model1.rowCount(), 2);
|
||||||
|
|||||||
@@ -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/eventmessagecontentmodel.h"
|
|
||||||
#include "testutils.h"
|
#include "testutils.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -21,11 +20,11 @@ class ReactionModelTest : public QObject
|
|||||||
private:
|
private:
|
||||||
Connection *connection = nullptr;
|
Connection *connection = nullptr;
|
||||||
TestUtils::TestRoom *room = nullptr;
|
TestUtils::TestRoom *room = nullptr;
|
||||||
EventMessageContentModel *parentModel;
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
|
|
||||||
|
void nullModel();
|
||||||
void basicReaction();
|
void basicReaction();
|
||||||
void newReaction();
|
void newReaction();
|
||||||
};
|
};
|
||||||
@@ -34,13 +33,20 @@ void ReactionModelTest::initTestCase()
|
|||||||
{
|
{
|
||||||
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||||
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-reactionmodel-sync.json"_s);
|
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-reactionmodel-sync.json"_s);
|
||||||
parentModel = new EventMessageContentModel(room, "123456"_L1);
|
}
|
||||||
|
|
||||||
|
void ReactionModelTest::nullModel()
|
||||||
|
{
|
||||||
|
auto model = ReactionModel(nullptr, nullptr);
|
||||||
|
|
||||||
|
QCOMPARE(model.rowCount(), 0);
|
||||||
|
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), QVariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReactionModelTest::basicReaction()
|
void ReactionModelTest::basicReaction()
|
||||||
{
|
{
|
||||||
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
|
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
|
||||||
auto model = ReactionModel(parentModel, event->id(), room);
|
auto model = ReactionModel(event, room);
|
||||||
|
|
||||||
QCOMPARE(model.rowCount(), 1);
|
QCOMPARE(model.rowCount(), 1);
|
||||||
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), u"<span style=\"font-family: 'emoji';\">👍</span>"_s);
|
QCOMPARE(model.data(model.index(0), ReactionModel::TextContentRole), u"<span style=\"font-family: 'emoji';\">👍</span>"_s);
|
||||||
@@ -52,7 +58,7 @@ void ReactionModelTest::basicReaction()
|
|||||||
void ReactionModelTest::newReaction()
|
void ReactionModelTest::newReaction()
|
||||||
{
|
{
|
||||||
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
|
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
|
||||||
auto model = new ReactionModel(parentModel, event->id(), room);
|
auto model = new ReactionModel(event, room);
|
||||||
|
|
||||||
QCOMPARE(model->rowCount(), 1);
|
QCOMPARE(model->rowCount(), 1);
|
||||||
QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole), u"Alice Margatroid reacted with <span style=\"font-family: 'emoji';\">👍</span>"_s);
|
QCOMPARE(model->data(model->index(0), ReactionModel::ToolTipRole), u"Alice Margatroid reacted with <span style=\"font-family: 'emoji';\">👍</span>"_s);
|
||||||
|
|||||||
@@ -1,141 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QSignalSpy>
|
|
||||||
#include <QTest>
|
|
||||||
#include <QVariantList>
|
|
||||||
|
|
||||||
#include "accountmanager.h"
|
|
||||||
#include "models/actionsmodel.h"
|
|
||||||
#include "roommanager.h"
|
|
||||||
|
|
||||||
#include "server.h"
|
|
||||||
#include "testutils.h"
|
|
||||||
|
|
||||||
using namespace Quotient;
|
|
||||||
|
|
||||||
class RoomManagerTest : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
private:
|
|
||||||
NeoChatConnection *connection = nullptr;
|
|
||||||
NeoChatRoom *room = nullptr;
|
|
||||||
|
|
||||||
Server server;
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void initTestCase();
|
|
||||||
void testMaximizeMedia();
|
|
||||||
void testResolveMatrixLinks();
|
|
||||||
};
|
|
||||||
|
|
||||||
void RoomManagerTest::initTestCase()
|
|
||||||
{
|
|
||||||
Connection::setRoomType<NeoChatRoom>();
|
|
||||||
server.start();
|
|
||||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
|
||||||
auto accountManager = new AccountManager(true);
|
|
||||||
QSignalSpy spy(accountManager, &AccountManager::connectionAdded);
|
|
||||||
connection = dynamic_cast<NeoChatConnection *>(accountManager->accounts()->front());
|
|
||||||
QVERIFY(connection);
|
|
||||||
auto roomId = server.createRoom(u"@user:localhost:1234"_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);
|
|
||||||
RoomManager::instance().setConnection(connection);
|
|
||||||
QSignalSpy roomSpy(&RoomManager::instance(), &RoomManager::currentRoomChanged);
|
|
||||||
RoomManager::instance().resolveResource(room->id());
|
|
||||||
QVERIFY(roomSpy.size() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoomManagerTest::testMaximizeMedia()
|
|
||||||
{
|
|
||||||
QSignalSpy spy(&RoomManager::instance(), &RoomManager::showMaximizedMedia);
|
|
||||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
|
||||||
|
|
||||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Tried to open media for empty event id");
|
|
||||||
RoomManager::instance().maximizeMedia(QString());
|
|
||||||
QVERIFY(!spy.wait(10));
|
|
||||||
|
|
||||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Tried to open media for unknown event id \"Doesn't exist\"");
|
|
||||||
RoomManager::instance().maximizeMedia(u"Doesn't exist"_s);
|
|
||||||
QVERIFY(!spy.wait(10));
|
|
||||||
|
|
||||||
const auto eventWithoutMedia = server.sendEvent(room->id(),
|
|
||||||
u"m.room.message"_s,
|
|
||||||
QJsonObject({
|
|
||||||
{u"body"_s, u"Foo"_s},
|
|
||||||
{u"format"_s, u"org.matrix.custom.html"_s},
|
|
||||||
{u"formatted_body"_s, u"Foo"_s},
|
|
||||||
{u"msgtype"_s, u"m.text"_s},
|
|
||||||
}));
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, u"Tried to open media for unknown event id \"%1\""_s.arg(eventWithoutMedia).toLatin1().data());
|
|
||||||
RoomManager::instance().maximizeMedia(eventWithoutMedia);
|
|
||||||
QVERIFY(!spy.wait(10));
|
|
||||||
|
|
||||||
// NOTE: This is supposed to test that maximizing pending media works correctly. This probably doesn't work in the UI yet, but at least the backend supports
|
|
||||||
// it. If the server ever learns how to process events, this becomes pointless and we need to find a way of preventing *these* events from arriving
|
|
||||||
auto pendingEventWithoutMedia = room->postText(u"Hello"_s);
|
|
||||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, u"Tried to open media for unknown event id \"%1\""_s.arg(pendingEventWithoutMedia).toLatin1().data());
|
|
||||||
RoomManager::instance().maximizeMedia(pendingEventWithoutMedia);
|
|
||||||
QVERIFY(!spy.wait(10));
|
|
||||||
|
|
||||||
const auto eventWithMedia = server.sendEvent(room->id(),
|
|
||||||
u"m.room.message"_s,
|
|
||||||
QJsonObject({
|
|
||||||
{u"body"_s, u"Foo"_s},
|
|
||||||
{u"filename"_s, u"foo.jpg"_s},
|
|
||||||
{u"info"_s,
|
|
||||||
QJsonObject{
|
|
||||||
{u"h"_s, 1000},
|
|
||||||
{u"w"_s, 2000},
|
|
||||||
{u"size"_s, 10000},
|
|
||||||
{u"mimetype"_s, u"image/png"_s},
|
|
||||||
}},
|
|
||||||
{u"msgtype"_s, u"m.image"_s},
|
|
||||||
{u"url"_s, u"mxc://foo.bar/asdf"_s},
|
|
||||||
}));
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
RoomManager::instance().maximizeMedia(eventWithMedia);
|
|
||||||
QVERIFY(spy.size() == 1);
|
|
||||||
QVERIFY(spy[0][0] == 0);
|
|
||||||
|
|
||||||
auto pendingEventWithMedia = room->postJson(u"m.room.message"_s,
|
|
||||||
QJsonObject({
|
|
||||||
{u"body"_s, u"Foo"_s},
|
|
||||||
{u"filename"_s, u"foo.jpg"_s},
|
|
||||||
{u"info"_s,
|
|
||||||
QJsonObject{
|
|
||||||
{u"h"_s, 1000},
|
|
||||||
{u"w"_s, 2000},
|
|
||||||
{u"size"_s, 10000},
|
|
||||||
{u"mimetype"_s, u"image/png"_s},
|
|
||||||
}},
|
|
||||||
{u"msgtype"_s, u"m.image"_s},
|
|
||||||
{u"url"_s, u"mxc://foo.bar/asdf"_s},
|
|
||||||
}));
|
|
||||||
RoomManager::instance().maximizeMedia(pendingEventWithMedia);
|
|
||||||
QVERIFY(spy.size() == 2);
|
|
||||||
QVERIFY(spy[1][0] == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoomManagerTest::testResolveMatrixLinks()
|
|
||||||
{
|
|
||||||
// Test if resolving a non-joined room will bring up the confirmation dialog.
|
|
||||||
const QSignalSpy askToJoinSpy(&RoomManager::instance(), &RoomManager::askJoinRoom);
|
|
||||||
RoomManager::instance().resolveResource(QStringLiteral("matrix:r/testbuild:matrix.org"), QStringLiteral("join"));
|
|
||||||
QTRY_COMPARE(askToJoinSpy.size(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
QTEST_MAIN(RoomManagerTest)
|
|
||||||
#include "roommanagertest.moc"
|
|
||||||
@@ -1,371 +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 <QHttpServerResponder>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QSslCertificate>
|
|
||||||
#include <QSslKey>
|
|
||||||
#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) {
|
|
||||||
Changes changes;
|
|
||||||
changes.invitations += Changes::InviteUser{
|
|
||||||
.userId = QJsonDocument::fromJson(request.body()).object()[u"user_id"_s].toString(),
|
|
||||||
.roomId = roomId,
|
|
||||||
};
|
|
||||||
m_state += changes;
|
|
||||||
responder.write(QJsonDocument(QJsonObject{}), QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
|
||||||
|
|
||||||
m_server.route(u"/_matrix/client/r0/sync"_s, QHttpServerRequest::Method::Get, this, &Server::sync);
|
|
||||||
|
|
||||||
QSslConfiguration config;
|
|
||||||
QFile key(QStringLiteral(DATA_DIR) + u"/localhost.key"_s);
|
|
||||||
void(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)
|
|
||||||
{
|
|
||||||
const auto roomId = generateRoomId();
|
|
||||||
Changes changes;
|
|
||||||
changes.newRooms += Changes::NewRoom{
|
|
||||||
.initialMembers = {matrixId},
|
|
||||||
.roomId = {roomId},
|
|
||||||
.tags = {},
|
|
||||||
};
|
|
||||||
m_state += changes;
|
|
||||||
return roomId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::inviteUser(const QString &roomId, const QString &matrixId)
|
|
||||||
{
|
|
||||||
Changes changes;
|
|
||||||
changes.invitations += Changes::InviteUser{
|
|
||||||
.userId = matrixId,
|
|
||||||
.roomId = roomId,
|
|
||||||
};
|
|
||||||
m_state += changes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::banUser(const QString &roomId, const QString &matrixId)
|
|
||||||
{
|
|
||||||
Changes changes;
|
|
||||||
changes.bans += Changes::BanUser{
|
|
||||||
.userId = matrixId,
|
|
||||||
.roomId = roomId,
|
|
||||||
};
|
|
||||||
m_state += changes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::joinUser(const QString &roomId, const QString &matrixId)
|
|
||||||
{
|
|
||||||
Changes changes;
|
|
||||||
changes.joins += Changes::JoinUser{
|
|
||||||
.userId = matrixId,
|
|
||||||
.roomId = roomId,
|
|
||||||
};
|
|
||||||
m_state += changes;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Server::createServerNoticesRoom(const QString &matrixId)
|
|
||||||
{
|
|
||||||
const auto roomId = generateRoomId();
|
|
||||||
Changes changes;
|
|
||||||
changes.newRooms += Changes::NewRoom{
|
|
||||||
.initialMembers = {matrixId},
|
|
||||||
.roomId = {roomId},
|
|
||||||
.tags = {u"m.server_notice"_s},
|
|
||||||
};
|
|
||||||
m_state += changes;
|
|
||||||
return roomId;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Server::sendEvent(const QString &roomId, const QString &eventType, const QJsonObject &content)
|
|
||||||
{
|
|
||||||
Changes changes;
|
|
||||||
const auto eventId = generateEventId();
|
|
||||||
changes.events += Changes::Event{
|
|
||||||
.fullJson = QJsonObject{{u"type"_s, eventType},
|
|
||||||
{u"content"_s, content},
|
|
||||||
{u"sender"_s, u"@foo:server.com"_s},
|
|
||||||
{u"event_id"_s, eventId},
|
|
||||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
|
||||||
{u"room_id"_s, roomId}},
|
|
||||||
};
|
|
||||||
m_state += changes;
|
|
||||||
return eventId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::sync(const QHttpServerRequest &request, QHttpServerResponder &responder)
|
|
||||||
{
|
|
||||||
QJsonObject joinRooms;
|
|
||||||
auto token = request.query().queryItemValue(u"since"_s).toInt();
|
|
||||||
|
|
||||||
for (const auto &change : m_state.mid(token)) {
|
|
||||||
for (const auto &newRoom : change.newRooms) {
|
|
||||||
QJsonArray stateEvents;
|
|
||||||
stateEvents += 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, newRoom.roomId},
|
|
||||||
{u"sender"_s, newRoom.initialMembers[0]},
|
|
||||||
{u"state_key"_s, QString()},
|
|
||||||
{u"type"_s, u"m.room.create"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
for (const auto &member : newRoom.initialMembers) {
|
|
||||||
stateEvents += 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, newRoom.roomId},
|
|
||||||
{u"sender"_s, member},
|
|
||||||
{u"state_key"_s, member},
|
|
||||||
{u"type"_s, u"m.room.member"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto room = QJsonObject{{u"state"_s, QJsonObject{{u"events"_s, stateEvents}}}};
|
|
||||||
|
|
||||||
QJsonArray roomAccountData;
|
|
||||||
QJsonObject tags;
|
|
||||||
for (const auto &tag : newRoom.tags) {
|
|
||||||
tags[tag] = QJsonObject();
|
|
||||||
}
|
|
||||||
if (!tags.empty()) {
|
|
||||||
roomAccountData += QJsonObject{{u"type"_s, u"m.tag"_s}, {u"content"_s, QJsonObject{{u"tags"_s, tags}}}};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (roomAccountData.size() > 0) {
|
|
||||||
room[u"account_data"] = QJsonObject{{u"events"_s, roomAccountData}};
|
|
||||||
}
|
|
||||||
|
|
||||||
joinRooms[newRoom.roomId] = room;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &change : m_state.mid(token)) {
|
|
||||||
for (const auto &invitation : change.invitations) {
|
|
||||||
// TODO: The invitation could be for a room we haven't joined yet. Shouldn't be necessary for now, though.
|
|
||||||
auto stateEvents = joinRooms[invitation.roomId][u"state"_s][u"events"_s].toArray();
|
|
||||||
stateEvents += 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, invitation.roomId},
|
|
||||||
{u"sender"_s, u"@user:localhost:1234"_s},
|
|
||||||
{u"state_key"_s, invitation.userId},
|
|
||||||
{u"type"_s, u"m.room.member"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
if (joinRooms.contains(invitation.roomId)) {
|
|
||||||
auto room = joinRooms[invitation.roomId].toObject();
|
|
||||||
room[u"state"_s] = QJsonObject{{u"events"_s, stateEvents}};
|
|
||||||
joinRooms[invitation.roomId] = room;
|
|
||||||
} else {
|
|
||||||
joinRooms[invitation.roomId] = QJsonObject{{u"state"_s,
|
|
||||||
QJsonObject{
|
|
||||||
{u"events"_s, stateEvents},
|
|
||||||
}}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &change : m_state.mid(token)) {
|
|
||||||
for (const auto &ban : change.bans) {
|
|
||||||
// TODO: The ban could be for a room we haven't joined yet. Shouldn't be necessary for now, though.
|
|
||||||
auto stateEvents = joinRooms[ban.roomId][u"state"_s][u"events"_s].toArray();
|
|
||||||
stateEvents += 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, ban.roomId},
|
|
||||||
{u"sender"_s, u"@user:localhost:1234"_s},
|
|
||||||
{u"state_key"_s, ban.userId},
|
|
||||||
{u"type"_s, u"m.room.member"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
if (joinRooms.contains(ban.roomId)) {
|
|
||||||
auto room = joinRooms[ban.roomId].toObject();
|
|
||||||
room[u"state"_s] = QJsonObject{{u"events"_s, stateEvents}};
|
|
||||||
joinRooms[ban.roomId] = room;
|
|
||||||
} else {
|
|
||||||
joinRooms[ban.roomId] = QJsonObject{{u"state"_s,
|
|
||||||
QJsonObject{
|
|
||||||
{u"events"_s, stateEvents},
|
|
||||||
}}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &change : m_state.mid(token)) {
|
|
||||||
for (const auto &join : change.joins) {
|
|
||||||
// TODO: The join could be for a room we haven't joined yet. Shouldn't be necessary for now, though.
|
|
||||||
auto stateEvents = joinRooms[join.roomId][u"state"_s][u"events"_s].toArray();
|
|
||||||
stateEvents += 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, join.roomId},
|
|
||||||
{u"sender"_s, u"@user:localhost:1234"_s},
|
|
||||||
{u"state_key"_s, join.userId},
|
|
||||||
{u"type"_s, u"m.room.member"_s},
|
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
|
||||||
};
|
|
||||||
if (joinRooms.contains(join.roomId)) {
|
|
||||||
auto room = joinRooms[join.roomId].toObject();
|
|
||||||
room[u"state"_s] = QJsonObject{{u"events"_s, stateEvents}};
|
|
||||||
joinRooms[join.roomId] = room;
|
|
||||||
} else {
|
|
||||||
joinRooms[join.roomId] = QJsonObject{{u"state"_s,
|
|
||||||
QJsonObject{
|
|
||||||
{u"events"_s, stateEvents},
|
|
||||||
}}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &change : m_state.mid(token)) {
|
|
||||||
for (const auto &event : change.events) {
|
|
||||||
// TODO the room might be in a different join state.
|
|
||||||
auto timeline = joinRooms[event.fullJson[u"room_id"_s].toString()][u"timeline"_s][u"events"_s].toArray();
|
|
||||||
timeline += event.fullJson;
|
|
||||||
if (joinRooms.contains(event.fullJson[u"room_id"_s].toString())) {
|
|
||||||
auto room = joinRooms[event.fullJson[u"room_id"_s].toString()].toObject();
|
|
||||||
room[u"timeline"_s] = QJsonObject{{u"events"_s, timeline}};
|
|
||||||
joinRooms[event.fullJson[u"room_id"_s].toString()] = room;
|
|
||||||
} else {
|
|
||||||
joinRooms[event.fullJson[u"room_id"_s].toString()] = QJsonObject{
|
|
||||||
{u"timeline"_s, QJsonObject{{u"events"_s, timeline}}},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject syncData = {
|
|
||||||
// {u"account_data"_s, QJsonObject {}},
|
|
||||||
// {u"presence"_s, QJsonObject {}},
|
|
||||||
{u"next_batch"_s, QString::number(m_state.size())},
|
|
||||||
};
|
|
||||||
|
|
||||||
QJsonObject rooms;
|
|
||||||
if (!joinRooms.isEmpty()) {
|
|
||||||
rooms[u"join"_s] = joinRooms;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rooms.empty()) {
|
|
||||||
syncData[u"rooms"_s] = rooms;
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << syncData;
|
|
||||||
responder.write(QJsonDocument(syncData), QHttpServerResponder::StatusCode::Ok);
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <QHttpServer>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QSslServer>
|
|
||||||
|
|
||||||
struct Changes {
|
|
||||||
struct NewRoom {
|
|
||||||
QStringList initialMembers;
|
|
||||||
QString roomId;
|
|
||||||
QStringList tags;
|
|
||||||
};
|
|
||||||
QList<NewRoom> newRooms;
|
|
||||||
|
|
||||||
struct InviteUser {
|
|
||||||
QString userId;
|
|
||||||
QString roomId;
|
|
||||||
};
|
|
||||||
QList<InviteUser> invitations;
|
|
||||||
|
|
||||||
struct BanUser {
|
|
||||||
QString userId;
|
|
||||||
QString roomId;
|
|
||||||
};
|
|
||||||
QList<BanUser> bans;
|
|
||||||
|
|
||||||
struct JoinUser {
|
|
||||||
QString userId;
|
|
||||||
QString roomId;
|
|
||||||
};
|
|
||||||
QList<JoinUser> joins;
|
|
||||||
|
|
||||||
struct Event {
|
|
||||||
QJsonObject fullJson;
|
|
||||||
};
|
|
||||||
QList<Event> events;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RoomData {
|
|
||||||
QStringList members;
|
|
||||||
QString id;
|
|
||||||
QStringList tags;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Server : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a server notices room.
|
|
||||||
*/
|
|
||||||
QString createServerNoticesRoom(const QString &matrixId);
|
|
||||||
QString sendEvent(const QString &roomId, const QString &eventType, const QJsonObject &content);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QHttpServer m_server;
|
|
||||||
QSslServer m_sslServer;
|
|
||||||
|
|
||||||
void sync(const QHttpServerRequest &request, QHttpServerResponder &responder);
|
|
||||||
|
|
||||||
QList<Changes> m_state;
|
|
||||||
};
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QSignalSpy>
|
|
||||||
#include <QTest>
|
|
||||||
|
|
||||||
#include <KLocalizedString>
|
|
||||||
|
|
||||||
#include <Quotient/connection.h>
|
|
||||||
#include <Quotient/eventstats.h>
|
|
||||||
#include <Quotient/quotient_common.h>
|
|
||||||
#include <Quotient/syncdata.h>
|
|
||||||
|
|
||||||
#include "accountmanager.h"
|
|
||||||
#include "neochatroom.h"
|
|
||||||
#include "roommanager.h"
|
|
||||||
#include "server.h"
|
|
||||||
|
|
||||||
#include "testutils.h"
|
|
||||||
|
|
||||||
using namespace Quotient;
|
|
||||||
|
|
||||||
class ServerNoticesTest : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
private:
|
|
||||||
NeoChatConnection *connection = nullptr;
|
|
||||||
Server server;
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void initTestCase();
|
|
||||||
void test();
|
|
||||||
};
|
|
||||||
|
|
||||||
void ServerNoticesTest::initTestCase()
|
|
||||||
{
|
|
||||||
Connection::setRoomType<NeoChatRoom>();
|
|
||||||
server.start();
|
|
||||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
|
||||||
auto accountManager = new AccountManager(true);
|
|
||||||
QSignalSpy spy(accountManager, &AccountManager::connectionAdded);
|
|
||||||
connection = dynamic_cast<NeoChatConnection *>(accountManager->accounts()->front());
|
|
||||||
QVERIFY(connection);
|
|
||||||
auto roomId = server.createRoom(u"@user:localhost:1234"_s);
|
|
||||||
RoomManager::instance().setConnection(connection);
|
|
||||||
|
|
||||||
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());
|
|
||||||
auto room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
|
|
||||||
QVERIFY(room);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerNoticesTest::test()
|
|
||||||
{
|
|
||||||
auto roomTreeModel = RoomManager::instance().roomTreeModel();
|
|
||||||
QCOMPARE(roomTreeModel->rowCount(roomTreeModel->index(NeoChatRoomType::ServerNotice, 0)), 0);
|
|
||||||
auto sortFilterRoomTreeModel = RoomManager::instance().sortFilterRoomTreeModel();
|
|
||||||
const auto roomId = server.createServerNoticesRoom(u"@user:localhost:1234"_s);
|
|
||||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
const auto room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
|
|
||||||
QVERIFY(connection->room(roomId)->isServerNoticeRoom());
|
|
||||||
QCOMPARE(roomTreeModel->rowCount(roomTreeModel->index(NeoChatRoomType::ServerNotice, 0)), 1);
|
|
||||||
QCOMPARE(sortFilterRoomTreeModel->mapFromSource(roomTreeModel->indexForRoom(room)).parent().row(), 1 /* Below the normal room */);
|
|
||||||
server.sendEvent(roomId,
|
|
||||||
u"m.room.message"_s,
|
|
||||||
QJsonObject{
|
|
||||||
{u"body"_s, u"Foo"_s},
|
|
||||||
{u"format"_s, u"org.matrix.custom.html"_s},
|
|
||||||
{u"formatted_body"_s, u"Foo"_s},
|
|
||||||
{u"msgtype"_s, u"m.text"_s},
|
|
||||||
});
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
sortFilterRoomTreeModel->invalidate();
|
|
||||||
QCOMPARE(sortFilterRoomTreeModel->mapFromSource(roomTreeModel->indexForRoom(room)).parent().row(), 0);
|
|
||||||
room->markAllMessagesAsRead();
|
|
||||||
QCOMPARE(sortFilterRoomTreeModel->mapFromSource(roomTreeModel->indexForRoom(room)).parent().row(), 1 /* Below the normal room */);
|
|
||||||
}
|
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN(ServerNoticesTest)
|
|
||||||
#include "servernoticestest.moc"
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
#include <QTest>
|
|
||||||
#include <Quotient/events/event.h>
|
#include <Quotient/events/event.h>
|
||||||
#include <Quotient/syncdata.h>
|
#include <Quotient/syncdata.h>
|
||||||
|
|
||||||
@@ -33,7 +32,7 @@ public:
|
|||||||
if (!syncFileName.isEmpty()) {
|
if (!syncFileName.isEmpty()) {
|
||||||
QFile testSyncFile;
|
QFile testSyncFile;
|
||||||
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
|
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
|
||||||
Q_UNUSED(testSyncFile.open(QIODevice::ReadOnly));
|
testSyncFile.open(QIODevice::ReadOnly);
|
||||||
const auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
|
const auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
|
||||||
Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson.object());
|
Quotient::SyncRoomData roomData(id(), Quotient::JoinState::Join, testSyncJson.object());
|
||||||
update(std::move(roomData));
|
update(std::move(roomData));
|
||||||
@@ -47,7 +46,7 @@ inline Quotient::event_ptr_tt<EventT> loadEventFromFile(const QString &eventFile
|
|||||||
if (!eventFileName.isEmpty()) {
|
if (!eventFileName.isEmpty()) {
|
||||||
QFile testEventFile;
|
QFile testEventFile;
|
||||||
testEventFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + eventFileName);
|
testEventFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + eventFileName);
|
||||||
Q_UNUSED(testEventFile.open(QIODevice::ReadOnly));
|
testEventFile.open(QIODevice::ReadOnly);
|
||||||
auto testSyncJson = QJsonDocument::fromJson(testEventFile.readAll()).object();
|
auto testSyncJson = QJsonDocument::fromJson(testEventFile.readAll()).object();
|
||||||
return Quotient::loadEvent<EventT>(testSyncJson);
|
return Quotient::loadEvent<EventT>(testSyncJson);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -34,10 +33,6 @@ private Q_SLOTS:
|
|||||||
void stripDisallowedTags();
|
void stripDisallowedTags();
|
||||||
void stripDisallowedAttributes();
|
void stripDisallowedAttributes();
|
||||||
void emptyCodeTags();
|
void emptyCodeTags();
|
||||||
void addStyle_data();
|
|
||||||
void addStyle();
|
|
||||||
void dontAddStyle_data();
|
|
||||||
void dontAddStyle();
|
|
||||||
|
|
||||||
void sendSimpleStringCase();
|
void sendSimpleStringCase();
|
||||||
void sendSingleParaMarkup();
|
void sendSingleParaMarkup();
|
||||||
@@ -48,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();
|
||||||
@@ -65,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();
|
||||||
@@ -75,9 +67,6 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
void componentOutput_data();
|
void componentOutput_data();
|
||||||
void componentOutput();
|
void componentOutput();
|
||||||
|
|
||||||
void updateSpoiler_data();
|
|
||||||
void updateSpoiler();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void TextHandlerTest::initTestCase()
|
void TextHandlerTest::initTestCase()
|
||||||
@@ -96,26 +85,21 @@ void TextHandlerTest::initTestCase()
|
|||||||
|
|
||||||
void TextHandlerTest::allowedAttributes()
|
void TextHandlerTest::allowedAttributes()
|
||||||
{
|
{
|
||||||
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
|
||||||
const QString testInputString1 = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
|
const QString testInputString1 = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
|
||||||
const QString testOutputString1S = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
|
const QString testOutputString1 = u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
|
||||||
const QString testOutputString1R = u"<span data-mx-spoiler style=\"color: transparent; background: %1;\"><font color=#FFFFFF>Test</font><span>"_s.arg(
|
|
||||||
theme->alternateBackgroundColor().name());
|
|
||||||
// Handle urls where the href has either single (') or double (") quotes.
|
// Handle urls where the href has either single (') or double (") quotes.
|
||||||
const QString testInputString2 = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s;
|
const QString testInputString2 = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s;
|
||||||
const QString testOutputString2S = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s;
|
const QString testOutputString2 = u"<a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a>"_s;
|
||||||
const QString testOutputString2R =
|
|
||||||
u"<a href=\"https://kde.org\" style=\"text-decoration: none;\">link</a><a href='https://kde.org' style=\"text-decoration: none;\">link</a>"_s;
|
|
||||||
|
|
||||||
TextHandler testTextHandler;
|
TextHandler testTextHandler;
|
||||||
testTextHandler.setData(testInputString1);
|
testTextHandler.setData(testInputString1);
|
||||||
|
|
||||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString1S);
|
QCOMPARE(testTextHandler.handleSendText(), testOutputString1);
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString1R);
|
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString1);
|
||||||
|
|
||||||
testTextHandler.setData(testInputString2);
|
testTextHandler.setData(testInputString2);
|
||||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString2S);
|
QCOMPARE(testTextHandler.handleSendText(), testOutputString2);
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString2R);
|
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::stripDisallowedTags()
|
void TextHandlerTest::stripDisallowedTags()
|
||||||
@@ -158,56 +142,6 @@ void TextHandlerTest::emptyCodeTags()
|
|||||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::addStyle_data()
|
|
||||||
{
|
|
||||||
QTest::addColumn<QString>("testInputString");
|
|
||||||
QTest::addColumn<QString>("testOutputString");
|
|
||||||
|
|
||||||
QTest::newRow("link") << u"<a href=\"https://kde.org\">link</a>"_s << u"<a href=\"https://kde.org\" style=\"text-decoration: none;\">link</a>"_s;
|
|
||||||
QTest::newRow("table")
|
|
||||||
<< u"<table><tr><th>Company</th><th>Contact</th><th>Country</th></tr><tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr><tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr></table>"_s
|
|
||||||
<< u"<table style=\"width: 100%; border-collapse: collapse; border: 1px; border-style: solid;\"><tr><th style=\"border: 1px solid black; padding: 3px;\">Company</th><th style=\"border: 1px solid black; padding: 3px;\">Contact</th><th style=\"border: 1px solid black; padding: 3px;\">Country</th></tr><tr><td style=\"border: 1px solid black; padding: 3px;\">Alfreds Futterkiste</td><td style=\"border: 1px solid black; padding: 3px;\">Maria Anders</td><td style=\"border: 1px solid black; padding: 3px;\">Germany</td></tr><tr><td style=\"border: 1px solid black; padding: 3px;\">Centro comercial Moctezuma</td><td style=\"border: 1px solid black; padding: 3px;\">Francisco Chang</td><td style=\"border: 1px solid black; padding: 3px;\">Mexico</td></tr></table>"_s;
|
|
||||||
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
|
||||||
QTest::newRow("spoiler") << u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s
|
|
||||||
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\"><font color=#FFFFFF>Test</font><span>"_s.arg(
|
|
||||||
theme->alternateBackgroundColor().name());
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextHandlerTest::addStyle()
|
|
||||||
{
|
|
||||||
QFETCH(QString, testInputString);
|
|
||||||
QFETCH(QString, testOutputString);
|
|
||||||
|
|
||||||
TextHandler testTextHandler;
|
|
||||||
testTextHandler.setData(testInputString);
|
|
||||||
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextHandlerTest::dontAddStyle_data()
|
|
||||||
{
|
|
||||||
QTest::addColumn<QString>("testInputString");
|
|
||||||
QTest::addColumn<QString>("testOutputString");
|
|
||||||
|
|
||||||
QTest::newRow("link") << u"<a href=\"https://kde.org\">link</a>"_s << u"<a href=\"https://kde.org\">link</a>"_s;
|
|
||||||
QTest::newRow("table")
|
|
||||||
<< u"<table><tr><th>Company</th><th>Contact</th><th>Country</th></tr><tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr><tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr></table>"_s
|
|
||||||
<< u"<table><tr><th>Company</th><th>Contact</th><th>Country</th></tr><tr><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>Germany</td></tr><tr><td>Centro comercial Moctezuma</td><td>Francisco Chang</td><td>Mexico</td></tr></table>"_s;
|
|
||||||
QTest::newRow("spoiler") << u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s
|
|
||||||
<< u"<span data-mx-spoiler><font color=#FFFFFF>Test</font><span>"_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextHandlerTest::dontAddStyle()
|
|
||||||
{
|
|
||||||
QFETCH(QString, testInputString);
|
|
||||||
QFETCH(QString, testOutputString);
|
|
||||||
|
|
||||||
TextHandler testTextHandler;
|
|
||||||
testTextHandler.setData(testInputString);
|
|
||||||
|
|
||||||
QCOMPARE(testTextHandler.handleSendText(), testOutputString);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextHandlerTest::sendSimpleStringCase()
|
void TextHandlerTest::sendSimpleStringCase()
|
||||||
{
|
{
|
||||||
const QString testInputString = u"This data should just be left alone."_s;
|
const QString testInputString = u"This data should just be left alone."_s;
|
||||||
@@ -315,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;
|
||||||
@@ -400,8 +300,7 @@ void TextHandlerTest::receiveRichInPlainOut()
|
|||||||
void TextHandlerTest::receivePlainTextIn()
|
void TextHandlerTest::receivePlainTextIn()
|
||||||
{
|
{
|
||||||
const QString testInputString = u"<plain text in tag bracket>\nTest link https://kde.org."_s;
|
const QString testInputString = u"<plain text in tag bracket>\nTest link https://kde.org."_s;
|
||||||
const QString testOutputStringRich =
|
const QString testOutputStringRich = u"<plain text in tag bracket><br>Test link <a href=\"https://kde.org\">https://kde.org</a>."_s;
|
||||||
u"<plain text in tag bracket><br>Test link <a href=\"https://kde.org\" style=\"text-decoration: none;\">https://kde.org</a>."_s;
|
|
||||||
QString testOutputStringPlain = u"<plain text in tag bracket>\nTest link https://kde.org."_s;
|
QString testOutputStringPlain = u"<plain text in tag bracket>\nTest link https://kde.org."_s;
|
||||||
|
|
||||||
// Make sure quotes are maintained in a plain string.
|
// Make sure quotes are maintained in a plain string.
|
||||||
@@ -471,7 +370,7 @@ void TextHandlerTest::receivePlainStripMarkup()
|
|||||||
void TextHandlerTest::receiveRichUserPill()
|
void TextHandlerTest::receiveRichUserPill()
|
||||||
{
|
{
|
||||||
const QString testInputString = u"<p><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></p>"_s;
|
const QString testInputString = u"<p><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></p>"_s;
|
||||||
const QString testOutputString = u"<b><a href=\"https://matrix.to/#/@alice:example.org\" style=\"text-decoration: none;\">@alice:example.org</a></b>"_s;
|
const QString testOutputString = u"<b><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></b>"_s;
|
||||||
|
|
||||||
TextHandler testTextHandler;
|
TextHandler testTextHandler;
|
||||||
testTextHandler.setData(testInputString);
|
testTextHandler.setData(testInputString);
|
||||||
@@ -514,34 +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\" style=\"text-decoration: none;\">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\" style=\"text-decoration: none;\">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/\" style=\"text-decoration: none;\">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" style="text-decoration: none;">email@example.com</a> <a href="mailto:email@example.com" style="text-decoration: none;">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\" style=\"text-decoration: none;\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\" style=\"text-decoration: none;\">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\" style=\"text-decoration: none;\">@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.
|
||||||
*
|
*
|
||||||
@@ -550,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()
|
||||||
@@ -564,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()
|
||||||
@@ -610,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,9 +530,6 @@ void TextHandlerTest::componentOutput_data()
|
|||||||
QTest::newRow("quote") << u"<p>Text</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>"_s
|
QTest::newRow("quote") << u"<p>Text</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>"_s
|
||||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
|
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
|
||||||
MessageComponent{MessageComponentType::Quote, u"“blockquote”"_s, {}}};
|
MessageComponent{MessageComponentType::Quote, u"“blockquote”"_s, {}}};
|
||||||
QTest::newRow("multiple paragraph quote") << u"<blockquote>\n<p>blockquote</p>\n<p>next paragraph</p>\n</blockquote>"_s
|
|
||||||
<< QList<MessageComponent>{
|
|
||||||
MessageComponent{MessageComponentType::Quote, u"<p>“blockquote</p>\n<p>next paragraph”</p>"_s, {}}};
|
|
||||||
QTest::newRow("no tag first paragraph") << u"Text\n<p>Text</p>"_s
|
QTest::newRow("no tag first paragraph") << u"Text\n<p>Text</p>"_s
|
||||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
|
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, u"Text"_s, {}},
|
||||||
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
|
MessageComponent{MessageComponentType::Text, u"Text"_s, {}}};
|
||||||
@@ -661,35 +561,5 @@ void TextHandlerTest::componentOutput()
|
|||||||
QCOMPARE(testTextHandler.textComponents(testInputString), testOutputComponents);
|
QCOMPARE(testTextHandler.textComponents(testInputString), testOutputComponents);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::updateSpoiler_data()
|
|
||||||
{
|
|
||||||
QTest::addColumn<QString>("testInputString");
|
|
||||||
QTest::addColumn<QString>("testOutputString");
|
|
||||||
QTest::addColumn<bool>("spoilerRevealed");
|
|
||||||
|
|
||||||
auto theme = static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
|
||||||
QTest::newRow("same length") << u"<span data-mx-spoiler style=\"color: #123456; background: #123456;\">Test<span>"_s
|
|
||||||
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\">Test<span>"_s.arg(
|
|
||||||
theme->alternateBackgroundColor().name())
|
|
||||||
<< false;
|
|
||||||
QTest::newRow("different length") << u"<span data-mx-spoiler style=\"color: short; background: looooooooooong;\">Test<span>"_s
|
|
||||||
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\">Test<span>"_s.arg(
|
|
||||||
theme->alternateBackgroundColor().name())
|
|
||||||
<< false;
|
|
||||||
QTest::newRow("spoiler revealed")
|
|
||||||
<< u"<span data-mx-spoiler style=\"color: transparent; background: %1;\">Test<span>"_s.arg(theme->alternateBackgroundColor().name())
|
|
||||||
<< u"<span data-mx-spoiler style=\"color: %1; background: %2;\">Test<span>"_s.arg(theme->textColor().name(), theme->alternateBackgroundColor().name())
|
|
||||||
<< true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextHandlerTest::updateSpoiler()
|
|
||||||
{
|
|
||||||
QFETCH(QString, testInputString);
|
|
||||||
QFETCH(QString, testOutputString);
|
|
||||||
QFETCH(bool, spoilerRevealed);
|
|
||||||
|
|
||||||
QCOMPARE(TextHandler::updateSpoilerText(this, testInputString, spoilerRevealed), testOutputString);
|
|
||||||
}
|
|
||||||
|
|
||||||
QTEST_MAIN(TextHandlerTest)
|
QTEST_MAIN(TextHandlerTest)
|
||||||
#include "texthandlertest.moc"
|
#include "texthandlertest.moc"
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -137,11 +137,7 @@ void TimelineMessageModelTest::pendingEvent()
|
|||||||
model->setRoom(room);
|
model->setRoom(room);
|
||||||
QCOMPARE(model->rowCount(), 0);
|
QCOMPARE(model->rowCount(), 0);
|
||||||
|
|
||||||
#if Quotient_VERSION_MINOR > 9
|
|
||||||
auto txnId = room->postText("New plain message"_L1);
|
|
||||||
#else
|
|
||||||
auto txnId = room->postPlainText("New plain message"_L1);
|
auto txnId = room->postPlainText("New plain message"_L1);
|
||||||
#endif
|
|
||||||
QCOMPARE(model->rowCount(), 1);
|
QCOMPARE(model->rowCount(), 1);
|
||||||
QCOMPARE(spyInsert.count(), 1);
|
QCOMPARE(spyInsert.count(), 1);
|
||||||
|
|
||||||
@@ -149,11 +145,7 @@ void TimelineMessageModelTest::pendingEvent()
|
|||||||
QCOMPARE(model->rowCount(), 0);
|
QCOMPARE(model->rowCount(), 0);
|
||||||
QCOMPARE(spyRemove.count(), 1);
|
QCOMPARE(spyRemove.count(), 1);
|
||||||
|
|
||||||
#if Quotient_VERSION_MINOR > 9
|
|
||||||
txnId = room->postText("New plain message"_L1);
|
|
||||||
#else
|
|
||||||
txnId = room->postPlainText("New plain message"_L1);
|
txnId = room->postPlainText("New plain message"_L1);
|
||||||
#endif
|
|
||||||
QCOMPARE(model->rowCount(), 1);
|
QCOMPARE(model->rowCount(), 1);
|
||||||
QCOMPARE(spyInsert.count(), 2);
|
QCOMPARE(spyInsert.count(), 2);
|
||||||
|
|
||||||
@@ -161,7 +153,7 @@ void TimelineMessageModelTest::pendingEvent()
|
|||||||
// different every time.
|
// different every time.
|
||||||
QFile testSyncFile;
|
QFile testSyncFile;
|
||||||
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + u"test-pending-sync.json"_s);
|
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + u"test-pending-sync.json"_s);
|
||||||
QVERIFY(testSyncFile.open(QIODevice::ReadOnly));
|
testSyncFile.open(QIODevice::ReadOnly);
|
||||||
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
|
auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll());
|
||||||
auto root = testSyncJson.object();
|
auto root = testSyncJson.object();
|
||||||
auto timeline = root["timeline"_L1].toObject();
|
auto timeline = root["timeline"_L1].toObject();
|
||||||
@@ -208,7 +200,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()
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
|
|
||||||
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}" )
|
|
||||||
|
|
||||||
qt_add_executable(timeline_memtest
|
|
||||||
main.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(timeline_memtest PRIVATE neochatplugin Timelineplugin)
|
|
||||||
target_link_libraries(timeline_memtest PUBLIC
|
|
||||||
Qt::Core
|
|
||||||
Qt::Quick
|
|
||||||
Qt::Qml
|
|
||||||
Qt::Gui
|
|
||||||
Qt::QuickControls2
|
|
||||||
Qt::Widgets
|
|
||||||
KF6::I18nQml
|
|
||||||
QuotientQt6
|
|
||||||
LibNeoChat
|
|
||||||
Timeline
|
|
||||||
)
|
|
||||||
|
|
||||||
ecm_add_qml_module(timeline_memtest URI org.kde.neochat.timeline_memtest GENERATE_PLUGIN_SOURCE
|
|
||||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/timeline_memtest
|
|
||||||
QML_FILES
|
|
||||||
Main.qml
|
|
||||||
SOURCES
|
|
||||||
memtesttimelinemodel.cpp
|
|
||||||
memtesttimelinemodel.h
|
|
||||||
DEPENDENCIES
|
|
||||||
QtCore
|
|
||||||
QtQuick
|
|
||||||
IMPORTS
|
|
||||||
org.kde.neochat.timeline
|
|
||||||
)
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
|
|
||||||
QQC2.ApplicationWindow {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
title: "Timeline Memory Test"
|
|
||||||
|
|
||||||
minimumWidth: Kirigami.Units.gridUnit * 30
|
|
||||||
minimumHeight: Kirigami.Units.gridUnit * 30
|
|
||||||
|
|
||||||
visible: true
|
|
||||||
|
|
||||||
QQC2.ScrollView {
|
|
||||||
width: root.width
|
|
||||||
height: root.height
|
|
||||||
|
|
||||||
contentItem: ListView {
|
|
||||||
cacheBuffer: 1000000
|
|
||||||
model: messageFilterModel
|
|
||||||
|
|
||||||
delegate: EventDelegate {
|
|
||||||
room: memTestTimelineModel.room
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QQmlApplicationEngine>
|
|
||||||
#include <QQmlContext>
|
|
||||||
|
|
||||||
#include <KLocalizedQmlContext>
|
|
||||||
#include <KLocalizedString>
|
|
||||||
|
|
||||||
#include "memtesttimelinemodel.h"
|
|
||||||
#include "models/messagefiltermodel.h"
|
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
|
||||||
|
|
||||||
KLocalization::setupLocalizedContext(&engine);
|
|
||||||
|
|
||||||
MemTestTimelineModel *memTestTimelineModel = new MemTestTimelineModel;
|
|
||||||
MessageFilterModel *messageFilterModel = new MessageFilterModel(nullptr, memTestTimelineModel);
|
|
||||||
engine.rootContext()->setContextProperty(u"memTestTimelineModel"_s, memTestTimelineModel);
|
|
||||||
engine.rootContext()->setContextProperty(u"messageFilterModel"_s, messageFilterModel);
|
|
||||||
|
|
||||||
engine.loadFromModule("org.kde.neochat.timeline_memtest", "Main");
|
|
||||||
|
|
||||||
return app.exec();
|
|
||||||
}
|
|
||||||
@@ -1,379 +0,0 @@
|
|||||||
{
|
|
||||||
"ephemeral": {
|
|
||||||
"events": [
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"$1000000000000:example.org": {
|
|
||||||
"m.read": {
|
|
||||||
"@alice:example.org": {
|
|
||||||
"ts": 1000000000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "m.receipt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"$1000000000000:example.org": {
|
|
||||||
"m.read": {
|
|
||||||
"@bob:example.org": {
|
|
||||||
"ts": 1000000000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "m.receipt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"$1000000000003:example.org": {
|
|
||||||
"m.read": {
|
|
||||||
"@tim:example.org": {
|
|
||||||
"ts": 1000000000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "m.receipt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"$1000000000003:example.org": {
|
|
||||||
"m.read": {
|
|
||||||
"@example:example.org": {
|
|
||||||
"ts": 1000000000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "m.receipt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"$1000000000003:example.org": {
|
|
||||||
"m.read": {
|
|
||||||
"@jeff:example.org": {
|
|
||||||
"ts": 1000000000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "m.receipt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"$1000000000003:example.org": {
|
|
||||||
"m.read": {
|
|
||||||
"@tina:example.org": {
|
|
||||||
"ts": 1000000000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "m.receipt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"$1000000000003:example.org": {
|
|
||||||
"m.read": {
|
|
||||||
"@sally:example.org": {
|
|
||||||
"ts": 1000000000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "m.receipt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"$1000000000003:example.org": {
|
|
||||||
"m.read": {
|
|
||||||
"@fred:example.org": {
|
|
||||||
"ts": 1000000000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "m.receipt"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"events": [
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
|
||||||
"displayname": "Example",
|
|
||||||
"membership": "join"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582555PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1000000000000,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "example:example.org",
|
|
||||||
"state_key": "@example:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
|
||||||
"displayname": "Alice",
|
|
||||||
"membership": "join",
|
|
||||||
"reason": "Looking for support"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1000000000000,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "alice:example.org",
|
|
||||||
"state_key": "@alice:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
|
||||||
"displayname": "Bob",
|
|
||||||
"membership": "join"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1000000000000,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "bob:example.org",
|
|
||||||
"state_key": "@bob:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
|
||||||
"displayname": "Tim",
|
|
||||||
"membership": "join"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1000000000000,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "tim:example.org",
|
|
||||||
"state_key": "@tim:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
|
||||||
"displayname": "Jeff",
|
|
||||||
"membership": "join"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1000000000000,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "jeff:example.org",
|
|
||||||
"state_key": "@jeff:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
|
||||||
"displayname": "Tina",
|
|
||||||
"membership": "join"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1000000000000,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "tina:example.org",
|
|
||||||
"state_key": "@tina:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
|
||||||
"displayname": "Sally",
|
|
||||||
"membership": "join"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1000000000000,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "sally:example.org",
|
|
||||||
"state_key": "@sally:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
|
||||||
"displayname": "Fred",
|
|
||||||
"membership": "join"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1000000000000,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "fred:example.org",
|
|
||||||
"state_key": "@fred:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"timeline": {
|
|
||||||
"events": [
|
|
||||||
{
|
|
||||||
"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": 0,
|
|
||||||
"origin_server_ts": 1000000000000,
|
|
||||||
"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": 1,
|
|
||||||
"origin_server_ts": 1000000000001,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "@example:example.org",
|
|
||||||
"type": "m.room.message",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1233
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"m.relates_to": {
|
|
||||||
"event_id": 1,
|
|
||||||
"key": "👍",
|
|
||||||
"rel_type": "m.annotation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"origin_server_ts": 1000000000002,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "@alice:example.org",
|
|
||||||
"type": "m.reaction",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 390159120
|
|
||||||
},
|
|
||||||
"event_id": 2,
|
|
||||||
"age": 390159120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"body": "reply",
|
|
||||||
"format": "org.matrix.custom.html",
|
|
||||||
"formatted_body": "reply",
|
|
||||||
"m.relates_to": {
|
|
||||||
"m.in_reply_to": {
|
|
||||||
"event_id": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"msgtype": "m.text"
|
|
||||||
},
|
|
||||||
"origin_server_ts": 1000000000003,
|
|
||||||
"sender": "@alice:example.org",
|
|
||||||
"type": "m.room.message",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 98
|
|
||||||
},
|
|
||||||
"event_id": 3,
|
|
||||||
"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": 4,
|
|
||||||
"origin_server_ts": 1000000000004,
|
|
||||||
"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": 5,
|
|
||||||
"origin_server_ts": 1000000000005,
|
|
||||||
"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": 6,
|
|
||||||
"origin_server_ts": 1000000000006,
|
|
||||||
"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": 7,
|
|
||||||
"origin_server_ts": 1000000000007,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "@example:example.org",
|
|
||||||
"type": "m.room.message",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1232
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"limited": true,
|
|
||||||
"prev_batch": "t34-23535_0_0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#include "memtesttimelinemodel.h"
|
|
||||||
|
|
||||||
#include <Quotient/events/eventcontent.h>
|
|
||||||
#include <Quotient/events/roommessageevent.h>
|
|
||||||
|
|
||||||
using namespace Quotient;
|
|
||||||
|
|
||||||
MemTestTimelineModel::MemTestTimelineModel(QObject *parent)
|
|
||||||
: MessageModel(parent)
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
m_connection = Connection::makeMockConnection(u"@bob:example.org"_s);
|
|
||||||
m_room = new MemTestRoom(m_connection, u"#memtestroom:example.org"_s, u"memtest-sync.json"_s);
|
|
||||||
|
|
||||||
for (const auto &eventIt : m_room->messageEvents()) {
|
|
||||||
Q_EMIT newEventAdded(eventIt.event());
|
|
||||||
}
|
|
||||||
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::reference_wrapper<const RoomEvent>> MemTestTimelineModel::getEventForIndex(QModelIndex index) const
|
|
||||||
{
|
|
||||||
return *m_room->messageEvents().at(index.row()).event();
|
|
||||||
}
|
|
||||||
|
|
||||||
int MemTestTimelineModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(parent);
|
|
||||||
return m_room->messageEvents().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_memtesttimelinemodel.cpp"
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
|
||||||
#include <QQmlEngine>
|
|
||||||
|
|
||||||
#include <Quotient/events/roomevent.h>
|
|
||||||
#include <Quotient/syncdata.h>
|
|
||||||
|
|
||||||
#include "models/messagemodel.h"
|
|
||||||
|
|
||||||
namespace Quotient
|
|
||||||
{
|
|
||||||
class Connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
class NeoChatRoom;
|
|
||||||
|
|
||||||
class MemTestRoom : public NeoChatRoom
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MemTestRoom(Quotient::Connection *connection, const QString &roomName, const QString &syncFileName = {})
|
|
||||||
: NeoChatRoom(connection, roomName, Quotient::JoinState::Join)
|
|
||||||
{
|
|
||||||
syncNewEvents(syncFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void update(Quotient::SyncRoomData &&data, bool fromCache = false)
|
|
||||||
{
|
|
||||||
Room::updateData(std::move(data), fromCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
void syncNewEvents(const QString &syncFileName)
|
|
||||||
{
|
|
||||||
if (!syncFileName.isEmpty()) {
|
|
||||||
QFile testSyncFile;
|
|
||||||
testSyncFile.setFileName(QStringLiteral(DATA_DIR) + u'/' + syncFileName);
|
|
||||||
auto ok = testSyncFile.open(QIODevice::ReadOnly);
|
|
||||||
if (!ok) {
|
|
||||||
qWarning() << "Failed to open" << testSyncFile.fileName() << testSyncFile.errorString();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class MemTestTimelineModel
|
|
||||||
*
|
|
||||||
* This is a special version of the MessageModel design to load an unchanging set
|
|
||||||
* of events from a json file so that timeline memory optimisations can be measured.
|
|
||||||
*/
|
|
||||||
class MemTestTimelineModel : public MessageModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
QML_ELEMENT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit MemTestTimelineModel(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Number of rows in the model.
|
|
||||||
*
|
|
||||||
* @sa QAbstractItemModel::rowCount
|
|
||||||
*/
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QPointer<Quotient::Connection> m_connection;
|
|
||||||
|
|
||||||
std::vector<Quotient::RoomEventPtr> m_events;
|
|
||||||
|
|
||||||
std::optional<std::reference_wrapper<const Quotient::RoomEvent>> getEventForIndex(QModelIndex index) const override;
|
|
||||||
};
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,7 @@ Name[sv]=NeoChat
|
|||||||
Name[ta]=நியோச்சாட்
|
Name[ta]=நியோச்சாட்
|
||||||
Name[tr]=NeoChat
|
Name[tr]=NeoChat
|
||||||
Name[uk]=NeoChat
|
Name[uk]=NeoChat
|
||||||
|
Name[x-test]=xxNeoChatxx
|
||||||
Name[zh_CN]=NeoChat
|
Name[zh_CN]=NeoChat
|
||||||
Name[zh_TW]=NeoChat
|
Name[zh_TW]=NeoChat
|
||||||
GenericName=Matrix Client
|
GenericName=Matrix Client
|
||||||
@@ -87,6 +88,7 @@ GenericName[sv]=Matrix-klient
|
|||||||
GenericName[ta]=Matrix வாங்கி
|
GenericName[ta]=Matrix வாங்கி
|
||||||
GenericName[tr]=Matrix İstemcisi
|
GenericName[tr]=Matrix İstemcisi
|
||||||
GenericName[uk]=Клієнт Matrix
|
GenericName[uk]=Клієнт Matrix
|
||||||
|
GenericName[x-test]=xxMatrix Clientxx
|
||||||
GenericName[zh_CN]=Matrix 客户端
|
GenericName[zh_CN]=Matrix 客户端
|
||||||
GenericName[zh_TW]=Matrix 用戶端
|
GenericName[zh_TW]=Matrix 用戶端
|
||||||
Comment=Chat on Matrix
|
Comment=Chat on Matrix
|
||||||
@@ -107,20 +109,16 @@ Comment[hu]=Csevegés Matrixon
|
|||||||
Comment[ia]=Conversation en ditecto sur Matrix
|
Comment[ia]=Conversation en ditecto sur Matrix
|
||||||
Comment[it]= su Matrix
|
Comment[it]= su Matrix
|
||||||
Comment[ka]=ჩატი Matrix-ზე
|
Comment[ka]=ჩატი Matrix-ზე
|
||||||
Comment[ko]=Matrix에서 대화하기
|
|
||||||
Comment[lv]=Tērzējiet „Matrix“ tīklā
|
Comment[lv]=Tērzējiet „Matrix“ tīklā
|
||||||
Comment[nl]=Chat op Matrix
|
Comment[nl]=Chat op Matrix
|
||||||
Comment[pl]=Rozmawiaj na Matriksie
|
Comment[pl]=Rozmawiaj na Matriksie
|
||||||
Comment[pt_BR]=Bate papo na Matrix
|
|
||||||
Comment[ro]=Discutați pe Matrix
|
|
||||||
Comment[ru]=Общение в Matrix
|
|
||||||
Comment[sa]=Matrix इत्यत्र गपशपं कुर्वन्तु
|
Comment[sa]=Matrix इत्यत्र गपशपं कुर्वन्तु
|
||||||
Comment[sl]=Klepet na Matrixu
|
Comment[sl]=Klepet na Matrixu
|
||||||
Comment[sv]=Chatta på Matrix
|
Comment[sv]=Chatta på Matrix
|
||||||
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும்
|
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும்
|
||||||
Comment[tr]=Matrix üzerinde sohbet edin
|
Comment[tr]=Matrix üzerinde sohbet edin
|
||||||
Comment[uk]=Спілкування у Matrix
|
Comment[uk]=Спілкування у Matrix
|
||||||
Comment[zh_CN]=在 Matrix 上聊天
|
Comment[x-test]=xxChat on Matrixxx
|
||||||
Comment[zh_TW]=在 Matrix 上聊天
|
Comment[zh_TW]=在 Matrix 上聊天
|
||||||
MimeType=x-scheme-handler/matrix;
|
MimeType=x-scheme-handler/matrix;
|
||||||
Exec=neochat %u
|
Exec=neochat %u
|
||||||
|
|||||||
8443
po/ar/neochat.po
8443
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
7720
po/ast/neochat.po
7720
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
9627
po/az/neochat.po
9627
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
8411
po/ca/neochat.po
8411
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
8324
po/cs/neochat.po
8324
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
8838
po/da/neochat.po
8838
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
9114
po/de/neochat.po
9114
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
9579
po/el/neochat.po
9579
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
9160
po/en_GB/neochat.po
9160
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
9277
po/eo/neochat.po
9277
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
9163
po/es/neochat.po
9163
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
8755
po/eu/neochat.po
8755
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
8921
po/fi/neochat.po
8921
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
8869
po/fr/neochat.po
8869
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
7002
po/ga/neochat.po
7002
po/ga/neochat.po
File diff suppressed because it is too large
Load Diff
9301
po/gl/neochat.po
9301
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
7297
po/he/neochat.po
7297
po/he/neochat.po
File diff suppressed because it is too large
Load Diff
9365
po/hi/neochat.po
9365
po/hi/neochat.po
File diff suppressed because it is too large
Load Diff
9274
po/hu/neochat.po
9274
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
8732
po/ia/neochat.po
8732
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
9778
po/id/neochat.po
9778
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
9073
po/ie/neochat.po
9073
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
8740
po/it/neochat.po
8740
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
7708
po/ja/neochat.po
7708
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
8637
po/ka/neochat.po
8637
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
9448
po/ko/neochat.po
9448
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
8220
po/lt/neochat.po
8220
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
9006
po/lv/neochat.po
9006
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
8721
po/nl/neochat.po
8721
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
8884
po/nn/neochat.po
8884
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
9234
po/pa/neochat.po
9234
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
8844
po/pl/neochat.po
8844
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
9809
po/pt/neochat.po
9809
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -1,122 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
|
|
||||||
<!ENTITY % Brazilian-Portuguese "INCLUDE">
|
|
||||||
]>
|
|
||||||
<!--
|
|
||||||
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
|
||||||
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
||||||
-->
|
|
||||||
|
|
||||||
<refentry lang="&language;">
|
|
||||||
<refentryinfo>
|
|
||||||
<title
|
|
||||||
>Manual do Usuário do NeoChat</title>
|
|
||||||
<author
|
|
||||||
><firstname
|
|
||||||
>Carl</firstname
|
|
||||||
><surname
|
|
||||||
>Schwan</surname
|
|
||||||
> <contrib
|
|
||||||
>NeoChat man page.</contrib
|
|
||||||
> <email
|
|
||||||
>carl@carlschwan.eu</email
|
|
||||||
></author>
|
|
||||||
<date
|
|
||||||
>01/11/2022</date>
|
|
||||||
<releaseinfo
|
|
||||||
>22.09</releaseinfo>
|
|
||||||
<productname
|
|
||||||
>NeoChat</productname>
|
|
||||||
</refentryinfo>
|
|
||||||
|
|
||||||
<refmeta>
|
|
||||||
<refentrytitle>
|
|
||||||
<command
|
|
||||||
>neochat</command>
|
|
||||||
</refentrytitle>
|
|
||||||
<manvolnum
|
|
||||||
>1</manvolnum>
|
|
||||||
</refmeta>
|
|
||||||
|
|
||||||
<refnamediv>
|
|
||||||
<refname
|
|
||||||
>neochat</refname>
|
|
||||||
<refpurpose
|
|
||||||
>Cliente para interação com o protocolo de mensagens Matrix.</refpurpose>
|
|
||||||
</refnamediv>
|
|
||||||
<!-- body begins here -->
|
|
||||||
<refsynopsisdiv id='synopsis'>
|
|
||||||
<cmdsynopsis
|
|
||||||
><command
|
|
||||||
>neochat</command
|
|
||||||
> <arg choice="opt"
|
|
||||||
><replaceable
|
|
||||||
>URI</replaceable
|
|
||||||
></arg
|
|
||||||
> </cmdsynopsis>
|
|
||||||
</refsynopsisdiv>
|
|
||||||
|
|
||||||
|
|
||||||
<refsect1 id="description">
|
|
||||||
<title
|
|
||||||
>Descrição</title>
|
|
||||||
<para
|
|
||||||
>O <command
|
|
||||||
>neochat</command
|
|
||||||
> é um aplicativo de bate-papo para o protocolo Matrix. Ele funciona tanto em computadores quanto em dispositivos móveis. </para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1 id="options"
|
|
||||||
><title
|
|
||||||
>Opções</title>
|
|
||||||
<variablelist>
|
|
||||||
<varlistentry>
|
|
||||||
<term
|
|
||||||
><option
|
|
||||||
>URI</option
|
|
||||||
></term>
|
|
||||||
<listitem>
|
|
||||||
<para
|
|
||||||
>O URI da matriz para um usuário ou uma sala. Por exemplo, matrix:u/usuário:exemplo.org e matrix:r/root:exemplo.org. Isso fará com que o NeoChat tente abrir a sala ou conversa especificada. </para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1 id="bug">
|
|
||||||
<title
|
|
||||||
>Relatar bugs</title>
|
|
||||||
<para
|
|
||||||
>Você pode reportar erros e solicitar novas funcionalidades em <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General"
|
|
||||||
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General</ulink
|
|
||||||
></para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title
|
|
||||||
>Veja também</title>
|
|
||||||
<simplelist>
|
|
||||||
<member
|
|
||||||
>Lista de perguntas frequentes sobre o Matrix <ulink url="https://matrix.org/faq/"
|
|
||||||
>https://matrix.org/faq/</ulink
|
|
||||||
> </member>
|
|
||||||
<member
|
|
||||||
>kf5options(7)</member>
|
|
||||||
<member
|
|
||||||
>qt5options(7)</member>
|
|
||||||
</simplelist>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1 id="copyright"
|
|
||||||
><title
|
|
||||||
>Direitos autorais</title>
|
|
||||||
<para
|
|
||||||
>Direitos autorais © 2020-2022 Tobias Fella </para>
|
|
||||||
<para
|
|
||||||
>Direitos autorais © 2020-2022 Carl Schwan </para>
|
|
||||||
<para
|
|
||||||
>Licença: GNU General Public Versão 3 ou posterior <ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
|
|
||||||
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
|
|
||||||
>></para>
|
|
||||||
</refsect1>
|
|
||||||
</refentry>
|
|
||||||
10913
po/pt_BR/neochat.po
10913
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
7049
po/ro/neochat.po
7049
po/ro/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -1,122 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
|
|
||||||
<!ENTITY % Russian "INCLUDE">
|
|
||||||
]>
|
|
||||||
<!--
|
|
||||||
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
|
||||||
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
||||||
-->
|
|
||||||
|
|
||||||
<refentry lang="&language;">
|
|
||||||
<refentryinfo>
|
|
||||||
<title
|
|
||||||
>Руководство пользователя NeoChat</title>
|
|
||||||
<author
|
|
||||||
><firstname
|
|
||||||
>Carl</firstname
|
|
||||||
><surname
|
|
||||||
>Schwan</surname
|
|
||||||
> <contrib
|
|
||||||
>man-страница NeoChat.</contrib
|
|
||||||
> <email
|
|
||||||
>carl@carlschwan.eu</email
|
|
||||||
></author>
|
|
||||||
<date
|
|
||||||
>2022-11-01</date>
|
|
||||||
<releaseinfo
|
|
||||||
>22.09</releaseinfo>
|
|
||||||
<productname
|
|
||||||
>NeoChat</productname>
|
|
||||||
</refentryinfo>
|
|
||||||
|
|
||||||
<refmeta>
|
|
||||||
<refentrytitle>
|
|
||||||
<command
|
|
||||||
>neochat</command>
|
|
||||||
</refentrytitle>
|
|
||||||
<manvolnum
|
|
||||||
>1</manvolnum>
|
|
||||||
</refmeta>
|
|
||||||
|
|
||||||
<refnamediv>
|
|
||||||
<refname
|
|
||||||
>neochat</refname>
|
|
||||||
<refpurpose
|
|
||||||
>Клиент для взаимодействия с протоколом обмена сообщениями Matrix</refpurpose>
|
|
||||||
</refnamediv>
|
|
||||||
<!-- body begins here -->
|
|
||||||
<refsynopsisdiv id='synopsis'>
|
|
||||||
<cmdsynopsis
|
|
||||||
><command
|
|
||||||
>neochat</command
|
|
||||||
> <arg choice="opt"
|
|
||||||
><replaceable
|
|
||||||
>URI</replaceable
|
|
||||||
></arg
|
|
||||||
> </cmdsynopsis>
|
|
||||||
</refsynopsisdiv>
|
|
||||||
|
|
||||||
|
|
||||||
<refsect1 id="description">
|
|
||||||
<title
|
|
||||||
>Описание</title>
|
|
||||||
<para
|
|
||||||
><command
|
|
||||||
>neochat</command
|
|
||||||
> — приложение для настольных и мобильных устройств, позволяющее общаться в чатах с помощью протокола Matrix. </para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1 id="options"
|
|
||||||
><title
|
|
||||||
>Параметры</title>
|
|
||||||
<variablelist>
|
|
||||||
<varlistentry>
|
|
||||||
<term
|
|
||||||
><option
|
|
||||||
>URI</option
|
|
||||||
></term>
|
|
||||||
<listitem>
|
|
||||||
<para
|
|
||||||
>URI-адрес пользователя или комнаты в Matrix, например: matrix:u/user:example.org и matrix:r/root:example.org. NeoChat попытается открыть указанную комнату или беседу. </para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1 id="bug">
|
|
||||||
<title
|
|
||||||
>Отчёты об ошибках</title>
|
|
||||||
<para
|
|
||||||
>Сообщать об ошибках и отправлять предложения по улучшению можно по адресу <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General"
|
|
||||||
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General</ulink
|
|
||||||
></para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title
|
|
||||||
>Смотрите также</title>
|
|
||||||
<simplelist>
|
|
||||||
<member
|
|
||||||
>Список наиболее часто задаваемых вопросов о Matrix <ulink url="https://matrix.org/faq/"
|
|
||||||
>https://matrix.org/faq/</ulink
|
|
||||||
> </member>
|
|
||||||
<member
|
|
||||||
>kf5options(7)</member>
|
|
||||||
<member
|
|
||||||
>qt5options(7)</member>
|
|
||||||
</simplelist>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1 id="copyright"
|
|
||||||
><title
|
|
||||||
>Авторские права</title>
|
|
||||||
<para
|
|
||||||
>Авторские права © Tobias Fella, 2020–2022 </para>
|
|
||||||
<para
|
|
||||||
>Авторские права © Carl Schwan, 2020–2022 </para>
|
|
||||||
<para
|
|
||||||
>Лицензия: стандартная общественная лицензия GNU версии 3 или любой более поздней версии <<ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
|
|
||||||
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
|
|
||||||
>></para>
|
|
||||||
</refsect1>
|
|
||||||
</refentry>
|
|
||||||
9625
po/ru/neochat.po
9625
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
9301
po/sa/neochat.po
9301
po/sa/neochat.po
File diff suppressed because it is too large
Load Diff
9281
po/sk/neochat.po
9281
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
8392
po/sl/neochat.po
8392
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
8786
po/sv/neochat.po
8786
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
9055
po/ta/neochat.po
9055
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
9102
po/tok/neochat.po
9102
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
8704
po/tr/neochat.po
8704
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
8448
po/uk/neochat.po
8448
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
7939
po/zh_CN/neochat.po
7939
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
8237
po/zh_TW/neochat.po
8237
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
|||||||
# SPDX-FileCopyrightText: 2024-2025 Scarlett Moore <sgmoore@kde.org>
|
# SPDX-FileCopyrightText: 2024 Scarlett Moore <sgmoore@kde.org>
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
---
|
---
|
||||||
name: neochat
|
name: neochat
|
||||||
base: core24
|
base: core22
|
||||||
adopt-info: neochat
|
adopt-info: neochat
|
||||||
grade: stable
|
grade: stable
|
||||||
confinement: strict
|
confinement: strict
|
||||||
@@ -24,15 +24,12 @@ apps:
|
|||||||
- network-manager-observe
|
- network-manager-observe
|
||||||
- password-manager-service
|
- password-manager-service
|
||||||
- accounts-service
|
- accounts-service
|
||||||
environment:
|
|
||||||
QT_PLUGIN_PATH: "$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/plugins/snap/kf6-core24/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/plugins"
|
|
||||||
QML_IMPORT_PATH: "$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/qml:/snap/kf6-core24/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/qml"
|
|
||||||
|
|
||||||
compression: lzo
|
compression: lzo
|
||||||
|
|
||||||
package-repositories:
|
package-repositories:
|
||||||
- type: apt
|
- type: apt
|
||||||
ppa: ubuntu-toolchain-r/test
|
ppa: ubuntu-toolchain-r/test
|
||||||
|
|
||||||
slots:
|
slots:
|
||||||
session-dbus-interface:
|
session-dbus-interface:
|
||||||
@@ -44,12 +41,11 @@ parts:
|
|||||||
olm:
|
olm:
|
||||||
source: https://gitlab.matrix.org/matrix-org/olm.git
|
source: https://gitlab.matrix.org/matrix-org/olm.git
|
||||||
source-depth: 1
|
source-depth: 1
|
||||||
source-tag: '3.2.16'
|
source-tag: '3.2.12'
|
||||||
plugin: cmake
|
plugin: cmake
|
||||||
cmake-parameters:
|
cmake-parameters:
|
||||||
- -DCMAKE_BUILD_TYPE=Release
|
- -DCMAKE_BUILD_TYPE=Release
|
||||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
- -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
|
||||||
prime:
|
prime:
|
||||||
- -usr/include
|
- -usr/include
|
||||||
- -usr/lib/*/pkgconfig
|
- -usr/lib/*/pkgconfig
|
||||||
@@ -70,7 +66,7 @@ parts:
|
|||||||
- -Dcrypto=disabled
|
- -Dcrypto=disabled
|
||||||
- -Dgtk_doc=false
|
- -Dgtk_doc=false
|
||||||
build-packages:
|
build-packages:
|
||||||
- meson
|
- meson
|
||||||
- libglib2.0-dev
|
- libglib2.0-dev
|
||||||
- libgcrypt20-dev
|
- libgcrypt20-dev
|
||||||
prime:
|
prime:
|
||||||
@@ -85,7 +81,7 @@ parts:
|
|||||||
plugin: cmake
|
plugin: cmake
|
||||||
build-environment:
|
build-environment:
|
||||||
- PATH: /snap/bin:${PATH}
|
- PATH: /snap/bin:${PATH}
|
||||||
- PKG_CONFIG_PATH: "$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET/pkgconfig:$PKG_CONFIG_PATH"
|
- PKG_CONFIG_PATH: $CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET/pkgconfig:$PKG_CONFIG_PATH
|
||||||
cmake-parameters:
|
cmake-parameters:
|
||||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
- -DCMAKE_BUILD_TYPE=Release
|
- -DCMAKE_BUILD_TYPE=Release
|
||||||
@@ -101,7 +97,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:
|
||||||
@@ -109,6 +105,8 @@ parts:
|
|||||||
build-snaps:
|
build-snaps:
|
||||||
- cmake
|
- cmake
|
||||||
build-packages:
|
build-packages:
|
||||||
|
- gcc-13
|
||||||
|
- g++-13
|
||||||
- libssl-dev
|
- libssl-dev
|
||||||
cmake-parameters:
|
cmake-parameters:
|
||||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
@@ -116,6 +114,9 @@ parts:
|
|||||||
- -DBUILD_TESTING=OFF
|
- -DBUILD_TESTING=OFF
|
||||||
- -DQuotient_ENABLE_E2EE=ON
|
- -DQuotient_ENABLE_E2EE=ON
|
||||||
- -DBUILD_WITH_QT6=ON
|
- -DBUILD_WITH_QT6=ON
|
||||||
|
override-build: |
|
||||||
|
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 --slave /usr/bin/g++ g++ /usr/bin/g++-13 --slave /usr/bin/gcov gcov /usr/bin/gcov-13
|
||||||
|
craftctl default
|
||||||
prime:
|
prime:
|
||||||
- -usr/include
|
- -usr/include
|
||||||
- -usr/lib/*/pkgconfig
|
- -usr/lib/*/pkgconfig
|
||||||
@@ -128,8 +129,6 @@ parts:
|
|||||||
plugin: cmake
|
plugin: cmake
|
||||||
build-environment:
|
build-environment:
|
||||||
- PATH: /snap/bin:${PATH}
|
- PATH: /snap/bin:${PATH}
|
||||||
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
|
|
||||||
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
|
|
||||||
cmake-parameters:
|
cmake-parameters:
|
||||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
- -DCMAKE_BUILD_TYPE=Release
|
- -DCMAKE_BUILD_TYPE=Release
|
||||||
@@ -140,32 +139,17 @@ parts:
|
|||||||
- -usr/lib/*/pkgconfig
|
- -usr/lib/*/pkgconfig
|
||||||
- -usr/lib/*/cmake
|
- -usr/lib/*/cmake
|
||||||
|
|
||||||
kunifiedpush:
|
|
||||||
source: https://invent.kde.org/libraries/kunifiedpush.git
|
|
||||||
plugin: cmake
|
|
||||||
build-environment:
|
|
||||||
- PATH: /snap/bin:${PATH}
|
|
||||||
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
|
|
||||||
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
|
|
||||||
cmake-parameters:
|
|
||||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
- -DCMAKE_BUILD_TYPE=Release
|
|
||||||
- -DBUILD_TESTING=OFF
|
|
||||||
|
|
||||||
neochat:
|
neochat:
|
||||||
after:
|
after:
|
||||||
- qtkeychain
|
- qtkeychain
|
||||||
- libquotient
|
- libquotient
|
||||||
- kquickimageeditor
|
- kquickimageeditor
|
||||||
- kunifiedpush
|
|
||||||
parse-info:
|
parse-info:
|
||||||
- usr/share/metainfo/org.kde.neochat.appdata.xml
|
- usr/share/metainfo/org.kde.neochat.appdata.xml
|
||||||
source: .
|
source: .
|
||||||
plugin: cmake
|
plugin: cmake
|
||||||
build-environment:
|
build-environment:
|
||||||
- PATH: /snap/bin:${PATH}
|
- PATH: /snap/bin:${PATH}
|
||||||
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
|
|
||||||
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
|
|
||||||
build-packages:
|
build-packages:
|
||||||
- cmark
|
- cmark
|
||||||
- libcmark-dev
|
- libcmark-dev
|
||||||
@@ -189,12 +173,3 @@ parts:
|
|||||||
prime:
|
prime:
|
||||||
- usr/lib/*/libcmark.so*
|
- usr/lib/*/libcmark.so*
|
||||||
|
|
||||||
gpu-2404:
|
|
||||||
after: [neochat]
|
|
||||||
source: https://github.com/canonical/gpu-snap.git
|
|
||||||
plugin: dump
|
|
||||||
override-prime: |
|
|
||||||
craftctl default
|
|
||||||
${CRAFT_PART_SRC}/bin/gpu-2404-cleanup mesa-2404
|
|
||||||
prime:
|
|
||||||
- bin/gpu-2404-wrapper
|
|
||||||
|
|||||||
@@ -1,18 +1,571 @@
|
|||||||
# 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
|
||||||
|
events/joinrulesevent.cpp
|
||||||
|
events/joinrulesevent.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/neochatdeactivateaccountjob.cpp
|
||||||
|
jobs/neochatdeactivateaccountjob.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
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
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/ContextMenu.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/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)
|
||||||
|
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::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"
|
||||||
|
"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-low"
|
||||||
|
"security-low-symbolic"
|
||||||
|
"kde"
|
||||||
|
"list-remove-symbolic"
|
||||||
|
"edit-delete"
|
||||||
|
"user-home-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,365 +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
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
set(EXTRA_IMPORTS org.kde.purpose)
|
|
||||||
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
|
|
||||||
qml/MeetingDialog.qml
|
|
||||||
DEPENDENCIES
|
|
||||||
QtCore
|
|
||||||
QtQuick
|
|
||||||
io.github.quotient_im.libquotient
|
|
||||||
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
|
|
||||||
org.kde.config
|
|
||||||
org.kde.syntaxhighlighting
|
|
||||||
${EXTRA_IMPORTS}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT ANDROID AND NOT WIN32)
|
|
||||||
qt_target_qml_sources(neochat QML_FILES
|
|
||||||
qml/ShareAction.qml
|
|
||||||
qml/GlobalMenu.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
|
|
||||||
KF6::IconThemes
|
|
||||||
)
|
|
||||||
|
|
||||||
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::ItemModels
|
|
||||||
KF6::I18nQml
|
|
||||||
KirigamiApp
|
|
||||||
QuotientQt6
|
|
||||||
Login
|
|
||||||
Rooms
|
|
||||||
MessageContent
|
|
||||||
Spaces
|
|
||||||
)
|
|
||||||
|
|
||||||
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"
|
|
||||||
"amarok_playcount"
|
|
||||||
|
|
||||||
${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 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)
|
|
||||||
# krunner plugin must be the same as the app id for flatpak to export it
|
|
||||||
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins RENAME org.kde.neochat.desktop)
|
|
||||||
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,382 +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 <KLocalizedString>
|
|
||||||
|
|
||||||
#include <QGuiApplication>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include <Quotient/events/roommemberevent.h>
|
|
||||||
#include <Quotient/qt_connection_util.h>
|
|
||||||
#include <Quotient/settings.h>
|
|
||||||
|
|
||||||
#include "enums/roomsortparameter.h"
|
|
||||||
#include "general_logging.h"
|
|
||||||
#include "mediasizehelper.h"
|
|
||||||
#include "models/actionsmodel.h"
|
|
||||||
#include "models/messagemodel.h"
|
|
||||||
#include "models/roomlistmodel.h"
|
|
||||||
#include "models/roomtreemodel.h"
|
|
||||||
#include "neochatconfig.h"
|
|
||||||
#include "neochatroom.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
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [this] {
|
|
||||||
#ifndef Q_OS_ANDROID
|
|
||||||
delete m_trayIcon;
|
|
||||||
#endif
|
|
||||||
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) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
QStringList unsupportedPlatforms{u"GNOME"_s, u"Pantheon"_s};
|
|
||||||
return !unsupportedPlatforms.contains(QString::fromLatin1(qgetenv("XDG_CURRENT_DESKTOP")));
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
#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) {
|
|
||||||
NotificationsManager::postPushNotification(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
qGuiApp->setBadgeNumber(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
if (!file.open(QFile::ReadOnly)) {
|
|
||||||
qCWarning(GENERAL) << "Failed to open file" << path;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
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,79 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "commonroomsmodel.h"
|
|
||||||
#include "jobs/neochatgetcommonroomsjob.h"
|
|
||||||
|
|
||||||
#include <QGuiApplication>
|
|
||||||
|
|
||||||
using namespace Quotient;
|
|
||||||
|
|
||||||
CommonRoomsModel::CommonRoomsModel(QObject *parent)
|
|
||||||
: QAbstractListModel(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NeoChatConnection *CommonRoomsModel::connection() const
|
|
||||||
{
|
|
||||||
return m_connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonRoomsModel::setConnection(NeoChatConnection *connection)
|
|
||||||
{
|
|
||||||
m_connection = connection;
|
|
||||||
Q_EMIT connectionChanged();
|
|
||||||
reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CommonRoomsModel::userId() const
|
|
||||||
{
|
|
||||||
return m_userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonRoomsModel::setUserId(const QString &userId)
|
|
||||||
{
|
|
||||||
m_userId = userId;
|
|
||||||
Q_EMIT userIdChanged();
|
|
||||||
reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant CommonRoomsModel::data(const QModelIndex &index, int roleName) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(index)
|
|
||||||
Q_UNUSED(roleName)
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
int CommonRoomsModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(parent)
|
|
||||||
return m_commonRooms.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonRoomsModel::reload()
|
|
||||||
{
|
|
||||||
if (!m_connection || m_userId.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_connection->canCheckMutualRooms()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checking if you have mutual rooms with yourself doesn't make sense and servers reject it too
|
|
||||||
if (m_connection->userId() == m_userId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_connection->callApi<NeochatGetCommonRoomsJob>(m_userId).then([this](const auto job) {
|
|
||||||
const auto &replyData = job->jsonData();
|
|
||||||
beginResetModel();
|
|
||||||
for (const auto &roomId : replyData[u"joined"_s].toArray()) {
|
|
||||||
m_commonRooms.push_back(roomId.toString());
|
|
||||||
}
|
|
||||||
endResetModel();
|
|
||||||
Q_EMIT countChanged();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_commonroomsmodel.cpp"
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
|
||||||
#include <QQmlEngine>
|
|
||||||
|
|
||||||
#include "neochatconnection.h"
|
|
||||||
|
|
||||||
#include <Quotient/events/roommessageevent.h>
|
|
||||||
#include <Quotient/roommember.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Model to show the common or mutual rooms between you and another user.
|
|
||||||
*/
|
|
||||||
class CommonRoomsModel : public QAbstractListModel
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
QML_ELEMENT
|
|
||||||
Q_PROPERTY(NeoChatConnection *connection WRITE setConnection READ connection NOTIFY connectionChanged REQUIRED)
|
|
||||||
Q_PROPERTY(QString userId WRITE setUserId READ userId NOTIFY userIdChanged REQUIRED)
|
|
||||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum Roles {
|
|
||||||
RoomIdRole = Qt::DisplayRole,
|
|
||||||
};
|
|
||||||
Q_ENUM(Roles)
|
|
||||||
|
|
||||||
explicit CommonRoomsModel(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
[[nodiscard]] NeoChatConnection *connection() const;
|
|
||||||
void setConnection(NeoChatConnection *connection);
|
|
||||||
|
|
||||||
[[nodiscard]] QString userId() const;
|
|
||||||
void setUserId(const QString &userId);
|
|
||||||
|
|
||||||
[[nodiscard]] QVariant data(const QModelIndex &index, int roleName) const override;
|
|
||||||
[[nodiscard]] Q_INVOKABLE int rowCount(const QModelIndex &parent = {}) const override;
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void connectionChanged();
|
|
||||||
void userIdChanged();
|
|
||||||
void countChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void reload();
|
|
||||||
|
|
||||||
QPointer<NeoChatConnection> m_connection;
|
|
||||||
QString m_userId;
|
|
||||||
QList<QString> m_commonRooms;
|
|
||||||
};
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import Qt.labs.platform as Labs
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Window
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
import org.kde.neochat.settings
|
|
||||||
|
|
||||||
Labs.MenuBar {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property NeoChatConnection connection
|
|
||||||
required property Kirigami.ApplicationWindow appWindow
|
|
||||||
|
|
||||||
Labs.Menu {
|
|
||||||
title: i18nc("menu", "File")
|
|
||||||
|
|
||||||
Labs.MenuItem {
|
|
||||||
icon.name: "list-add-user"
|
|
||||||
text: i18nc("@action:inmenu", "Find User")
|
|
||||||
enabled: root.connection
|
|
||||||
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UserSearchPage'), {
|
|
||||||
connection: root.connection
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title", "Find User")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Labs.MenuItem {
|
|
||||||
icon.name: "system-users-symbolic"
|
|
||||||
text: i18nc("@action:inmenu", "Create a Room…")
|
|
||||||
enabled: root.connection
|
|
||||||
shortcut: StandardKey.New
|
|
||||||
onTriggered: {
|
|
||||||
Qt.createComponent('org.kde.neochat', 'CreateRoomDialog').createObject(root.appWindow, {
|
|
||||||
connection: root.connection
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title", "Create a Room")
|
|
||||||
}).open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Labs.MenuItem {
|
|
||||||
icon.name: "compass-symbolic"
|
|
||||||
text: i18nc("@action:inmenu", "Explore Rooms")
|
|
||||||
enabled: root.connection
|
|
||||||
onTriggered: {
|
|
||||||
let dialog = root.appWindow.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
|
|
||||||
connection: root.connection
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title", "Explore Rooms")
|
|
||||||
});
|
|
||||||
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
|
|
||||||
RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, isJoined ? "" : "join");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Labs.MenuItem {
|
|
||||||
text: i18nc("menu", "Configure NeoChat…")
|
|
||||||
|
|
||||||
shortcut: StandardKey.Preferences
|
|
||||||
onTriggered: NeoChatSettingsView.open()
|
|
||||||
}
|
|
||||||
Labs.MenuItem {
|
|
||||||
text: i18nc("menu", "Quit NeoChat")
|
|
||||||
|
|
||||||
shortcut: StandardKey.Quit
|
|
||||||
onTriggered: Qt.quit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Labs.Menu {
|
|
||||||
title: i18nc("menu", "View")
|
|
||||||
|
|
||||||
Labs.MenuItem {
|
|
||||||
icon.name: "search-symbolic"
|
|
||||||
enabled: root.connection
|
|
||||||
text: i18nc("@action:inmenu opens a UI element called the 'Quick Switcher', which offers a fast keyboard-based interface for switching in between chats.", "Search Rooms")
|
|
||||||
onTriggered: (root.appWindow as Main).quickSwitcher.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Labs.Menu {
|
|
||||||
title: i18nc("menu", "Window")
|
|
||||||
|
|
||||||
Labs.MenuItem {
|
|
||||||
icon.name: "view-fullscreen-symbolic"
|
|
||||||
text: root.appWindow.visibility === Window.FullScreen ? i18nc("menu", "Exit Full Screen") : i18nc("menu", "Enter Full Screen")
|
|
||||||
onTriggered: root.appWindow.visibility === Window.FullScreen ? root.appWindow.showNormal() : root.appWindow.showFullScreen()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Labs.Menu {
|
|
||||||
title: i18nc("menu", "Help")
|
|
||||||
|
|
||||||
Labs.MenuItem {
|
|
||||||
icon.name: "help-about-symbolic"
|
|
||||||
text: i18nc("menu", "About NeoChat")
|
|
||||||
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutPage"))
|
|
||||||
}
|
|
||||||
Labs.MenuItem {
|
|
||||||
icon.name: "kde-symbolic"
|
|
||||||
text: i18nc("menu", "About KDE")
|
|
||||||
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDEPage"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
import org.kde.neochat
|
|
||||||
|
|
||||||
Item {
|
|
||||||
required property NeoChatConnection connection
|
|
||||||
required property Kirigami.ApplicationWindow appWindow
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-FileCopyrightText: 2024 Carl Schwan <carl@carlschwan.eu>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property string text
|
|
||||||
|
|
||||||
onTextChanged: {
|
|
||||||
// This is done so the text doesn't disappear for a split second while in the opacity transition
|
|
||||||
if (root.text.length > 0) {
|
|
||||||
urlLabel.text = root.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
z: 99
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
opacity: (!root.text.startsWith("https://matrix.to/") && root.text.length > 0) ? 1 : 0
|
|
||||||
visible: opacity > 0
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
OpacityAnimator {
|
|
||||||
duration: Kirigami.Units.shortDuration
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Control {
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
|
||||||
|
|
||||||
Accessible.ignored: true
|
|
||||||
|
|
||||||
contentItem: QQC2.Label {
|
|
||||||
id: urlLabel
|
|
||||||
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Kirigami.ShadowedRectangle {
|
|
||||||
corners.topRightRadius: Kirigami.Units.cornerRadius
|
|
||||||
color: Kirigami.Theme.backgroundColor
|
|
||||||
border {
|
|
||||||
color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, Kirigami.Theme.frameContrast)
|
|
||||||
width: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,201 +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
|
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
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.SelectableLabel {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
font: Kirigami.Theme.smallFont
|
|
||||||
textFormat: TextEdit.PlainText
|
|
||||||
visible: root.currentRoom && root.currentRoom.canonicalAlias
|
|
||||||
text: root.currentRoom && root.currentRoom.canonicalAlias ? root.currentRoom.canonicalAlias : ""
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
}
|
|
||||||
|
|
||||||
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.invitingMember.displayName
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Label {
|
|
||||||
text: root.invitingMember.id
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
|
|
||||||
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: xi18nc("@info:label Ensure you are referring to the same translation used for that settings page", "You can reject invitations from unknown users under the <interface>Security & Safety</interface> 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,22 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
|
|
||||||
Kirigami.PromptDialog {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property bool hasExistingMeeting
|
|
||||||
|
|
||||||
title: hasExistingMeeting ? i18nc("@title", "Join Meeting") : i18nc("@title", "Start Meeting")
|
|
||||||
subtitle: hasExistingMeeting ? i18nc("@info:label", "You are about to join a Jitsi meeting in your web browser.") : i18nc("@info:label", "You are about to start a new Jitsi meeting in your web browser.")
|
|
||||||
standardButtons: Kirigami.Dialog.Cancel
|
|
||||||
|
|
||||||
customFooterActions: Kirigami.Action {
|
|
||||||
icon.name: "camera-video-symbolic"
|
|
||||||
text: hasExistingMeeting ? i18nc("@action:button Join the Jitsi meeting", "Join") : i18nc("@action:button Start a new Jitsi meeting", "Start")
|
|
||||||
onTriggered: root.accept()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,151 +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
|
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
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.delegates as Delegates
|
|
||||||
|
|
||||||
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(QQC2.ApplicationWindow.window.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: i18nc("@label", "Poll type:")
|
|
||||||
currentIndex: 0
|
|
||||||
textRole: "text"
|
|
||||||
valueRole: "value"
|
|
||||||
model: [
|
|
||||||
{ value: PollKind.Disclosed, text: i18nc("@item:inlistbox", "Open poll") },
|
|
||||||
{ value: PollKind.Undisclosed, text: i18nc("@item:inlistbox", "Closed poll") }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
FormCard.FormTextDelegate {
|
|
||||||
verticalPadding: 0
|
|
||||||
text: pollTypeCombo.currentValue == 0 ? i18nc("@info", "Voters can see the result as soon as they have voted") : i18nc("@info", "Results are revealed only after the poll has closed")
|
|
||||||
}
|
|
||||||
FormCard.FormTextFieldDelegate {
|
|
||||||
id: questionTextField
|
|
||||||
label: i18nc("@label", "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: i18nc("@placeholder", "Enter option")
|
|
||||||
}
|
|
||||||
QQC2.ToolButton {
|
|
||||||
display: QQC2.AbstractButton.IconOnly
|
|
||||||
text: i18nc("@action:button", "Remove option")
|
|
||||||
icon.name: "edit-delete-remove"
|
|
||||||
onClicked: optionModel.remove(optionDelegate.index)
|
|
||||||
QQC2.ToolTip.text: text
|
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
|
||||||
QQC2.ToolTip.visible: hovered
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,57 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
|
|
||||||
Kirigami.SearchDialog {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property NeoChatConnection connection
|
|
||||||
required property Kirigami.ApplicationWindow window
|
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: "Ctrl+K"
|
|
||||||
onActivated: if (root.connection) root.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
onAccepted: if (currentItem) {
|
|
||||||
(root.currentItem as RoomDelegate).clicked();
|
|
||||||
}
|
|
||||||
|
|
||||||
onTextChanged: RoomManager.sortFilterRoomListModel.filterText = text
|
|
||||||
model: RoomManager.sortFilterRoomListModel
|
|
||||||
emptyText: i18nc("Placeholder message", "No room found")
|
|
||||||
Kirigami.Action {
|
|
||||||
id: exploreRoomAction
|
|
||||||
text: i18nc("@action:button", "Explore rooms")
|
|
||||||
icon.name: "compass"
|
|
||||||
onTriggered: {
|
|
||||||
root.close()
|
|
||||||
let dialog = root.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
|
|
||||||
connection: root.connection
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title", "Explore Rooms")
|
|
||||||
});
|
|
||||||
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
|
|
||||||
RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, isJoined ? "" : "join");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: emptyHelpfulAction = exploreRoomAction
|
|
||||||
|
|
||||||
parent: QQC2.Overlay.overlay
|
|
||||||
|
|
||||||
delegate: RoomDelegate {
|
|
||||||
connection: root.connection
|
|
||||||
onClicked: root.close()
|
|
||||||
showConfigure: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,420 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2018-2020 Black Hat <bhat@encom.eu.org>
|
|
||||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
import QtQuick.Window
|
|
||||||
import QtQuick.Layouts
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
|
|
||||||
Kirigami.Page {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The NeoChatRoom the delegate is being displayed in.
|
|
||||||
*/
|
|
||||||
readonly property NeoChatRoom currentRoom: RoomManager.currentRoom
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The TimelineModel to use.
|
|
||||||
*
|
|
||||||
* Required so that new events can be requested when the end of the current
|
|
||||||
* local timeline is reached.
|
|
||||||
*
|
|
||||||
* @note For loading a room in a different window, override this with a new
|
|
||||||
* TimelineModel set with the room to be shown.
|
|
||||||
*
|
|
||||||
* @sa TimelineModel
|
|
||||||
*/
|
|
||||||
property TimelineModel timelineModel: RoomManager.timelineModel
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The MessageFilterModel to use.
|
|
||||||
*
|
|
||||||
* This model has the filtered list of events that should be shown in the timeline.
|
|
||||||
*
|
|
||||||
* @note For loading a room in a different window, override this with a new
|
|
||||||
* MessageFilterModel with the new TimelineModel as the source model.
|
|
||||||
*
|
|
||||||
* @sa TimelineModel, MessageFilterModel
|
|
||||||
*/
|
|
||||||
property MessageFilterModel messageFilterModel: RoomManager.messageFilterModel
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The MediaMessageFilterModel to use.
|
|
||||||
*
|
|
||||||
* This model has the filtered list of media events that should be shown in
|
|
||||||
* the timeline.
|
|
||||||
*
|
|
||||||
* @note For loading a room in a different window, override this with a new
|
|
||||||
* MediaMessageFilterModel with the new MessageFilterModel as the source model.
|
|
||||||
*
|
|
||||||
* @sa TimelineModel, MessageFilterModel
|
|
||||||
*/
|
|
||||||
property MediaMessageFilterModel mediaMessageFilterModel: RoomManager.mediaMessageFilterModel
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The WidgetModel to use.
|
|
||||||
*
|
|
||||||
* This model has the list of widgets available in the current room.
|
|
||||||
*
|
|
||||||
* @note For loading a room in a different window, override this with a new
|
|
||||||
* WidgetModel.
|
|
||||||
*
|
|
||||||
* @sa WidgetModel
|
|
||||||
*/
|
|
||||||
property WidgetModel widgetModel: RoomManager.widgetModel
|
|
||||||
|
|
||||||
title: root.currentRoom ? root.currentRoom.displayName : ""
|
|
||||||
focus: true
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
background: null // This needs to stay null, because of transparency blur
|
|
||||||
|
|
||||||
onHeightChanged: {
|
|
||||||
// HACK: See TimelineView for the hack details.
|
|
||||||
// We get the height change here *first* so we are informed this is because of a window resize and not due to the pinned message.
|
|
||||||
resetViewSettling();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resets the view settling of the timeline.
|
|
||||||
// This should be called whenever the apparent height of the timeline changes, or else the view will scroll on its own!
|
|
||||||
function resetViewSettling(): void {
|
|
||||||
(timelineViewLoader.item as TimelineView).resetViewSettling();
|
|
||||||
}
|
|
||||||
|
|
||||||
actions: [
|
|
||||||
Kirigami.Action {
|
|
||||||
id: jitsiMeetingAction
|
|
||||||
|
|
||||||
readonly property bool hasExistingMeeting: root.widgetModel.jitsiIndex >= 0
|
|
||||||
readonly property bool canStartNewMeeting: root.currentRoom.canSendState("im.vector.modular.widgets")
|
|
||||||
|
|
||||||
tooltip: {
|
|
||||||
if (hasExistingMeeting) {
|
|
||||||
return i18nc("@action:button", "Join Jitsi meeting…");
|
|
||||||
}
|
|
||||||
|
|
||||||
return canStartNewMeeting ? i18nc("@action:button", "Start Jitsi meeting…") : i18nc("@action:button", "You do not have permissions to start Jitsi meetings")
|
|
||||||
}
|
|
||||||
icon {
|
|
||||||
name: "camera-video-symbolic"
|
|
||||||
color: hasExistingMeeting ? Kirigami.Theme.highlightColor : "transparent"
|
|
||||||
}
|
|
||||||
enabled: hasExistingMeeting || canStartNewMeeting
|
|
||||||
visible: root.currentRoom && !root.currentRoom.isSpace
|
|
||||||
onTriggered: {
|
|
||||||
const dialog = Qt.createComponent("org.kde.neochat", "MeetingDialog").createObject(QQC2.Overlay.overlay, { hasExistingMeeting });
|
|
||||||
dialog.onAccepted.connect(doAction);
|
|
||||||
dialog.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
function doAction(): void {
|
|
||||||
let url;
|
|
||||||
if (!hasExistingMeeting) {
|
|
||||||
url = root.widgetModel.addJitsiConference();
|
|
||||||
} else {
|
|
||||||
let idx = root.widgetModel.index(root.widgetModel.jitsiIndex, 0);
|
|
||||||
url = root.widgetModel.data(idx, WidgetModel.UrlRole);
|
|
||||||
}
|
|
||||||
Qt.openUrlExternally(url);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Kirigami.Action {
|
|
||||||
visible: Kirigami.Settings.isMobile || !(root.Kirigami.PageStack.pageStack as Kirigami.PageRow)?.wideMode
|
|
||||||
icon.name: "view-right-new"
|
|
||||||
onTriggered: (root.QQC2.ApplicationWindow.window as Main).openRoomDrawer()
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
Kirigami.Action {
|
|
||||||
enabled: root.currentRoom && !root.currentRoom.isSpace
|
|
||||||
shortcut: "Ctrl+F"
|
|
||||||
onTriggered: {
|
|
||||||
((root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomSearchPage'), {
|
|
||||||
room: root.currentRoom
|
|
||||||
}, {
|
|
||||||
title: i18nc("@action:title", "Search")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyNavigation.left: (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).get(0)
|
|
||||||
|
|
||||||
onCurrentRoomChanged: {
|
|
||||||
if (!Kirigami.Settings.isMobile && chatBarLoader.item) {
|
|
||||||
(chatBarLoader.item as ChatBar).forceActiveFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (root.currentRoom.tagNames.includes("m.server_notice")) {
|
|
||||||
banner.text = i18nc("@info", "This room contains official messages from your homeserver.")
|
|
||||||
banner.show("message");
|
|
||||||
} else {
|
|
||||||
banner.hideIf("message");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: root.currentRoom.connection
|
|
||||||
function onIsOnlineChanged() {
|
|
||||||
if (!root.currentRoom.connection.isOnline) {
|
|
||||||
banner.text = i18nc("@info:status", "NeoChat is offline. Please check your network connection.");
|
|
||||||
banner.type = Kirigami.MessageType.Error;
|
|
||||||
banner.show("offline");
|
|
||||||
} else {
|
|
||||||
banner.hideIf("offline");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
header: ColumnLayout {
|
|
||||||
id: headerLayout
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
readonly property bool shouldShowPins: root.currentRoom.pinnedMessage.length > 0 && !Kirigami.Settings.isMobile
|
|
||||||
|
|
||||||
QQC2.Control {
|
|
||||||
id: pinControl
|
|
||||||
|
|
||||||
visible: headerLayout.shouldShowPins
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
color: Kirigami.Theme.backgroundColor
|
|
||||||
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
|
||||||
Kirigami.Theme.inherit: false
|
|
||||||
}
|
|
||||||
|
|
||||||
contentItem: RowLayout {
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Kirigami.Icon {
|
|
||||||
source: "pin-symbolic"
|
|
||||||
|
|
||||||
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
|
|
||||||
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Label {
|
|
||||||
text: root.currentRoom.pinnedMessage
|
|
||||||
maximumLineCount: 1
|
|
||||||
elide: Text.ElideRight
|
|
||||||
|
|
||||||
onLinkActivated: link => UrlHelper.openUrl(link)
|
|
||||||
onHoveredLinkChanged: if (hoveredLink.length > 0 && hoveredLink !== "1") {
|
|
||||||
(QQC2.ApplicationWindow.window as Main).hoverLinkIndicator.text = hoveredLink;
|
|
||||||
} else {
|
|
||||||
(QQC2.ApplicationWindow.window as Main).hoverLinkIndicator.text = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TapHandler {
|
|
||||||
onTapped: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomPinnedMessagesPage'), {
|
|
||||||
room: root.currentRoom
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title", "Pinned Messages")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Kirigami.Separator {
|
|
||||||
visible: headerLayout.shouldShowPins
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Kirigami.InlineMessage {
|
|
||||||
id: banner
|
|
||||||
|
|
||||||
// Used to keep track of messages so we can hide the right one at the right time
|
|
||||||
property string messageId
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
showCloseButton: true
|
|
||||||
visible: false
|
|
||||||
position: Kirigami.InlineMessage.Position.Header
|
|
||||||
|
|
||||||
function show(msgid: string): void {
|
|
||||||
messageId = msgid;
|
|
||||||
visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideIf(msgid: string): void {
|
|
||||||
if (messageId == msgid) {
|
|
||||||
visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: timelineViewLoader
|
|
||||||
anchors.fill: parent
|
|
||||||
// We need the loader to be active but invisible while the room is loading messages so signals in TimelineView work.
|
|
||||||
active: root.currentRoom && !root.currentRoom.isInvite && !root.currentRoom.isSpace
|
|
||||||
sourceComponent: TimelineView {
|
|
||||||
id: timelineView
|
|
||||||
messageFilterModel: root.messageFilterModel
|
|
||||||
compactLayout: NeoChatConfig.compactLayout
|
|
||||||
fileDropEnabled: !Controller.isFlatpak
|
|
||||||
markReadCondition: NeoChatConfig.markReadCondition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: invitationLoader
|
|
||||||
active: root.currentRoom && root.currentRoom.isInvite
|
|
||||||
anchors.fill: parent
|
|
||||||
sourceComponent: InvitationView {
|
|
||||||
currentRoom: root.currentRoom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: spaceLoader
|
|
||||||
active: root.currentRoom && root.currentRoom.isSpace
|
|
||||||
anchors.fill: parent
|
|
||||||
sourceComponent: SpaceHomePage {
|
|
||||||
room: root.currentRoom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
active: !RoomManager.currentRoom
|
|
||||||
anchors.centerIn: parent
|
|
||||||
sourceComponent: Kirigami.PlaceholderMessage {
|
|
||||||
icon.name: "org.kde.neochat"
|
|
||||||
text: i18nc("@title", "Welcome to NeoChat")
|
|
||||||
explanation: i18nc("@info:usagetip", "Select or join a room to get started")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
footer: Loader {
|
|
||||||
id: chatBarLoader
|
|
||||||
height: active ? (item as ChatBar)?.implicitHeight : 0
|
|
||||||
active: timelineViewLoader.active && !root.currentRoom.readOnly
|
|
||||||
sourceComponent: ChatBar {
|
|
||||||
id: chatBar
|
|
||||||
width: parent.width
|
|
||||||
currentRoom: root.currentRoom
|
|
||||||
connection: root.currentRoom.connection as NeoChatConnection
|
|
||||||
|
|
||||||
// Creating a reply (or doing anything in the chat bar) can change the height, but this isn't picked up on the root's onHeightChanged.
|
|
||||||
onHeightChanged: root.resetViewSettling()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: RoomManager
|
|
||||||
function onCurrentRoomChanged() {
|
|
||||||
if (root.currentRoom && root.currentRoom.isInvite) {
|
|
||||||
Controller.clearInvitationNotification(root.currentRoom.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onGoToEvent(eventId) {
|
|
||||||
(timelineViewLoader.item as TimelineView).goToEvent(eventId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: root.currentRoom.connection
|
|
||||||
function onJoinedRoom(room, invited) {
|
|
||||||
if (root.currentRoom.id === invited.id) {
|
|
||||||
RoomManager.resolveResource(room.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onPressed: event => {
|
|
||||||
if (event.key === Qt.Key_PageUp) {
|
|
||||||
event.accepted = true;
|
|
||||||
(timelineViewLoader.item as TimelineView).pageUp();
|
|
||||||
} else if (event.key === Qt.Key_PageDown) {
|
|
||||||
event.accepted = true;
|
|
||||||
(timelineViewLoader.item as TimelineView).pageDown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: RoomManager
|
|
||||||
|
|
||||||
function onShowMessage(messageType, message) {
|
|
||||||
banner.text = message;
|
|
||||||
banner.type = messageType;
|
|
||||||
banner.show("generic");
|
|
||||||
}
|
|
||||||
|
|
||||||
function onShowEventSource(eventId) {
|
|
||||||
(root.Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
|
||||||
sourceText: root.currentRoom.getEventJsonSource(eventId)
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title:dialog", "Message Source"),
|
|
||||||
width: Kirigami.Units.gridUnit * 25
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function onShowDelegateMenu(eventId: string, author, messageComponentType, plainText: string, richText: string, mimeType: string, progressInfo, selectedText: string, hoveredLink: string) {
|
|
||||||
(delegateContextMenu.createObject(root, {
|
|
||||||
author: author,
|
|
||||||
eventId: eventId,
|
|
||||||
plainText: plainText,
|
|
||||||
mimeType: mimeType,
|
|
||||||
progressInfo: progressInfo,
|
|
||||||
messageComponentType: messageComponentType,
|
|
||||||
selectedText,
|
|
||||||
hoveredLink,
|
|
||||||
}) as DelegateContextMenu).popup();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onShowMaximizedMedia(index) {
|
|
||||||
var popup = maximizeComponent.createObject(QQC2.Overlay.overlay, {
|
|
||||||
initialIndex: index
|
|
||||||
});
|
|
||||||
popup.closed.connect(() => {
|
|
||||||
timelineViewLoader.item.interactive = true;
|
|
||||||
popup.destroy();
|
|
||||||
});
|
|
||||||
popup.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onShowMaximizedCode(author, time, codeText, language) {
|
|
||||||
(Qt.createComponent('org.kde.neochat', 'CodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
|
||||||
author: author,
|
|
||||||
time: time,
|
|
||||||
codeText: codeText,
|
|
||||||
language: language
|
|
||||||
}) as CodeMaximizeComponent).open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: delegateContextMenu
|
|
||||||
DelegateContextMenu {
|
|
||||||
room: root.currentRoom
|
|
||||||
connection: root.currentRoom.connection as NeoChatConnection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: maximizeComponent
|
|
||||||
NeochatMaximizeComponent {
|
|
||||||
currentRoom: root.currentRoom
|
|
||||||
model: root.mediaMessageFilterModel
|
|
||||||
parent: root.QQC2.Overlay.overlay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user