Compare commits
189 Commits
work/nvrwh
...
work/nico/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94210a7ce7 | ||
|
|
280d90e191 | ||
|
|
b4b24430a1 | ||
|
|
b7b7f1817a | ||
|
|
3d67a682f4 | ||
|
|
da6df18367 | ||
|
|
0b1b1b8c8c | ||
|
|
2493a00ba4 | ||
|
|
d6ebb1308c | ||
|
|
332c311023 | ||
|
|
27d33d121a | ||
|
|
e954fc204f | ||
|
|
d1f7e7091e | ||
|
|
bd4eeb405b | ||
|
|
e6a060c192 | ||
|
|
f53a7a27f6 | ||
|
|
34384dced4 | ||
|
|
b68cfafab2 | ||
|
|
58b836fd1e | ||
|
|
90cad05bae | ||
|
|
072f7cec37 | ||
|
|
39388e204e | ||
|
|
6ccb201110 | ||
|
|
178b516c7c | ||
|
|
ac88e13e58 | ||
|
|
8d3e145e0b | ||
|
|
f40d1b9f4e | ||
|
|
e9cd165457 | ||
|
|
c0c86c67b6 | ||
|
|
12afa43d23 | ||
|
|
386f637b94 | ||
|
|
d7bd9f4609 | ||
|
|
33c9edc9a3 | ||
|
|
3b2dbc731e | ||
|
|
51a29ac528 | ||
|
|
cc8bf79a9b | ||
|
|
8d47e58861 | ||
|
|
47ce8a4846 | ||
|
|
71c9537c61 | ||
|
|
8825e6ec83 | ||
|
|
44ec93f0a0 | ||
|
|
ed7688e66f | ||
|
|
6b49854b12 | ||
|
|
e8484ebc7a | ||
|
|
17d01c68c4 | ||
|
|
dae2cbab90 | ||
|
|
b8e8fa3ee5 | ||
|
|
9c4a925171 | ||
|
|
8996806b05 | ||
|
|
2bd4579c10 | ||
|
|
0891f32c08 | ||
|
|
5287c2d529 | ||
|
|
084b89f3dc | ||
|
|
2dd3197beb | ||
|
|
6d9dca7da8 | ||
|
|
e0f16054fc | ||
|
|
fa70679439 | ||
|
|
949bd20873 | ||
|
|
79a9eb0de0 | ||
|
|
e1b9bc7d0e | ||
|
|
a1abf22174 | ||
|
|
fa27d993e2 | ||
|
|
d4b750433e | ||
|
|
9df534c72c | ||
|
|
f785e4d5b0 | ||
|
|
f186be7314 | ||
|
|
3cbcc2b597 | ||
|
|
61f3d6c9ae | ||
|
|
d8b2436f0d | ||
|
|
ea76edce74 | ||
|
|
5482aad7ba | ||
|
|
aaa26571d1 | ||
|
|
554e3576fd | ||
|
|
8d2c7ff8c2 | ||
|
|
92261eb94f | ||
|
|
4dfb7fc3e2 | ||
|
|
2728446692 | ||
|
|
dfb32fe687 | ||
|
|
55507112a9 | ||
|
|
d9aa77a9f4 | ||
|
|
c0ea52c331 | ||
|
|
f1b9d2329f | ||
|
|
0707fd8189 | ||
|
|
6bef2205db | ||
|
|
ace62b4df1 | ||
|
|
d76e512785 | ||
|
|
db2692c411 | ||
|
|
4c9bdd03ce | ||
|
|
efa2c012a7 | ||
|
|
072dc1b6a3 | ||
|
|
4066427168 | ||
|
|
b901c1bdf2 | ||
|
|
532310d739 | ||
|
|
4f7d32df2b | ||
|
|
833d2159e7 | ||
|
|
ccf8701395 | ||
|
|
5d696aabc4 | ||
|
|
ebd521e2ee | ||
|
|
9d5303113e | ||
|
|
3850fe15a5 | ||
|
|
5392481d06 | ||
|
|
0ce048517b | ||
|
|
c51e16e16c | ||
|
|
765a95050d | ||
|
|
38dcefffcb | ||
|
|
391b61dcb4 | ||
|
|
d76c9fcbcf | ||
|
|
f7b8ae2af2 | ||
|
|
ddbf9b60d4 | ||
|
|
8948ff5faa | ||
|
|
d270e202a8 | ||
|
|
61e1dd14ba | ||
|
|
eee93e0f1f | ||
|
|
826760a55c | ||
|
|
749398df8f | ||
|
|
150968d226 | ||
|
|
d81df24e7c | ||
|
|
594a5cf6ca | ||
|
|
0af420b824 | ||
|
|
31fed8362a | ||
|
|
dbcf8c6327 | ||
|
|
8012392400 | ||
|
|
3e48578b44 | ||
|
|
d7e656e57f | ||
|
|
8e83b923d9 | ||
|
|
a739f0f09f | ||
|
|
bc74737b0f | ||
|
|
e92fccf904 | ||
|
|
20cbedfff5 | ||
|
|
e0d508d3dd | ||
|
|
af318a2bae | ||
|
|
6b4e81c763 | ||
|
|
dcac63aa04 | ||
|
|
7818747e45 | ||
|
|
7cb1f856ca | ||
|
|
5955c8e7dc | ||
|
|
dee3c279e8 | ||
|
|
94427280d8 | ||
|
|
8b245b1cc9 | ||
|
|
0513cd10c4 | ||
|
|
28b5631d06 | ||
|
|
5f2cd92da7 | ||
|
|
4535125c54 | ||
|
|
8831da956a | ||
|
|
f2ec6e1d4c | ||
|
|
93f7def532 | ||
|
|
782f5517d3 | ||
|
|
f238c18ce8 | ||
|
|
4fe0ea373f | ||
|
|
982d21dd58 | ||
|
|
7002132bde | ||
|
|
1ef931f7e7 | ||
|
|
8797015c6a | ||
|
|
85a562d469 | ||
|
|
f50c62ba12 | ||
|
|
13f05a0995 | ||
|
|
1adddcc0d9 | ||
|
|
f03cd3f4c6 | ||
|
|
29a2e4eb99 | ||
|
|
7137a5808f | ||
|
|
fa6f451e11 | ||
|
|
666f247185 | ||
|
|
93dd25f954 | ||
|
|
8e2ba9552f | ||
|
|
1f02c5ea5e | ||
|
|
112b26c39d | ||
|
|
5e243ed01b | ||
|
|
706809d12a | ||
|
|
3fc06c2a74 | ||
|
|
4bc2c42982 | ||
|
|
6651fa4fa3 | ||
|
|
07d65a0046 | ||
|
|
4c9f062a70 | ||
|
|
893ee4a763 | ||
|
|
fa67d174d2 | ||
|
|
bb542521fb | ||
|
|
85d3cf2d77 | ||
|
|
ebf4cfb825 | ||
|
|
d7daa697df | ||
|
|
884484922d | ||
|
|
83ab751d4a | ||
|
|
fcee5bfa92 | ||
|
|
eb610ffe81 | ||
|
|
647cc25e57 | ||
|
|
3912b8e096 | ||
|
|
67f88416f1 | ||
|
|
8e3398df34 | ||
|
|
1a09405829 | ||
|
|
304054a4bb |
@@ -2,7 +2,7 @@
|
||||
"id": "org.kde.neochat",
|
||||
"branch": "master",
|
||||
"runtime": "org.kde.Platform",
|
||||
"runtime-version": "5.15-21.08",
|
||||
"runtime-version": "5.15-22.08",
|
||||
"sdk": "org.kde.Sdk",
|
||||
"command": "neochat",
|
||||
"tags": [
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@ compile_commands.json
|
||||
kate.project.ctags.*
|
||||
*.user
|
||||
.flatpak-builder/
|
||||
.idea/
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
include:
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/reuse-lint.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
|
||||
# TODO enable once we can have qt6 libQuotient on the CI
|
||||
# - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/flatpak.yml
|
||||
|
||||
38
.kde-ci.yml
38
.kde-ci.yml
@@ -1,8 +1,8 @@
|
||||
# SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
||||
# SPDX-FileCopyrightText: 2021 Tobias Fella <tobias.fella@kde.org>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
Dependencies:
|
||||
- 'on': ['@all']
|
||||
- 'on': ['Linux/Qt5', 'Android/Qt5', 'FreeBSD/Qt5', 'Windows/Qt5']
|
||||
'require':
|
||||
'frameworks/extra-cmake-modules': '@stable'
|
||||
'frameworks/kcoreaddons': '@stable'
|
||||
@@ -18,15 +18,43 @@ Dependencies:
|
||||
'third-party/libquotient': '@latest'
|
||||
'third-party/qtkeychain': '@latest'
|
||||
'third-party/cmark': '@latest'
|
||||
- 'on': ['Windows', 'Linux', 'FreeBSD']
|
||||
'third-party/qcoro': '@latest'
|
||||
- 'on': ['Windows/Qt5', 'Linux/Qt5', 'FreeBSD/Qt5']
|
||||
'require':
|
||||
'frameworks/qqc2-desktop-style': '@stable'
|
||||
'frameworks/kio': '@stable'
|
||||
'frameworks/kwindowsystem': '@stable'
|
||||
'frameworks/kconfigwidgets': '@stable'
|
||||
- 'on': ['Linux', 'FreeBSD']
|
||||
- 'on': ['Linux/Qt5', 'FreeBSD/Qt5']
|
||||
'require':
|
||||
'frameworks/kdbusaddons': '@stable'
|
||||
|
||||
- 'on': ['Linux/Qt6', 'Android/Qt6', 'FreeBSD/Qt6', 'Windows/Qt6']
|
||||
'require':
|
||||
'frameworks/extra-cmake-modules': '@latest-kf6'
|
||||
'frameworks/kcoreaddons': '@latest-kf6'
|
||||
'frameworks/kirigami': '@latest-kf6'
|
||||
'frameworks/ki18n': '@latest-kf6'
|
||||
'frameworks/kconfig': '@latest-kf6'
|
||||
'frameworks/syntax-highlighting': '@latest-kf6'
|
||||
'frameworks/kitemmodels': '@latest-kf6'
|
||||
'frameworks/knotifications': '@latest-kf6'
|
||||
'libraries/kquickimageeditor': '@latest-kf6'
|
||||
'frameworks/sonnet': '@latest-kf6'
|
||||
'libraries/kirigami-addons': '@latest-kf6'
|
||||
'third-party/libquotient': '@latest'
|
||||
'third-party/qtkeychain': '@latest'
|
||||
'third-party/cmark': '@latest'
|
||||
'third-party/qcoro': '@latest'
|
||||
- 'on': ['Windows/Qt6', 'Linux/Qt6', 'FreeBSD/Qt6']
|
||||
'require':
|
||||
'frameworks/qqc2-desktop-style': '@latest-kf6'
|
||||
'frameworks/kio': '@latest-kf6'
|
||||
'frameworks/kwindowsystem': '@latest-kf6'
|
||||
'frameworks/kconfigwidgets': '@latest-kf6'
|
||||
- 'on': ['Linux/Qt6', 'FreeBSD/Qt6']
|
||||
'require':
|
||||
'frameworks/kdbusaddons': '@latest-kf6'
|
||||
|
||||
Options:
|
||||
require-passing-tests-on: [ 'Linux', 'FreeBSD', 'Windows' ]
|
||||
require-passing-tests-on: [ 'Linux/Qt5', 'FreeBSD', 'Windows' ]
|
||||
|
||||
@@ -7,7 +7,7 @@ Copyright: 2020 Carson Black <uhhadd@gmail.com>
|
||||
License: LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
|
||||
Files: android/res/drawable/splash.xml
|
||||
Copyright: 2020 Tobias Fella <fella@posteo.de>
|
||||
Copyright: 2020 Tobias Fella <tobias.fella@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: .gitignore
|
||||
@@ -27,11 +27,11 @@ Copyright: 2021 Carl Schwan <carlschwan@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: src/neochatconfig.kcfg
|
||||
Copyright: 2020-2021 Carl Schwan <carlschwan@kde.org>, Tobias Fella <fella@posteo.de>
|
||||
Copyright: 2020-2021 Carl Schwan <carlschwan@kde.org>, Tobias Fella <tobias.fella@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: src/neochat.notifyrc
|
||||
Copyright: 2020 Tobias Fella <fella@posteo.de>
|
||||
Copyright: 2020 Tobias Fella <tobias.fella@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: src/qml/Component/confetti.png src/qml/Component/glowdot.png
|
||||
@@ -39,5 +39,5 @@ Copyright: 2021 Alexey Andreyev <aa13q@ya.ru>
|
||||
License: CC0-1.0
|
||||
|
||||
Files: .flatpak-manifest.json
|
||||
Copyright: 2020-2022 Tobias Fella <fella@posteo.de>
|
||||
Copyright: 2020-2022 Tobias Fella <tobias.fella@kde.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
# 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 <fella@posteo.de>
|
||||
# SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
||||
# SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(NeoChat)
|
||||
set(PROJECT_VERSION "22.11")
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "23")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "03")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
set(KF5_MIN_VERSION "5.91.0")
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
|
||||
set(KF_MIN_VERSION "5.91.0")
|
||||
set(QT_MIN_VERSION "5.15.2")
|
||||
if (ANDROID)
|
||||
set(QT_MIN_VERSION "5.15.8")
|
||||
endif()
|
||||
|
||||
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
||||
|
||||
@@ -49,16 +57,16 @@ set_package_properties(Qt${QT_MAJOR_VERSION} PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
)
|
||||
find_package(KF5 ${KF5_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels)
|
||||
set_package_properties(KF5 PROPERTIES
|
||||
find_package(KF${QT_MAJOR_VERSION} ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels)
|
||||
set_package_properties(KF${QT_MAJOR_VERSION} PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
)
|
||||
set_package_properties(KF5Kirigami2 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Kirigami application UI framework"
|
||||
)
|
||||
find_package(KF5KirigamiAddons 0.6 REQUIRED)
|
||||
set_package_properties(KF${QT_MAJOR_VERSION}Kirigami2 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Kirigami application UI framework"
|
||||
)
|
||||
find_package(KF${QT_MAJOR_VERSION}KirigamiAddons 0.7.2 REQUIRED)
|
||||
|
||||
find_package(Qt${QT_MAJOR_VERSION}Keychain)
|
||||
set_package_properties(Qt${QT_MAJOR_VERSION}Keychain PROPERTIES
|
||||
@@ -74,15 +82,15 @@ if(ANDROID)
|
||||
)
|
||||
else()
|
||||
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} COMPONENTS Widgets)
|
||||
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle ConfigWidgets KIO WindowSystem)
|
||||
set_package_properties(KF5QQC2DesktopStyle PROPERTIES
|
||||
find_package(KF${QT_MAJOR_VERSION} ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle ConfigWidgets KIO WindowSystem)
|
||||
set_package_properties(KF${QT_MAJOR_VERSION}QQC2DesktopStyle PROPERTIES
|
||||
TYPE RUNTIME
|
||||
)
|
||||
ecm_find_qmlmodule(org.kde.syntaxhighlighting 1.0)
|
||||
endif()
|
||||
|
||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||
find_package(KF5DBusAddons ${KF5_MIN_VERSION} REQUIRED)
|
||||
find_package(KF${QT_MAJOR_VERSION}DBusAddons ${KF_MIN_VERSION} REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(Quotient 0.6)
|
||||
@@ -116,12 +124,14 @@ find_package(QCoro${QT_MAJOR_VERSION} 0.4 COMPONENTS Core REQUIRED)
|
||||
|
||||
qcoro_enable_coroutines()
|
||||
|
||||
find_package(KF5DocTools ${KF5_MIN_VERSION})
|
||||
set_package_properties(KF5DocTools PROPERTIES DESCRIPTION
|
||||
find_package(KF${QT_MAJOR_VERSION}DocTools ${KF_MIN_VERSION})
|
||||
set_package_properties(KF${QT_MAJOR_VERSION}DocTools PROPERTIES DESCRIPTION
|
||||
"Tools to generate documentation"
|
||||
TYPE OPTIONAL
|
||||
)
|
||||
|
||||
find_package(Sqlite3)
|
||||
|
||||
if(NOT Quotient_VERSION_MINOR GREATER 6)
|
||||
cmake_policy(SET CMP0063 OLD)
|
||||
endif()
|
||||
@@ -145,7 +155,7 @@ if (BUILD_TESTING AND Quotient_VERSION_MINOR GREATER 6)
|
||||
add_subdirectory(autotests)
|
||||
endif()
|
||||
|
||||
if(KF5DocTools_FOUND)
|
||||
if(KF${QT_MAJOR_VERSION}DocTools_FOUND)
|
||||
kdoctools_install(po)
|
||||
add_subdirectory(doc)
|
||||
endif()
|
||||
|
||||
0
LICENSES/MIT.txt
Executable file → Normal file
0
LICENSES/MIT.txt
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2020-2021 Carl Schwan <carlschwan@kde.org>
|
||||
SPDX-FileCopyrightText: 2020-2021 Tobias Fella <fella@posteo.de>
|
||||
SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
# NeoChat
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
android:name="org.qtproject.qt5.android.bindings.QtActivity"
|
||||
android:label="NeoChat"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:launchMode="singleTop">
|
||||
android:launchMode="singleTop"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
@@ -22,7 +23,6 @@
|
||||
</intent-filter>
|
||||
|
||||
<meta-data android:name="android.app.lib_name" android:value="neochat-app"/>
|
||||
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||
@@ -38,8 +38,6 @@
|
||||
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
|
||||
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
|
||||
<!-- Messages maps -->
|
||||
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
||||
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
||||
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||
|
||||
<!-- Splash screen -->
|
||||
|
||||
@@ -12,7 +12,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.4'
|
||||
classpath 'com.android.tools.build:gradle:7.0.2'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,10 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion qtMinSdkVersion
|
||||
targetSdkVersion qtTargetSdkVersion
|
||||
applicationId "org.kde.neochat"
|
||||
namespace "org.kde.neochat"
|
||||
versionCode timestamp
|
||||
versionName projectVersionFull
|
||||
manifestPlaceholders = [versionName: projectVersionFull, versionCode: timestamp]
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
|
||||
#define protected public // please don't hate me
|
||||
#include "neochatroom.h"
|
||||
#undef protected
|
||||
|
||||
#include <connection.h>
|
||||
#include <quotient_common.h>
|
||||
@@ -15,12 +13,23 @@
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
class TestRoom : public NeoChatRoom
|
||||
{
|
||||
public:
|
||||
using NeoChatRoom::NeoChatRoom;
|
||||
|
||||
void update(SyncRoomData &&data, bool fromCache = false)
|
||||
{
|
||||
Room::updateData(std::move(data), fromCache);
|
||||
}
|
||||
};
|
||||
|
||||
class NeoChatRoomTest : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
Connection *connection = nullptr;
|
||||
NeoChatRoom *room = nullptr;
|
||||
TestRoom *room = nullptr;
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
@@ -31,7 +40,7 @@ private Q_SLOTS:
|
||||
void NeoChatRoomTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
room = new NeoChatRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
||||
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
|
||||
|
||||
auto json = QJsonDocument::fromJson(R"EVENT({
|
||||
"account_data": {
|
||||
@@ -121,7 +130,7 @@ void NeoChatRoomTest::initTestCase()
|
||||
}
|
||||
})EVENT");
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, json.object());
|
||||
room->updateData(std::move(roomData));
|
||||
room->update(std::move(roomData));
|
||||
}
|
||||
|
||||
void NeoChatRoomTest::subtitleTextTest()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<!--
|
||||
- SPDX-License-Identifier: CC0-1.0
|
||||
- SPDX-FileCopyrightText: 2020-2021 Carl Schwan <carlschwan@kde.org>
|
||||
- SPDX-FileCopyrightText: 2020-2021 Tobias Fella <fella@posteo.de>
|
||||
- SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
||||
-->
|
||||
<component type="desktop">
|
||||
<id>org.kde.neochat</id>
|
||||
@@ -16,6 +16,7 @@
|
||||
<name xml:lang="ca-valencia">NeoChat</name>
|
||||
<name xml:lang="cs">NeoChat</name>
|
||||
<name xml:lang="de">NeoChat</name>
|
||||
<name xml:lang="el">NeoChat</name>
|
||||
<name xml:lang="en-GB">NeoChat</name>
|
||||
<name xml:lang="es">NeoChat</name>
|
||||
<name xml:lang="eu">NeoChat</name>
|
||||
@@ -50,6 +51,7 @@
|
||||
<summary xml:lang="ca-valencia">Un client per a Matrix, el protocol de comunicacions descentralitzat</summary>
|
||||
<summary xml:lang="cs">Klient pro decentralizovaný komunikační protokol matrix</summary>
|
||||
<summary xml:lang="de">Ein Programm für Matrix, das dezentrale Kommunikationsprotokoll</summary>
|
||||
<summary xml:lang="el">Ένας πελάτης για το Matrix, το αποκεντρωμένο πρωτόκολλο επικοινωνίας</summary>
|
||||
<summary xml:lang="en-GB">A client for matrix, the decentralised communication protocol</summary>
|
||||
<summary xml:lang="es">Un cliente para Matrix, el protocolo de comunicaciones descentralizado</summary>
|
||||
<summary xml:lang="eu">Matrix, deszentralizatutako komunikazio protokolorako bezero bat</summary>
|
||||
@@ -83,6 +85,7 @@
|
||||
<p xml:lang="ca">El NeoChat és un client de Matrix. Permet enviar missatges de text, fitxers de vídeo i d'àudio a la família, col·legues i amics usant el protocol Matrix.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat és un client de Matrix. Permet enviar missatges de text, fitxers de vídeo i d'àudio a la família, col·legues i amics utilitzant el protocol Matrix.</p>
|
||||
<p xml:lang="de">NeoChat ist ein Matrix-Client. Er ermöglicht Ihnen das Senden von Textnachrichten, Videos und Audiodateien an Ihre Familie, Kollegen und Freunde unter Verwendung des Matrix-Protokolls.</p>
|
||||
<p xml:lang="el">Το NeoChat είναι μια εφαρμογή του Matrix. Σας επιτρέπει να στέλνετε μηνύματα κειμένου, βίντεο και ήχο στην οικογένειά σας, σε συναδέλφους και φίλους με το πρωτόκολλο Matrix.</p>
|
||||
<p xml:lang="en-GB">NeoChat is a Matrix client. It allows you to send text messages, videos and audio files to your family, colleagues and friends using the Matrix protocol.</p>
|
||||
<p xml:lang="es">NeoChat es un cliente para Matrix. Le permite enviar mensajes de texto, vídeos y archivos de sonido a su familia, compañeros de trabajo y amigos usando el protocolo Matrix.</p>
|
||||
<p xml:lang="eu">NeoChat Matrix bezero bat da. Familiari, lankideei eta lagunei testu-mezuak, bideoak eta audio-fitxategiak bidaltzeko aukera ematen du, Matrix protokoloa erabiliz.</p>
|
||||
@@ -113,6 +116,7 @@
|
||||
<p xml:lang="ca">Matrix és un protocol de comunicacions descentralitzat, que retorna el control a l'usuari. Actualment el NeoChat implementa una gran part del protocol amb l'excepció dels xats encriptats i els xats de vídeo.</p>
|
||||
<p xml:lang="ca-valencia">Matrix és un protocol de comunicacions descentralitzat, que retorna el control a l'usuari. Actualment NeoChat implementa una gran part del protocol amb l'excepció dels xats encriptats i els xats de vídeo.</p>
|
||||
<p xml:lang="de">Matrix ist ein dezentralisiertes Kommunikationsprotokoll, das dem Benutzer wieder die Kontrolle zurückgibt. Derzeit implementiert NeoChat einen großen Teil des Protokolls mit der Ausnahme von verschlüsselten Chats und Video-Chat.</p>
|
||||
<p xml:lang="el">Το Matrix είναι ένα αποκεντρωμένο πρωτόκολλο επικοινωνίας, δίνοντας πίσω στον χρήστη τον έλεγχο. Προς το παρόν το NeoChat υλοποιεί ένα μεγάλο μέρος του πρωτοκόλλου με εξαίρεση τις κρυπτογραφημένες συνομιλίες και τη συνομιλία με βίντεο.</p>
|
||||
<p xml:lang="en-GB">Matrix is a decentralised communication protocol, putting the user back in control. Currently NeoChat implements large part of the protocol with the exception of encrypted chats and video chat.</p>
|
||||
<p xml:lang="es">Matrix es un protocolo de comunicaciones descentralizado, que devuelve el control al usuario. En la actualidad, NeoChat implementa gran parte del protocolo con la excepción de chats cifrados y chats de vídeo.</p>
|
||||
<p xml:lang="eu">Matrix komunikazio-protokolo deszentralizatu bat da, erabiltzaileari kontrola itzultzen diona. Gaur egun, NeoChat-ek protokoloaren zati handi bat inplementatzen du, berriketa zifratuak eta bideo berriketak izan ezik.</p>
|
||||
@@ -142,7 +146,8 @@
|
||||
<p xml:lang="az">Vahid istifadəçi interfeysi ilə təmin olunan NeoChat, həm mobil telefonda həm də kompyuterlərdə işləyir.</p>
|
||||
<p xml:lang="ca">El NeoChat funciona en els mòbils i a l'escriptori, proporcionant una experiència d'usuari coherent.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat funciona en els mòbils i en l'escriptori, proporcionant una experiència d'usuari coherent.</p>
|
||||
<p xml:lang="de">NeoChat funktioniert sowohl auf dem Mobiltelefon als auch auf dem Arbeitsfläche und bietet ein einheitliches Benutzererlebnis. </p>
|
||||
<p xml:lang="de">NeoChat funktioniert sowohl auf Mobilgeräten als auch auf dem PC und bietet ein einheitliches Benutzererlebnis.</p>
|
||||
<p xml:lang="el">Το NeoChat λειτουργεί και στα κινητά και στους υπολογιστές γραφείου παρέχοντας μια αδιάλειπτη εμπειρία χρήσης.</p>
|
||||
<p xml:lang="en-GB">NeoChat works both on mobile and desktop while providing a consistent user experience.</p>
|
||||
<p xml:lang="es">NeoChat funciona en móviles y en el escritorio a la vez que proporciona una experiencia de usuario consistente.</p>
|
||||
<p xml:lang="eu">NeoChat mugikorretan eta mahaigainean dabil, erabiltzaile esperientzia koherentea eskainiz.</p>
|
||||
@@ -174,12 +179,13 @@
|
||||
<category>Network</category>
|
||||
</categories>
|
||||
<developer_name>The KDE Community</developer_name>
|
||||
<developer_name xml:lang="ar">مجتمع كدي</developer_name>
|
||||
<developer_name xml:lang="ar">مجتمع كِيدِي</developer_name>
|
||||
<developer_name xml:lang="az">KDE Cəmiyyəti</developer_name>
|
||||
<developer_name xml:lang="ca">La comunitat KDE</developer_name>
|
||||
<developer_name xml:lang="ca-valencia">La comunitat KDE</developer_name>
|
||||
<developer_name xml:lang="cs">Komunita KDE</developer_name>
|
||||
<developer_name xml:lang="de">Die KDE-Gemeinschaft</developer_name>
|
||||
<developer_name xml:lang="el">Η Κοινότητα του KDE</developer_name>
|
||||
<developer_name xml:lang="en-GB">The KDE Community</developer_name>
|
||||
<developer_name xml:lang="es">La comunidad KDE</developer_name>
|
||||
<developer_name xml:lang="eu">KDE komunitatea</developer_name>
|
||||
@@ -210,6 +216,7 @@
|
||||
<project_license>GPL-3.0</project_license>
|
||||
<custom>
|
||||
<value key="KDE::matrix">#neochat:kde.org</value>
|
||||
<value key="KDE::windows_store">https://www.microsoft.com/store/apps/9PNXWVNRC29H</value>
|
||||
</custom>
|
||||
<launchable type="desktop-id">org.kde.neochat.desktop</launchable>
|
||||
<screenshots>
|
||||
@@ -224,6 +231,20 @@
|
||||
<content_attribute id="social-chat">intense</content_attribute>
|
||||
</content_rating>
|
||||
<releases>
|
||||
<release version="23.01" date="2023-01-30">
|
||||
<url>https://plasma-mobile.org/2023/01/30/january-blog-post/</url>
|
||||
<description>
|
||||
<p>New features and bugfixes:</p>
|
||||
<ul>
|
||||
<li>Notifications will now be shown for all accounts, not just the active one</li>
|
||||
<li>There is a new "compact" mode for the room list</li>
|
||||
<li>You can now search in the room history</li>
|
||||
<li>Emojis and Reactions have been significantly improved</li>
|
||||
<li>Fixed several crashes around user invitations</li>
|
||||
<li>Room permission settings can now be configured</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="22.11" date="2022-11-30">
|
||||
<url>https://plasma-mobile.org/2022/11/30/plasma-mobile-gear-22-11/</url>
|
||||
</release>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
# SPDX-FileCopyrightText: 2020 Tobias Fella <fella@posteo.de>
|
||||
# SPDX-FileCopyrightText: 2020 Tobias Fella <tobias.fella@kde.org>
|
||||
[Desktop Entry]
|
||||
Version=1.5
|
||||
Name=NeoChat
|
||||
@@ -9,6 +9,7 @@ Name[ca]=NeoChat
|
||||
Name[ca@valencia]=NeoChat
|
||||
Name[cs]=NeoChat
|
||||
Name[de]=NeoChat
|
||||
Name[el]=NeoChat
|
||||
Name[en_GB]=NeoChat
|
||||
Name[es]=NeoChat
|
||||
Name[eu]=NeoChat
|
||||
@@ -45,6 +46,7 @@ GenericName[ca]=Client de Matrix
|
||||
GenericName[ca@valencia]=Client de Matrix
|
||||
GenericName[cs]=Klient protokolu Matrix
|
||||
GenericName[de]=Matrix-Programm
|
||||
GenericName[el]=Εφαρμογή του Matrix
|
||||
GenericName[en_GB]=Matrix Client
|
||||
GenericName[es]=Cliente para Matrix
|
||||
GenericName[eu]=Matrix bezeroa
|
||||
@@ -80,6 +82,7 @@ Comment[az]=Matrix protokolu üçün müştəri
|
||||
Comment[ca]=Client per al protocol Matrix
|
||||
Comment[ca@valencia]=Client per al protocol Matrix
|
||||
Comment[de]=Programm für das Matrix-Protokoll
|
||||
Comment[el]=Πελάτης για το πρωτόκολλο Matrix
|
||||
Comment[en_GB]=Client for the Matrix protocol
|
||||
Comment[es]=Cliente para el protocolo Matrix
|
||||
Comment[eu]=Matrix protokolorako bezeroa
|
||||
|
||||
2180
po/ar/neochat.po
2180
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
2349
po/az/neochat.po
2349
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
2183
po/ca/neochat.po
2183
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2624
po/cs/neochat.po
2624
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
2148
po/da/neochat.po
2148
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
3008
po/de/neochat.po
3008
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
3870
po/el/neochat.po
Normal file
3870
po/el/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
2875
po/en_GB/neochat.po
2875
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
2197
po/es/neochat.po
2197
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
2230
po/eu/neochat.po
2230
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
2343
po/fi/neochat.po
2343
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
2216
po/fr/neochat.po
2216
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
2348
po/hu/neochat.po
2348
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
2585
po/ia/neochat.po
2585
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
2271
po/id/neochat.po
2271
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
2212
po/ie/neochat.po
2212
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
122
po/it/docs/neochat/man-neochat.1.docbook
Normal file
122
po/it/docs/neochat/man-neochat.1.docbook
Normal file
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
|
||||
<!ENTITY % Italian "INCLUDE">
|
||||
]>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
-->
|
||||
|
||||
<refentry lang="&language;">
|
||||
<refentryinfo>
|
||||
<title
|
||||
>Manuale utente di NeoChat</title>
|
||||
<author
|
||||
><firstname
|
||||
>Carl</firstname
|
||||
><surname
|
||||
>Schwan</surname
|
||||
> <contrib
|
||||
>Pagina man di NeoChat.</contrib
|
||||
> <email
|
||||
>carl@carlschwan.eu</email
|
||||
></author>
|
||||
<date
|
||||
>1/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
|
||||
>Client per l'interazione con il protocollo di messaggistica 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
|
||||
>Descrizione</title>
|
||||
<para
|
||||
><command
|
||||
>neochat</command
|
||||
> è un'applicazione di chat per il protocollo Matrix che funziona sia su desktop che su dispositivi mobili. </para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="options"
|
||||
><title
|
||||
>Opzioni</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term
|
||||
><option
|
||||
>URI</option
|
||||
></term>
|
||||
<listitem>
|
||||
<para
|
||||
>L'URI matrix per un utente o una stanza. ad esempio matrix:u/utente:esempio.org e matrix:r/stanza:esempio.org. Questo farà in modo che NeoChat provi ad aprire la stanza o la conversazione specificata. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="bug">
|
||||
<title
|
||||
>Segnalazione bug</title>
|
||||
<para
|
||||
>Puoi segnalare bug e richiedere funzionalità su <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
|
||||
>Vedi anche</title>
|
||||
<simplelist>
|
||||
<member
|
||||
>Un elenco di domande frequenti su 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
|
||||
>Copyright</title>
|
||||
<para
|
||||
>Copyright © 2020-2022 Tobias Fella </para>
|
||||
<para
|
||||
>Copyright © 2020-2022 Carl Schwan </para>
|
||||
<para
|
||||
>Licenza: GNU General Public Version 3 o successiva <<ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
|
||||
>></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
2225
po/it/neochat.po
2225
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
2131
po/ja/neochat.po
2131
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
2172
po/ka/neochat.po
2172
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
2323
po/ko/neochat.po
2323
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
3743
po/lt/neochat.po
Normal file
3743
po/lt/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
2179
po/nl/neochat.po
2179
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
2172
po/nn/neochat.po
2172
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
2321
po/pa/neochat.po
2321
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
2231
po/pl/neochat.po
2231
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
2148
po/pt/neochat.po
2148
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
2350
po/pt_BR/neochat.po
2350
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
2248
po/ru/neochat.po
2248
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
2357
po/sk/neochat.po
2357
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
2175
po/sl/neochat.po
2175
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
2331
po/sv/neochat.po
2331
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
2233
po/ta/neochat.po
2233
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
2200
po/tok/neochat.po
2200
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
5
po/tr/docs/neochat/CMakeLists.txt
Normal file
5
po/tr/docs/neochat/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
kdoctools_create_manpage(man-neochat.1.docbook 1 INSTALL_DESTINATION ${MAN_INSTALL_DIR})
|
||||
122
po/tr/docs/neochat/man-neochat.1.docbook
Normal file
122
po/tr/docs/neochat/man-neochat.1.docbook
Normal file
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
|
||||
<!ENTITY % Turkish "INCLUDE">
|
||||
]>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
-->
|
||||
|
||||
<refentry lang="&language;">
|
||||
<refentryinfo>
|
||||
<title
|
||||
>NeoChat Kullanıcı Kılavuzu</title>
|
||||
<author
|
||||
><firstname
|
||||
>Carl</firstname
|
||||
><surname
|
||||
>Schwan</surname
|
||||
> <contrib
|
||||
>NeoChat man page.</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 iletileşme protokolü ile etkileşim için istemci</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
|
||||
>Açıklama</title>
|
||||
<para
|
||||
><command
|
||||
>neochat</command
|
||||
>, Matrix protokolü için hem masaüstünde hem de taşınabilir aygıtlarda çalışan bir sohbet uygulamasıdır. </para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="options"
|
||||
><title
|
||||
>Seçenekler</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term
|
||||
><option
|
||||
>URI</option
|
||||
></term>
|
||||
<listitem>
|
||||
<para
|
||||
>Bir kullanıcı veya oda için matrix URI'si; örneğin, matrix:u/kullanıcı:örnek.org ve matrix:r/kök:örnek.org. Bu, NeoChat'in verilen odayı veya konuşmayı açmayı denemesini sağlar. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="bug">
|
||||
<title
|
||||
>Hata Bildirme</title>
|
||||
<para
|
||||
>Hataları veya özellik isteklerini <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
|
||||
> bağlantısından bildirebilirsiniz</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title
|
||||
>Ayrıca</title>
|
||||
<simplelist>
|
||||
<member
|
||||
>Matrix üzerine sıkça sorulan soruların bir listesi: <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
|
||||
>Telif Hakkı</title>
|
||||
<para
|
||||
>Telif hakkı © 2020-2022 Tobias Fella </para>
|
||||
<para
|
||||
>Telif hakkı © 2020-2022 Carl Schwan </para>
|
||||
<para
|
||||
>Lisans: GNU Genel Kamu Lisansa, 3. sürüm veya sonrası <<ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
|
||||
>></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
2208
po/tr/neochat.po
2208
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
2193
po/uk/neochat.po
2193
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
2237
po/zh_CN/neochat.po
2237
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
2145
po/zh_TW/neochat.po
2145
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -1,51 +1,52 @@
|
||||
# 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 <fella@posteo.de>
|
||||
# SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
add_library(neochat STATIC
|
||||
controller.cpp
|
||||
actionshandler.cpp
|
||||
emojimodel.cpp
|
||||
models/emojimodel.cpp
|
||||
emojitones.cpp
|
||||
customemojimodel.cpp
|
||||
models/customemojimodel.cpp
|
||||
clipboard.cpp
|
||||
matriximageprovider.cpp
|
||||
messageeventmodel.cpp
|
||||
messagefiltermodel.cpp
|
||||
roomlistmodel.cpp
|
||||
sortfilterspacelistmodel.cpp
|
||||
models/messageeventmodel.cpp
|
||||
models/messagefiltermodel.cpp
|
||||
models/roomlistmodel.cpp
|
||||
models/sortfilterspacelistmodel.cpp
|
||||
spacehierarchycache.cpp
|
||||
roommanager.cpp
|
||||
neochatroom.cpp
|
||||
neochatuser.cpp
|
||||
userlistmodel.cpp
|
||||
publicroomlistmodel.cpp
|
||||
userdirectorylistmodel.cpp
|
||||
keywordnotificationrulemodel.cpp
|
||||
models/userlistmodel.cpp
|
||||
models/userfiltermodel.cpp
|
||||
models/publicroomlistmodel.cpp
|
||||
models/userdirectorylistmodel.cpp
|
||||
models/keywordnotificationrulemodel.cpp
|
||||
utils.cpp
|
||||
notificationsmanager.cpp
|
||||
sortfilterroomlistmodel.cpp
|
||||
models/sortfilterroomlistmodel.cpp
|
||||
chatdocumenthandler.cpp
|
||||
devicesmodel.cpp
|
||||
models/devicesmodel.cpp
|
||||
filetypesingleton.cpp
|
||||
login.cpp
|
||||
stickerevent.cpp
|
||||
webshortcutmodel.cpp
|
||||
models/webshortcutmodel.cpp
|
||||
blurhash.cpp
|
||||
blurhashimageprovider.cpp
|
||||
joinrulesevent.cpp
|
||||
collapsestateproxymodel.cpp
|
||||
models/collapsestateproxymodel.cpp
|
||||
urlhelper.cpp
|
||||
windowcontroller.cpp
|
||||
linkpreviewer.cpp
|
||||
completionmodel.cpp
|
||||
completionproxymodel.cpp
|
||||
actionsmodel.cpp
|
||||
serverlistmodel.cpp
|
||||
statemodel.cpp
|
||||
models/completionmodel.cpp
|
||||
models/completionproxymodel.cpp
|
||||
models/actionsmodel.cpp
|
||||
models/serverlistmodel.cpp
|
||||
models/statemodel.cpp
|
||||
filetransferpseudojob.cpp
|
||||
searchmodel.cpp
|
||||
models/searchmodel.cpp
|
||||
)
|
||||
|
||||
add_executable(neochat-app
|
||||
@@ -78,7 +79,7 @@ if(NOT ANDROID)
|
||||
else()
|
||||
target_sources(neochat PRIVATE trayicon.cpp)
|
||||
endif()
|
||||
target_link_libraries(neochat PUBLIC KF5::ConfigWidgets KF5::WindowSystem)
|
||||
target_link_libraries(neochat PUBLIC KF${QT_MAJOR_VERSION}::ConfigWidgets KF${QT_MAJOR_VERSION}::WindowSystem)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_COLORSCHEME)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_WINDOWSYSTEM)
|
||||
endif()
|
||||
@@ -86,13 +87,14 @@ endif()
|
||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||
target_sources(neochat-app PRIVATE res_desktop.qrc)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_RUNNER)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_X11)
|
||||
target_sources(neochat PRIVATE runner.cpp)
|
||||
else()
|
||||
target_sources(neochat-app PRIVATE res_android.qrc)
|
||||
endif()
|
||||
|
||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR})
|
||||
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF5::I18n KF5::Kirigami2 KF5::Notifications KF5::ConfigCore KF5::ConfigGui KF5::CoreAddons KF5::SonnetCore KF5::ItemModels Quotient cmark::cmark ${QTKEYCHAIN_LIBRARIES} QCoro::Core)
|
||||
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF${QT_MAJOR_VERSION}::I18n KF${QT_MAJOR_VERSION}::Kirigami2 KF${QT_MAJOR_VERSION}::Notifications KF${QT_MAJOR_VERSION}::ConfigCore KF${QT_MAJOR_VERSION}::ConfigGui KF${QT_MAJOR_VERSION}::CoreAddons KF${QT_MAJOR_VERSION}::SonnetCore KF${QT_MAJOR_VERSION}::ItemModels Quotient cmark::cmark ${QTKEYCHAIN_LIBRARIES} QCoro::Core)
|
||||
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
||||
|
||||
if(NEOCHAT_FLATPAK)
|
||||
@@ -102,6 +104,9 @@ 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
|
||||
@@ -158,7 +163,7 @@ if(ANDROID)
|
||||
"zoom-out"
|
||||
"image-rotate-left-symbolic"
|
||||
"image-rotate-right-symbolic"
|
||||
"channel-insecure-symbolic"
|
||||
"channel-secure-symbolic"
|
||||
"download"
|
||||
"smiley"
|
||||
"tools-check-spelling"
|
||||
@@ -169,9 +174,10 @@ if(ANDROID)
|
||||
"favorite"
|
||||
"window-new"
|
||||
"globe"
|
||||
"visibility"
|
||||
)
|
||||
else()
|
||||
target_link_libraries(neochat PUBLIC Qt::Widgets KF5::KIOWidgets)
|
||||
target_link_libraries(neochat PUBLIC Qt::Widgets KF${QT_MAJOR_VERSION}::KIOWidgets)
|
||||
install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
|
||||
endif()
|
||||
|
||||
@@ -179,12 +185,12 @@ if(NOT ANDROID)
|
||||
set_target_properties(neochat-app PROPERTIES OUTPUT_NAME "neochat")
|
||||
endif()
|
||||
|
||||
if(TARGET KF5::DBusAddons)
|
||||
target_link_libraries(neochat PUBLIC KF5::DBusAddons)
|
||||
if(TARGET KF${QT_MAJOR_VERSION}::DBusAddons)
|
||||
target_link_libraries(neochat PUBLIC KF${QT_MAJOR_VERSION}::DBusAddons)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_KDBUSADDONS)
|
||||
endif()
|
||||
|
||||
if (TARGET KF5::KIOWidgets)
|
||||
if (TARGET KF${QT_MAJOR_VERSION}::KIOWidgets)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_KIO)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
#include <KLocalizedString>
|
||||
#include <QStringBuilder>
|
||||
|
||||
#include "actionsmodel.h"
|
||||
#include "controller.h"
|
||||
#include "customemojimodel.h"
|
||||
#include "models/actionsmodel.h"
|
||||
#include "models/customemojimodel.h"
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatroom.h"
|
||||
#include "neochatuser.h"
|
||||
#include "roommanager.h"
|
||||
|
||||
@@ -58,9 +59,9 @@ void ActionsHandler::setRoom(NeoChatRoom *room)
|
||||
Q_EMIT roomChanged();
|
||||
}
|
||||
|
||||
void ActionsHandler::handleMessage()
|
||||
void ActionsHandler::handleNewMessage()
|
||||
{
|
||||
checkEffects();
|
||||
checkEffects(m_room->chatBoxText());
|
||||
if (!m_room->chatBoxAttachmentPath().isEmpty()) {
|
||||
QUrl url(m_room->chatBoxAttachmentPath());
|
||||
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
||||
@@ -69,13 +70,39 @@ void ActionsHandler::handleMessage()
|
||||
m_room->setChatBoxText({});
|
||||
return;
|
||||
}
|
||||
QString handledText = m_room->chatBoxText();
|
||||
|
||||
std::sort(m_room->mentions()->begin(), m_room->mentions()->end(), [](const auto &a, const auto &b) -> bool {
|
||||
QString handledText = m_room->chatBoxText();
|
||||
handledText = handleMentions(handledText);
|
||||
handleMessage(m_room->chatBoxText(), handledText);
|
||||
}
|
||||
|
||||
void ActionsHandler::handleEdit()
|
||||
{
|
||||
checkEffects(m_room->editText());
|
||||
|
||||
QString handledText = m_room->editText();
|
||||
handledText = handleMentions(handledText, true);
|
||||
handleMessage(m_room->editText(), handledText, true);
|
||||
}
|
||||
|
||||
QString ActionsHandler::handleMentions(QString handledText, const bool &isEdit)
|
||||
{
|
||||
if (!m_room) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QVector<Mention> *mentions;
|
||||
if (isEdit) {
|
||||
mentions = m_room->editMentions();
|
||||
} else {
|
||||
mentions = m_room->mentions();
|
||||
}
|
||||
|
||||
std::sort(mentions->begin(), mentions->end(), [](const auto &a, const auto &b) -> bool {
|
||||
return a.cursor.anchor() > b.cursor.anchor();
|
||||
});
|
||||
|
||||
for (const auto &mention : *m_room->mentions()) {
|
||||
for (const auto &mention : *mentions) {
|
||||
if (mention.text.isEmpty() || mention.id.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -83,11 +110,16 @@ void ActionsHandler::handleMessage()
|
||||
mention.cursor.position() - mention.cursor.anchor(),
|
||||
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text, mention.id));
|
||||
}
|
||||
m_room->mentions()->clear();
|
||||
mentions->clear();
|
||||
|
||||
return handledText;
|
||||
}
|
||||
|
||||
void ActionsHandler::handleMessage(const QString &text, QString handledText, const bool &isEdit)
|
||||
{
|
||||
if (NeoChatConfig::allowQuickEdit()) {
|
||||
QRegularExpression sed("^s/([^/]*)/([^/]*)(/g)?$");
|
||||
auto match = sed.match(m_room->chatBoxText());
|
||||
auto match = sed.match(text);
|
||||
if (match.hasMatch()) {
|
||||
const QString regex = match.captured(1);
|
||||
const QString replacement = match.captured(2).toHtmlEscaped();
|
||||
@@ -146,13 +178,13 @@ void ActionsHandler::handleMessage()
|
||||
if (handledText.length() == 0) {
|
||||
return;
|
||||
}
|
||||
m_room->postMessage(m_room->chatBoxText(), handledText, messageType, m_room->chatBoxReplyId(), m_room->chatBoxEditId());
|
||||
|
||||
m_room->postMessage(text, handledText, messageType, m_room->chatBoxReplyId(), isEdit ? m_room->chatBoxEditId() : "");
|
||||
}
|
||||
|
||||
void ActionsHandler::checkEffects()
|
||||
void ActionsHandler::checkEffects(const QString &text)
|
||||
{
|
||||
std::optional<QString> effect = std::nullopt;
|
||||
const auto &text = m_room->chatBoxText();
|
||||
if (text.contains("\u2744")) {
|
||||
effect = QLatin1String("snowflake");
|
||||
} else if (text.contains("\u1F386")) {
|
||||
|
||||
@@ -33,14 +33,22 @@ Q_SIGNALS:
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
/// \brief Post a message.
|
||||
///
|
||||
/// This also interprets commands if any.
|
||||
void handleMessage();
|
||||
/**
|
||||
* @brief Pre-process text and send message.
|
||||
*/
|
||||
void handleNewMessage();
|
||||
|
||||
/**
|
||||
* @brief Pre-process text and send edit.
|
||||
*/
|
||||
void handleEdit();
|
||||
|
||||
private:
|
||||
NeoChatRoom *m_room = nullptr;
|
||||
void checkEffects();
|
||||
void checkEffects(const QString &text);
|
||||
|
||||
QString handleMentions(QString handledText, const bool &isEdit = false);
|
||||
void handleMessage(const QString &text, QString handledText, const bool &isEdit = false);
|
||||
};
|
||||
|
||||
QString markdownToHTML(const QString &markdown);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "blurhashimageprovider.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2021 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
#include <Sonnet/BackgroundChecker>
|
||||
#include <Sonnet/Settings>
|
||||
|
||||
#include "actionsmodel.h"
|
||||
#include "models/actionsmodel.h"
|
||||
#include "models/roomlistmodel.h"
|
||||
#include "neochatroom.h"
|
||||
#include "roomlistmodel.h"
|
||||
|
||||
class SyntaxHighlighter : public QSyntaxHighlighter
|
||||
{
|
||||
@@ -105,14 +105,19 @@ ChatDocumentHandler::ChatDocumentHandler(QObject *parent)
|
||||
{
|
||||
connect(this, &ChatDocumentHandler::roomChanged, this, [this]() {
|
||||
m_completionModel->setRoom(m_room);
|
||||
static NeoChatRoom *previousRoom = nullptr;
|
||||
static QPointer<NeoChatRoom> previousRoom = nullptr;
|
||||
if (previousRoom) {
|
||||
disconnect(previousRoom, &NeoChatRoom::chatBoxTextChanged, this, nullptr);
|
||||
disconnect(previousRoom, &NeoChatRoom::editTextChanged, this, nullptr);
|
||||
}
|
||||
previousRoom = m_room;
|
||||
connect(m_room, &NeoChatRoom::chatBoxTextChanged, this, [this]() {
|
||||
int start = completionStartIndex();
|
||||
m_completionModel->setText(m_room->chatBoxText().mid(start, cursorPosition() - start), m_room->chatBoxText().mid(start));
|
||||
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
|
||||
});
|
||||
connect(m_room, &NeoChatRoom::editTextChanged, this, [this]() {
|
||||
int start = completionStartIndex();
|
||||
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
|
||||
});
|
||||
});
|
||||
connect(this, &ChatDocumentHandler::documentChanged, this, [this]() {
|
||||
@@ -123,7 +128,7 @@ ChatDocumentHandler::ChatDocumentHandler(QObject *parent)
|
||||
return;
|
||||
}
|
||||
int start = completionStartIndex();
|
||||
m_completionModel->setText(m_room->chatBoxText().mid(start, cursorPosition() - start), m_room->chatBoxText().mid(start));
|
||||
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,7 +143,7 @@ int ChatDocumentHandler::completionStartIndex() const
|
||||
#else
|
||||
const auto cursor = cursorPosition();
|
||||
#endif
|
||||
const auto &text = m_room->chatBoxText();
|
||||
const auto &text = getText();
|
||||
auto start = std::min(cursor, text.size()) - 1;
|
||||
while (start > -1) {
|
||||
if (text.at(start) == QLatin1Char(' ')) {
|
||||
@@ -150,6 +155,20 @@ int ChatDocumentHandler::completionStartIndex() const
|
||||
return start;
|
||||
}
|
||||
|
||||
bool ChatDocumentHandler::isEdit() const
|
||||
{
|
||||
return m_isEdit;
|
||||
}
|
||||
|
||||
void ChatDocumentHandler::setIsEdit(bool edit)
|
||||
{
|
||||
if (edit == m_isEdit) {
|
||||
return;
|
||||
}
|
||||
m_isEdit = edit;
|
||||
Q_EMIT isEditChanged();
|
||||
}
|
||||
|
||||
QQuickTextDocument *ChatDocumentHandler::document() const
|
||||
{
|
||||
return m_document;
|
||||
@@ -204,7 +223,7 @@ void ChatDocumentHandler::complete(int index)
|
||||
if (m_completionModel->autoCompletionType() == CompletionModel::User) {
|
||||
auto name = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Text).toString();
|
||||
auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Subtitle).toString();
|
||||
auto text = m_room->chatBoxText();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char('@'), cursorPosition() - 1);
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
cursor.setPosition(at);
|
||||
@@ -213,11 +232,11 @@ void ChatDocumentHandler::complete(int index)
|
||||
cursor.setPosition(at);
|
||||
cursor.setPosition(cursor.position() + name.size(), QTextCursor::KeepAnchor);
|
||||
cursor.setKeepPositionOnInsert(true);
|
||||
m_room->mentions()->push_back({cursor, name, 0, 0, id});
|
||||
pushMention({cursor, name, 0, 0, id});
|
||||
m_highlighter->rehighlight();
|
||||
} else if (m_completionModel->autoCompletionType() == CompletionModel::Command) {
|
||||
auto command = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedText).toString();
|
||||
auto text = m_room->chatBoxText();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char('/'));
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
cursor.setPosition(at);
|
||||
@@ -225,7 +244,7 @@ void ChatDocumentHandler::complete(int index)
|
||||
cursor.insertText(QStringLiteral("/%1 ").arg(command));
|
||||
} else if (m_completionModel->autoCompletionType() == CompletionModel::Room) {
|
||||
auto alias = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Subtitle).toString();
|
||||
auto text = m_room->chatBoxText();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char('#'), cursorPosition() - 1);
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
cursor.setPosition(at);
|
||||
@@ -234,11 +253,11 @@ void ChatDocumentHandler::complete(int index)
|
||||
cursor.setPosition(at);
|
||||
cursor.setPosition(cursor.position() + alias.size(), QTextCursor::KeepAnchor);
|
||||
cursor.setKeepPositionOnInsert(true);
|
||||
m_room->mentions()->push_back({cursor, alias, 0, 0, alias});
|
||||
pushMention({cursor, alias, 0, 0, alias});
|
||||
m_highlighter->rehighlight();
|
||||
} else if (m_completionModel->autoCompletionType() == CompletionModel::Emoji) {
|
||||
auto shortcode = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedText).toString();
|
||||
auto text = m_room->chatBoxText();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char(':'));
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
cursor.setPosition(at);
|
||||
@@ -281,3 +300,27 @@ void ChatDocumentHandler::setSelectionEnd(int position)
|
||||
m_selectionEnd = position;
|
||||
Q_EMIT selectionEndChanged();
|
||||
}
|
||||
|
||||
QString ChatDocumentHandler::getText() const
|
||||
{
|
||||
if (!m_room) {
|
||||
return QString();
|
||||
}
|
||||
if (m_isEdit) {
|
||||
return m_room->editText();
|
||||
} else {
|
||||
return m_room->chatBoxText();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatDocumentHandler::pushMention(const Mention mention) const
|
||||
{
|
||||
if (!m_room) {
|
||||
return;
|
||||
}
|
||||
if (m_isEdit) {
|
||||
m_room->editMentions()->push_back(mention);
|
||||
} else {
|
||||
m_room->mentions()->push_back(mention);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
#include <QQuickTextDocument>
|
||||
#include <QTextCursor>
|
||||
|
||||
#include "completionmodel.h"
|
||||
#include "userlistmodel.h"
|
||||
#include "models/completionmodel.h"
|
||||
#include "models/userlistmodel.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
class QTextDocument;
|
||||
class NeoChatRoom;
|
||||
@@ -17,6 +18,14 @@ class SyntaxHighlighter;
|
||||
class ChatDocumentHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* @brief Is the instance being used to handle an edit message.
|
||||
*
|
||||
* This is needed to ensure that the text and mentions are saved and retrieved
|
||||
* from the correct parameters in the assigned room.
|
||||
*/
|
||||
Q_PROPERTY(bool isEdit READ isEdit WRITE setIsEdit NOTIFY isEditChanged)
|
||||
Q_PROPERTY(QQuickTextDocument *document READ document WRITE setDocument NOTIFY documentChanged)
|
||||
Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
|
||||
Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged)
|
||||
@@ -24,11 +33,14 @@ class ChatDocumentHandler : public QObject
|
||||
|
||||
Q_PROPERTY(CompletionModel *completionModel READ completionModel NOTIFY completionModelChanged)
|
||||
|
||||
Q_PROPERTY(NeoChatRoom *room READ room NOTIFY roomChanged)
|
||||
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
|
||||
|
||||
public:
|
||||
explicit ChatDocumentHandler(QObject *parent = nullptr);
|
||||
|
||||
[[nodiscard]] bool isEdit() const;
|
||||
void setIsEdit(bool edit);
|
||||
|
||||
[[nodiscard]] QQuickTextDocument *document() const;
|
||||
void setDocument(QQuickTextDocument *document);
|
||||
|
||||
@@ -49,6 +61,7 @@ public:
|
||||
void updateCompletions();
|
||||
CompletionModel *completionModel() const;
|
||||
Q_SIGNALS:
|
||||
void isEditChanged();
|
||||
void documentChanged();
|
||||
void cursorPositionChanged();
|
||||
void roomChanged();
|
||||
@@ -59,6 +72,8 @@ Q_SIGNALS:
|
||||
private:
|
||||
int completionStartIndex() const;
|
||||
|
||||
bool m_isEdit;
|
||||
|
||||
QQuickTextDocument *m_document;
|
||||
|
||||
NeoChatRoom *m_room = nullptr;
|
||||
@@ -68,6 +83,9 @@ private:
|
||||
int m_selectionStart;
|
||||
int m_selectionEnd;
|
||||
|
||||
QString getText() const;
|
||||
void pushMention(const Mention mention) const;
|
||||
|
||||
SyntaxHighlighter *m_highlighter = nullptr;
|
||||
|
||||
CompletionModel::AutoCompletionType m_completionType = CompletionModel::None;
|
||||
|
||||
@@ -33,13 +33,14 @@ QImage Clipboard::image() const
|
||||
|
||||
QString Clipboard::saveImage(QString localPath) const
|
||||
{
|
||||
if (!QDir().exists(QStringLiteral("%1/screenshots").arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)))) {
|
||||
QDir().mkdir(QStringLiteral("%1/screenshots").arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
|
||||
QString imageDir(QStringLiteral("%1/screenshots").arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
|
||||
|
||||
if (!QDir().exists(imageDir)) {
|
||||
QDir().mkdir(imageDir);
|
||||
}
|
||||
|
||||
if (localPath.isEmpty()) {
|
||||
localPath = QStringLiteral("file://%1/screenshots/%2.png")
|
||||
.arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation),
|
||||
QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd-hh-mm-ss")));
|
||||
localPath = QStringLiteral("file://%1/%2.png").arg(imageDir, QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd-hh-mm-ss")));
|
||||
}
|
||||
QUrl url(localPath);
|
||||
if (!url.isLocalFile()) {
|
||||
@@ -51,21 +52,30 @@ QString Clipboard::saveImage(QString localPath) const
|
||||
return {};
|
||||
}
|
||||
|
||||
QDir dir;
|
||||
if (!dir.exists(localPath)) {
|
||||
dir.mkpath(localPath);
|
||||
if (image.save(url.toLocalFile())) {
|
||||
return localPath;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
||||
image.save(url.toLocalFile());
|
||||
|
||||
return localPath;
|
||||
}
|
||||
|
||||
void Clipboard::saveText(QString message)
|
||||
{
|
||||
QRegularExpression re("<[^>]*>");
|
||||
static QRegularExpression re(QStringLiteral("<[^>]*>"));
|
||||
auto *mineData = new QMimeData; // ownership is transferred to clipboard
|
||||
mineData->setHtml(message);
|
||||
mineData->setText(message.replace(re, ""));
|
||||
mineData->setText(message.replace(re, QString()));
|
||||
m_clipboard->setMimeData(mineData);
|
||||
}
|
||||
|
||||
void Clipboard::setImage(const QUrl &url)
|
||||
{
|
||||
if (url.isLocalFile()) {
|
||||
QImage img(url.path());
|
||||
auto *mimeData = new QMimeData;
|
||||
mimeData->setImageData(img);
|
||||
if (!img.isNull()) {
|
||||
m_clipboard->setMimeData(mimeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
Q_INVOKABLE QString saveImage(QString localPath = {}) const;
|
||||
|
||||
Q_INVOKABLE void saveText(QString message);
|
||||
Q_INVOKABLE void setImage(const QUrl &image);
|
||||
|
||||
private:
|
||||
QClipboard *m_clipboard;
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "collapsestateproxymodel.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
bool CollapseStateProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
Q_UNUSED(source_parent);
|
||||
return sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::EventTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If this is not a state, show it
|
||||
|| sourceModel()->data(sourceModel()->index(source_row + 1, 0), MessageEventModel::EventTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If this is the first state in a block, show it. TODO hidden events?
|
||||
|| sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::ShowSectionRole).toBool() // If it's a new day, show it
|
||||
|| sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::EventResolvedTypeRole)
|
||||
!= sourceModel()->data(sourceModel()->index(source_row + 1, 0),
|
||||
MessageEventModel::EventResolvedTypeRole) // Also show it if it's of a different type than the one before TODO improve in
|
||||
|| sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::AuthorIdRole)
|
||||
!= sourceModel()->data(sourceModel()->index(source_row + 1, 0), MessageEventModel::AuthorIdRole); // Also show it if it's a different author
|
||||
}
|
||||
|
||||
QVariant CollapseStateProxyModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == AggregateDisplayRole) {
|
||||
return aggregateEventToString(mapToSource(index).row());
|
||||
}
|
||||
return sourceModel()->data(mapToSource(index), role);
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> CollapseStateProxyModel::roleNames() const
|
||||
{
|
||||
auto roles = sourceModel()->roleNames();
|
||||
roles[AggregateDisplayRole] = "aggregateDisplay";
|
||||
return roles;
|
||||
}
|
||||
|
||||
QString CollapseStateProxyModel::aggregateEventToString(int sourceRow) const
|
||||
{
|
||||
QStringList parts;
|
||||
for (int i = sourceRow; i >= 0; i--) {
|
||||
parts += sourceModel()->data(sourceModel()->index(i, 0), Qt::DisplayRole).toString();
|
||||
if (sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::EventTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| (i > 0
|
||||
&& sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::EventResolvedTypeRole)
|
||||
!= sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::EventResolvedTypeRole)) // or of a different type
|
||||
|| (i > 0
|
||||
&& sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorIdRole)
|
||||
!= sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::AuthorIdRole)) // or by a different author
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!parts.isEmpty()) {
|
||||
QStringList chunks;
|
||||
while (!parts.isEmpty()) {
|
||||
chunks += QString();
|
||||
int count = 1;
|
||||
auto part = parts.takeFirst();
|
||||
chunks.last() += part;
|
||||
while (!parts.isEmpty() && parts.first() == part) {
|
||||
parts.removeFirst();
|
||||
count++;
|
||||
}
|
||||
if (count > 1) {
|
||||
chunks.last() += i18ncp("[user did something] n times", " %1 time", " %1 times", count);
|
||||
}
|
||||
}
|
||||
QString text = chunks.takeFirst();
|
||||
|
||||
if (chunks.size() > 0) {
|
||||
while (chunks.size() > 1) {
|
||||
text += i18nc("[action 1], [action 2 and action 3]", ", ");
|
||||
text += chunks.takeFirst();
|
||||
}
|
||||
text += i18nc("[action 1, action 2] and [action 3]", " and ");
|
||||
text += chunks.takeFirst();
|
||||
}
|
||||
return text;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "messageeventmodel.h"
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class CollapseStateProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Roles {
|
||||
AggregateDisplayRole = MessageEventModel::LastRole + 1,
|
||||
};
|
||||
[[nodiscard]] bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
[[nodiscard]] QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||
|
||||
[[nodiscard]] QString aggregateEventToString(int row) const;
|
||||
};
|
||||
@@ -1,10 +1,14 @@
|
||||
// SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org>
|
||||
// SPDX-FileCopyrightText: 2020 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2020 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <qt5keychain/keychain.h>
|
||||
#else
|
||||
#include <qt6keychain/keychain.h>
|
||||
#endif
|
||||
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
@@ -37,6 +41,7 @@
|
||||
#include <csapi/content-repo.h>
|
||||
#include <csapi/logout.h>
|
||||
#include <csapi/profile.h>
|
||||
#include <jobs/downloadfilejob.h>
|
||||
#include <qt_connection_util.h>
|
||||
|
||||
#ifdef QUOTIENT_07
|
||||
@@ -128,16 +133,7 @@ Controller::Controller(QObject *parent)
|
||||
if (AccountRegistry::instance().size() > oldAccountCount) {
|
||||
auto connection = AccountRegistry::instance().accounts()[AccountRegistry::instance().size() - 1];
|
||||
connect(connection, &Connection::syncDone, this, [=]() {
|
||||
bool changes = false;
|
||||
for (const auto &room : connection->allRooms()) {
|
||||
if (m_notificationCounts[room] != room->unreadStats().notableCount) {
|
||||
m_notificationCounts[room] = room->unreadStats().notableCount;
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
if (changes) {
|
||||
handleNotifications();
|
||||
}
|
||||
handleNotifications(connection);
|
||||
});
|
||||
}
|
||||
oldAccountCount = AccountRegistry::instance().size();
|
||||
@@ -146,19 +142,16 @@ Controller::Controller(QObject *parent)
|
||||
}
|
||||
|
||||
#ifdef QUOTIENT_07
|
||||
void Controller::handleNotifications()
|
||||
void Controller::handleNotifications(QPointer<Quotient::Connection> connection)
|
||||
{
|
||||
static bool initial = true;
|
||||
static QStringList initial;
|
||||
static QStringList oldNotifications;
|
||||
if (!m_connection) {
|
||||
return;
|
||||
}
|
||||
auto job = m_connection->callApi<GetNotificationsJob>();
|
||||
auto job = connection->callApi<GetNotificationsJob>();
|
||||
|
||||
connect(job, &BaseJob::success, this, [this, job]() {
|
||||
connect(job, &BaseJob::success, this, [job, connection]() {
|
||||
const auto notifications = job->jsonData()["notifications"].toArray();
|
||||
if (initial) {
|
||||
initial = false;
|
||||
if (!initial.contains(connection->user()->id())) {
|
||||
initial.append(connection->user()->id());
|
||||
for (const auto &n : notifications) {
|
||||
oldNotifications += n.toObject()["event"].toObject()["event_id"].toString();
|
||||
}
|
||||
@@ -174,10 +167,12 @@ void Controller::handleNotifications()
|
||||
continue;
|
||||
}
|
||||
oldNotifications += notification["event"].toObject()["event_id"].toString();
|
||||
auto room = m_connection->room(notification["room_id"].toString());
|
||||
auto room = connection->room(notification["room_id"].toString());
|
||||
|
||||
// If room exists, room is NOT active OR the application is NOT active, show notification
|
||||
if (room && !(room->id() == RoomManager::instance().currentRoom()->id() && QGuiApplication::applicationState() == Qt::ApplicationActive)) {
|
||||
if (room
|
||||
&& !(RoomManager::instance().currentRoom() && room->id() == RoomManager::instance().currentRoom()->id()
|
||||
&& QGuiApplication::applicationState() == Qt::ApplicationActive)) {
|
||||
// The room might have been deleted (for example rejected invitation).
|
||||
auto sender = room->user(notification["event"].toObject()["sender"].toString());
|
||||
|
||||
@@ -196,7 +191,7 @@ void Controller::handleNotifications()
|
||||
|
||||
if (notification["event"]["type"] == "m.room.encrypted") {
|
||||
#ifdef Quotient_E2EE_ENABLED
|
||||
auto decrypted = m_connection->decryptNotification(notification);
|
||||
auto decrypted = connection->decryptNotification(notification);
|
||||
body = decrypted["content"].toObject()["body"].toString();
|
||||
#endif
|
||||
if (body.isEmpty()) {
|
||||
@@ -381,6 +376,11 @@ void Controller::invokeLogin()
|
||||
if (error == "Unrecognised access token") {
|
||||
Q_EMIT errorOccured(i18n("Login Failed: Access Token invalid or revoked"));
|
||||
logout(connection, false);
|
||||
} else if (error == "Connection closed") {
|
||||
Q_EMIT errorOccured(i18n("Login Failed: %1", error));
|
||||
// Failed due to network connection issue. This might happen when the homeserver is
|
||||
// temporary down, or the user trying to re-launch NeoChat in a network that cannot
|
||||
// connect to the homeserver. In this case, we don't want to do logout().
|
||||
} else {
|
||||
Q_EMIT errorOccured(i18n("Login Failed: %1", error));
|
||||
logout(connection, true);
|
||||
@@ -611,6 +611,11 @@ void Controller::setActiveConnection(Connection *connection)
|
||||
m_isOnline = true;
|
||||
Q_EMIT isOnlineChanged(true);
|
||||
});
|
||||
connect(connection, &Connection::requestFailed, this, [=](BaseJob *job) {
|
||||
if (dynamic_cast<DownloadFileJob *>(job) && job->jsonData()["errcode"].toString() == "M_TOO_LARGE"_ls) {
|
||||
RoomManager::instance().warning(i18n("File too large to download."), i18n("Contact your matrix server administrator for support."));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
NeoChatConfig::self()->setActiveConnection(QString());
|
||||
}
|
||||
@@ -639,9 +644,17 @@ NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Om
|
||||
void Controller::createRoom(const QString &name, const QString &topic)
|
||||
{
|
||||
auto createRoomJob = m_connection->createRoom(Connection::PublishRoom, "", name, topic, QStringList());
|
||||
Quotient::CreateRoomJob::connect(createRoomJob, &CreateRoomJob::failure, [this, createRoomJob] {
|
||||
connect(createRoomJob, &CreateRoomJob::failure, this, [this, createRoomJob] {
|
||||
Q_EMIT errorOccured(i18n("Room creation failed: \"%1\"", createRoomJob->errorString()));
|
||||
});
|
||||
connectSingleShot(
|
||||
this,
|
||||
&Controller::roomAdded,
|
||||
this,
|
||||
[this](NeoChatRoom *room) {
|
||||
RoomManager::instance().enterRoom(room);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
bool Controller::isOnline() const
|
||||
|
||||
@@ -119,7 +119,7 @@ private:
|
||||
|
||||
bool hasWindowSystem() const;
|
||||
#ifdef QUOTIENT_07
|
||||
void handleNotifications();
|
||||
void handleNotifications(QPointer<Quotient::Connection> connection);
|
||||
#endif
|
||||
|
||||
private Q_SLOTS:
|
||||
@@ -151,6 +151,7 @@ Q_SIGNALS:
|
||||
void keyVerificationAccept(const QString &commitment);
|
||||
void keyVerificationKey(const QString &sas);
|
||||
void activeConnectionIndexChanged();
|
||||
void roomAdded(NeoChatRoom *room);
|
||||
|
||||
public Q_SLOTS:
|
||||
void logout(Quotient::Connection *conn, bool serverSideLogout);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "emojitones.h"
|
||||
#include "emojimodel.h"
|
||||
#include "models/emojimodel.h"
|
||||
|
||||
QMultiHash<QString, QVariant> EmojiTones::_tones = {
|
||||
#include "emojitones_data.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "filetransferpseudojob.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2020 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2020 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "login.h"
|
||||
@@ -181,8 +181,8 @@ void Login::loginWithSso()
|
||||
connectSingleShot(m_connection, &Connection::loginFlowsChanged, this, [this]() {
|
||||
SsoSession *session = m_connection->prepareForSso(m_deviceName);
|
||||
m_ssoUrl = session->ssoUrl();
|
||||
Q_EMIT ssoUrlChanged();
|
||||
});
|
||||
Q_EMIT ssoUrlChanged();
|
||||
}
|
||||
|
||||
bool Login::testing() const
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2020 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2020 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
44
src/main.cpp
44
src/main.cpp
@@ -42,38 +42,39 @@
|
||||
#include "blurhashimageprovider.h"
|
||||
#include "chatdocumenthandler.h"
|
||||
#include "clipboard.h"
|
||||
#include "collapsestateproxymodel.h"
|
||||
#include "controller.h"
|
||||
#include "customemojimodel.h"
|
||||
#include "devicesmodel.h"
|
||||
#include "emojimodel.h"
|
||||
#include "filetypesingleton.h"
|
||||
#include "joinrulesevent.h"
|
||||
#include "linkpreviewer.h"
|
||||
#include "keywordnotificationrulemodel.h"
|
||||
#include "login.h"
|
||||
#include "matriximageprovider.h"
|
||||
#include "messageeventmodel.h"
|
||||
#include "messagefiltermodel.h"
|
||||
#include "models/collapsestateproxymodel.h"
|
||||
#include "models/customemojimodel.h"
|
||||
#include "models/devicesmodel.h"
|
||||
#include "models/emojimodel.h"
|
||||
#include "models/keywordnotificationrulemodel.h"
|
||||
#include "models/messageeventmodel.h"
|
||||
#include "models/messagefiltermodel.h"
|
||||
#include "models/publicroomlistmodel.h"
|
||||
#include "models/roomlistmodel.h"
|
||||
#include "models/searchmodel.h"
|
||||
#include "models/serverlistmodel.h"
|
||||
#include "models/sortfilterroomlistmodel.h"
|
||||
#include "models/sortfilterspacelistmodel.h"
|
||||
#include "models/userdirectorylistmodel.h"
|
||||
#include "models/userfiltermodel.h"
|
||||
#include "models/userlistmodel.h"
|
||||
#include "models/webshortcutmodel.h"
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatroom.h"
|
||||
#include "neochatuser.h"
|
||||
#include "notificationsmanager.h"
|
||||
#include "searchmodel.h"
|
||||
#ifdef QUOTIENT_07
|
||||
#include "pollhandler.h"
|
||||
#endif
|
||||
#include "publicroomlistmodel.h"
|
||||
#include "roomlistmodel.h"
|
||||
#include "roommanager.h"
|
||||
#include "serverlistmodel.h"
|
||||
#include "sortfilterroomlistmodel.h"
|
||||
#include "sortfilterspacelistmodel.h"
|
||||
#include "spacehierarchycache.h"
|
||||
#include "urlhelper.h"
|
||||
#include "userdirectorylistmodel.h"
|
||||
#include "userlistmodel.h"
|
||||
#include "webshortcutmodel.h"
|
||||
#include "windowcontroller.h"
|
||||
#ifdef QUOTIENT_07
|
||||
#include <keyverificationsession.h>
|
||||
@@ -81,15 +82,19 @@
|
||||
#ifdef HAVE_COLORSCHEME
|
||||
#include "colorschemer.h"
|
||||
#endif
|
||||
#include "completionmodel.h"
|
||||
#include "models/completionmodel.h"
|
||||
#include "models/statemodel.h"
|
||||
#include "neochatuser.h"
|
||||
#include "statemodel.h"
|
||||
|
||||
#ifdef HAVE_RUNNER
|
||||
#include "runner.h"
|
||||
#include <QDBusConnection>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory
|
||||
@@ -152,7 +157,7 @@ int main(int argc, char *argv[])
|
||||
KAboutLicense::GPL_V3,
|
||||
i18n("© 2018-2020 Black Hat, 2020-2022 KDE Community"));
|
||||
about.addAuthor(i18n("Carl Schwan"), i18n("Maintainer"), QStringLiteral("carl@carlschwan.eu"), QStringLiteral("https://carlschwan.eu"));
|
||||
about.addAuthor(i18n("Tobias Fella"), i18n("Maintainer"), QStringLiteral("fella@posteo.de"), QStringLiteral("https://tobiasfella.de"));
|
||||
about.addAuthor(i18n("Tobias Fella"), i18n("Maintainer"), QStringLiteral("tobias.fella@kde.org"), QStringLiteral("https://tobiasfella.de"));
|
||||
about.addAuthor(i18n("James Graham"), i18n("Maintainer"), QStringLiteral("james.h.graham@protonmail.com"));
|
||||
about.addCredit(i18n("Black Hat"), i18n("Original author of Spectral"), QStringLiteral("bhat@encom.eu.org"));
|
||||
about.addCredit(i18n("Alexey Rusakov"), i18n("Maintainer of Quotient"), QStringLiteral("Kitsune-Ral@users.sf.net"));
|
||||
@@ -220,6 +225,7 @@ int main(int argc, char *argv[])
|
||||
qmlRegisterType<MessageEventModel>("org.kde.neochat", 1, 0, "MessageEventModel");
|
||||
qmlRegisterType<CollapseStateProxyModel>("org.kde.neochat", 1, 0, "CollapseStateProxyModel");
|
||||
qmlRegisterType<MessageFilterModel>("org.kde.neochat", 1, 0, "MessageFilterModel");
|
||||
qmlRegisterType<UserFilterModel>("org.kde.neochat", 1, 0, "UserFilterModel");
|
||||
qmlRegisterType<PublicRoomListModel>("org.kde.neochat", 1, 0, "PublicRoomListModel");
|
||||
qmlRegisterType<UserDirectoryListModel>("org.kde.neochat", 1, 0, "UserDirectoryListModel");
|
||||
qmlRegisterType<ServerListModel>("org.kde.neochat", 1, 0, "ServerListModel");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "actionsmodel.h"
|
||||
@@ -115,7 +115,7 @@ QVector<ActionsModel::Action> actions{
|
||||
QStringLiteral("spoiler"),
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
// Ideally, we would just return rainbowText and let that do the rest, but the colors don't survive markdownToHTML.
|
||||
room->postMessage(QStringLiteral("/rainbow %1").arg(text),
|
||||
room->postMessage(QStringLiteral("/spoiler %1").arg(text),
|
||||
QStringLiteral("<span data-mx-spoiler>%1</span>").arg(text),
|
||||
RoomMessageEvent::MsgType::Text,
|
||||
room->chatBoxReplyId(),
|
||||
@@ -158,11 +158,12 @@ QVector<ActionsModel::Action> actions{
|
||||
return QString();
|
||||
}
|
||||
#ifdef QUOTIENT_07
|
||||
if (room->currentState().get<RoomMemberEvent>(text)->membership() == Membership::Invite) {
|
||||
const RoomMemberEvent *roomMemberEvent = room->currentState().get<RoomMemberEvent>(text);
|
||||
if (roomMemberEvent && roomMemberEvent->membership() == Membership::Invite) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already invited to this room.", "%1 is already invited to this room.", text));
|
||||
return QString();
|
||||
}
|
||||
if (room->currentState().get<RoomMemberEvent>(text)->membership() == Membership::Ban) {
|
||||
if (roomMemberEvent && roomMemberEvent->membership() == Membership::Ban) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is banned from this room.", "%1 is banned from this room.", text));
|
||||
return QString();
|
||||
}
|
||||
@@ -208,6 +209,40 @@ QVector<ActionsModel::Action> actions{
|
||||
kli18n("<room alias or id>"),
|
||||
kli18n("Joins the given room"),
|
||||
},
|
||||
#ifdef QUOTIENT_07
|
||||
Action{
|
||||
QStringLiteral("knock"),
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
auto parts = text.split(QLatin1String(" "));
|
||||
QString roomName = parts[0];
|
||||
QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"));
|
||||
auto regexMatch = roomRegex.match(roomName);
|
||||
if (!regexMatch.hasMatch()) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error,
|
||||
i18nc("'<text>' does not look like a room id or alias.", "'%1' does not look like a room id or alias.", text));
|
||||
return QString();
|
||||
}
|
||||
auto targetRoom = text.startsWith(QLatin1Char('!')) ? room->connection()->room(text) : room->connection()->roomByAlias(text);
|
||||
if (targetRoom) {
|
||||
RoomManager::instance().enterRoom(dynamic_cast<NeoChatRoom *>(targetRoom));
|
||||
return QString();
|
||||
}
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Knocking room <roomname>.", "Knocking room %1.", text));
|
||||
auto connection = Controller::instance().activeConnection();
|
||||
const auto knownServer = roomName.mid(roomName.indexOf(":") + 1);
|
||||
if (parts.length() >= 2) {
|
||||
RoomManager::instance().knockRoom(connection, roomName, parts[1], QStringList{knownServer});
|
||||
} else {
|
||||
RoomManager::instance().knockRoom(connection, roomName, QString(), QStringList{knownServer});
|
||||
}
|
||||
return QString();
|
||||
},
|
||||
false,
|
||||
std::nullopt,
|
||||
kli18n("<room alias or id> [<reason>]"),
|
||||
kli18n("Requests to join the given room"),
|
||||
},
|
||||
#endif
|
||||
Action{
|
||||
QStringLiteral("j"),
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
134
src/models/collapsestateproxymodel.cpp
Normal file
134
src/models/collapsestateproxymodel.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "collapsestateproxymodel.h"
|
||||
#include "messageeventmodel.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
bool CollapseStateProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
Q_UNUSED(source_parent);
|
||||
return sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::EventTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If this is not a state, show it
|
||||
|| sourceModel()->data(sourceModel()->index(source_row + 1, 0), MessageEventModel::EventTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If this is the first state in a block, show it. TODO hidden events?
|
||||
|| sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::ShowSectionRole).toBool(); // If it's a new day, show it
|
||||
}
|
||||
|
||||
QVariant CollapseStateProxyModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == AggregateDisplayRole) {
|
||||
return aggregateEventToString(mapToSource(index).row());
|
||||
} else if (role == StateEventsRole) {
|
||||
return stateEventsList(mapToSource(index).row());
|
||||
} else if (role == AuthorListRole) {
|
||||
return authorList(mapToSource(index).row());
|
||||
}
|
||||
return sourceModel()->data(mapToSource(index), role);
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> CollapseStateProxyModel::roleNames() const
|
||||
{
|
||||
auto roles = sourceModel()->roleNames();
|
||||
roles[AggregateDisplayRole] = "aggregateDisplay";
|
||||
roles[StateEventsRole] = "stateEvents";
|
||||
roles[AuthorListRole] = "authorList";
|
||||
return roles;
|
||||
}
|
||||
|
||||
QString CollapseStateProxyModel::aggregateEventToString(int sourceRow) const
|
||||
{
|
||||
QStringList parts;
|
||||
QVariantList uniqueAuthors;
|
||||
for (int i = sourceRow; i >= 0; i--) {
|
||||
parts += sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::GenericDisplayRole).toString();
|
||||
QVariant nextAuthor = sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorRole);
|
||||
if (!uniqueAuthors.contains(nextAuthor)) {
|
||||
uniqueAuthors.append(nextAuthor);
|
||||
}
|
||||
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::EventTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
parts.sort(); // Sort them so that all identical events can be collected.
|
||||
if (!parts.isEmpty()) {
|
||||
QStringList chunks;
|
||||
while (!parts.isEmpty()) {
|
||||
chunks += QString();
|
||||
int count = 1;
|
||||
auto part = parts.takeFirst();
|
||||
chunks.last() += part;
|
||||
while (!parts.isEmpty() && parts.first() == part) {
|
||||
parts.removeFirst();
|
||||
count++;
|
||||
}
|
||||
if (count > 1 && uniqueAuthors.length() == 1) {
|
||||
chunks.last() += i18ncp("n times", " %1 time ", " %1 times ", count);
|
||||
}
|
||||
}
|
||||
chunks.removeDuplicates();
|
||||
QString text = "<style>a {text-decoration: none;}</style>"; // There can be links in the event text so make sure all are styled.
|
||||
// The author text is either "n users" if > 1 user or the matrix.to link to a single user.
|
||||
QString userText = uniqueAuthors.length() > 1 ? i18ncp("n users", " %1 user ", " %1 users ", uniqueAuthors.length())
|
||||
: QStringLiteral("<a href=\"https://matrix.to/#/%1\" style=\"color: %2\">%3</a> ")
|
||||
.arg(uniqueAuthors[0].toMap()["id"].toString(),
|
||||
uniqueAuthors[0].toMap()["color"].toString(),
|
||||
uniqueAuthors[0].toMap()["displayName"].toString());
|
||||
text += userText;
|
||||
text += chunks.takeFirst();
|
||||
|
||||
if (chunks.size() > 0) {
|
||||
while (chunks.size() > 1) {
|
||||
text += i18nc("[action 1], [action 2 and/or action 3]", ", ");
|
||||
text += chunks.takeFirst();
|
||||
}
|
||||
text += uniqueAuthors.length() > 1 ? i18nc("[action 1, action 2] or [action 3]", " or ") : i18nc("[action 1, action 2] and [action 3]", " and ");
|
||||
text += chunks.takeFirst();
|
||||
}
|
||||
return text;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList CollapseStateProxyModel::stateEventsList(int sourceRow) const
|
||||
{
|
||||
QVariantList stateEvents;
|
||||
for (int i = sourceRow; i >= 0; i--) {
|
||||
auto nextState = QVariantMap{
|
||||
{"author", sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorRole)},
|
||||
{"authorDisplayName", sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorDisplayNameRole).toString()},
|
||||
{"text", sourceModel()->data(sourceModel()->index(i, 0), Qt::DisplayRole).toString()},
|
||||
};
|
||||
stateEvents.append(nextState);
|
||||
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::EventTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return stateEvents;
|
||||
}
|
||||
|
||||
QVariantList CollapseStateProxyModel::authorList(int sourceRow) const
|
||||
{
|
||||
QVariantList uniqueAuthors;
|
||||
for (int i = sourceRow; i >= 0; i--) {
|
||||
QVariant nextAvatar = sourceModel()->data(sourceModel()->index(i, 0), MessageEventModel::AuthorRole);
|
||||
if (!uniqueAuthors.contains(nextAvatar)) {
|
||||
uniqueAuthors.append(nextAvatar);
|
||||
}
|
||||
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::EventTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return uniqueAuthors;
|
||||
}
|
||||
40
src/models/collapsestateproxymodel.h
Normal file
40
src/models/collapsestateproxymodel.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "messageeventmodel.h"
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class CollapseStateProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Roles {
|
||||
AggregateDisplayRole = MessageEventModel::LastRole + 1,
|
||||
StateEventsRole,
|
||||
AuthorListRole,
|
||||
};
|
||||
[[nodiscard]] bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
[[nodiscard]] QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||
|
||||
/**
|
||||
* @brief QString aggregating the text of consecutive state events starting at row.
|
||||
*
|
||||
* If state events happen on different days they will be split into two aggregate
|
||||
* events.
|
||||
*/
|
||||
[[nodiscard]] QString aggregateEventToString(int row) const;
|
||||
/**
|
||||
* @brief Return a list of consecutive state events starting at row.
|
||||
*
|
||||
* If state events happen on different days they will be split into two aggregate
|
||||
* events.
|
||||
*/
|
||||
[[nodiscard]] QVariantList stateEventsList(int row) const;
|
||||
/**
|
||||
* @brief List of unique authors for the aggregate state events starting at row.
|
||||
*/
|
||||
[[nodiscard]] QVariantList authorList(int row) const;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "completionmodel.h"
|
||||
@@ -16,7 +16,7 @@ CompletionModel::CompletionModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_filterModel(new CompletionProxyModel())
|
||||
, m_userListModel(new UserListModel(this))
|
||||
, m_emojiModel(new KConcatenateRowsProxyModel(this))
|
||||
, m_emojiModel(new QConcatenateTablesProxyModel(this))
|
||||
{
|
||||
connect(this, &CompletionModel::textChanged, this, &CompletionModel::updateCompletion);
|
||||
connect(this, &CompletionModel::roomChanged, this, [this]() {
|
||||
@@ -145,7 +145,7 @@ void CompletionModel::updateCompletion()
|
||||
m_filterModel->setFullText(m_fullText);
|
||||
m_filterModel->setFilterText(m_text);
|
||||
m_filterModel->invalidate();
|
||||
} else if (text().startsWith(QLatin1Char(':'))
|
||||
} else if (text().startsWith(QLatin1Char(':')) && !text()[1].isUpper()
|
||||
&& (m_fullText.indexOf(QLatin1Char(':'), 1) == -1
|
||||
|| (m_fullText.indexOf(QLatin1Char(' ')) != -1 && m_fullText.indexOf(QLatin1Char(':'), 1) > m_fullText.indexOf(QLatin1Char(' '), 1)))) {
|
||||
m_filterModel->setSourceModel(m_emojiModel);
|
||||
@@ -1,12 +1,11 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QConcatenateTablesProxyModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <KConcatenateRowsProxyModel>
|
||||
|
||||
#include "roomlistmodel.h"
|
||||
|
||||
class CompletionProxyModel;
|
||||
@@ -75,6 +74,6 @@ private:
|
||||
|
||||
UserListModel *m_userListModel;
|
||||
RoomListModel *m_roomListModel;
|
||||
KConcatenateRowsProxyModel *m_emojiModel;
|
||||
QConcatenateTablesProxyModel *m_emojiModel;
|
||||
};
|
||||
Q_DECLARE_METATYPE(CompletionModel::AutoCompletionType);
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "completionproxymodel.h"
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
@@ -4,8 +4,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <memory>
|
||||
#include <QRegularExpression>
|
||||
#include <memory>
|
||||
|
||||
struct CustomEmoji {
|
||||
QString name; // with :semicolons:
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "devicesmodel.h"
|
||||
@@ -70,7 +70,12 @@ void DevicesModel::logout(int index, const QString &password)
|
||||
auto job = Controller::instance().activeConnection()->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId);
|
||||
|
||||
connect(job, &BaseJob::result, this, [this, job, password, index] {
|
||||
if (job->error() != 0) {
|
||||
auto onSuccess = [this, index]() {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_devices.remove(index);
|
||||
endRemoveRows();
|
||||
};
|
||||
if (job->error() != BaseJob::Success) {
|
||||
QJsonObject replyData = job->jsonData();
|
||||
QJsonObject authData;
|
||||
authData["session"] = replyData["session"];
|
||||
@@ -79,11 +84,9 @@ void DevicesModel::logout(int index, const QString &password)
|
||||
QJsonObject identifier = {{"type", "m.id.user"}, {"user", Controller::instance().activeConnection()->user()->id()}};
|
||||
authData["identifier"] = identifier;
|
||||
auto *innerJob = Controller::instance().activeConnection()->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
||||
connect(innerJob, &BaseJob::success, this, [this, index]() {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_devices.remove(index);
|
||||
endRemoveRows();
|
||||
});
|
||||
connect(innerJob, &BaseJob::success, this, onSuccess);
|
||||
} else {
|
||||
onSuccess();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
@@ -67,6 +67,8 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
|
||||
roles[IsNameChangeRole] = "isNameChange";
|
||||
roles[IsAvatarChangeRole] = "isAvatarChange";
|
||||
roles[IsRedactedRole] = "isRedacted";
|
||||
roles[GenericDisplayRole] = "genericDisplay";
|
||||
roles[IsPendingRole] = "isPending";
|
||||
return roles;
|
||||
}
|
||||
|
||||
@@ -175,6 +177,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
||||
});
|
||||
connect(m_currentRoom, &Room::pendingEventAdded, this, &MessageEventModel::endInsertRows);
|
||||
connect(m_currentRoom, &Room::pendingEventAboutToMerge, this, [this](RoomEvent *, int i) {
|
||||
Q_EMIT dataChanged(index(i, 0), index(i, 0), {IsPendingRole});
|
||||
if (i == 0) {
|
||||
return; // No need to move anything, just refresh
|
||||
}
|
||||
@@ -439,7 +442,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
case EventTypeRole:
|
||||
return DelegateType::ReadMarker;
|
||||
case TimeRole: {
|
||||
const QDateTime eventDate = data(index(m_lastReadEventIndex.row() + 1, 0), TimeRole).toDateTime();
|
||||
const QDateTime eventDate = data(index(m_lastReadEventIndex.row() + 1, 0), TimeRole).toDateTime().toLocalTime();
|
||||
const KFormat format;
|
||||
return format.formatRelativeDateTime(eventDate, QLocale::ShortFormat);
|
||||
}
|
||||
@@ -462,6 +465,14 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
return m_currentRoom->eventToString(evt, Qt::RichText);
|
||||
}
|
||||
|
||||
if (role == GenericDisplayRole) {
|
||||
if (evt.isRedacted()) {
|
||||
return i18n("<i>[This message was deleted]</i>");
|
||||
}
|
||||
|
||||
return m_currentRoom->eventToGenericString(evt);
|
||||
}
|
||||
|
||||
if (role == FormattedBodyRole) {
|
||||
if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
|
||||
if (e->hasTextContent() && e->mimeType().name() != "text/plain") {
|
||||
@@ -560,7 +571,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
}
|
||||
|
||||
if (role == HighlightRole) {
|
||||
return m_currentRoom->isEventHighlighted(&evt);
|
||||
return !m_currentRoom->isDirectChat() && m_currentRoom->isEventHighlighted(&evt);
|
||||
}
|
||||
|
||||
if (role == FileMimetypeIcon) {
|
||||
@@ -899,6 +910,10 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
return evt.isRedacted();
|
||||
}
|
||||
|
||||
if (role == IsPendingRole) {
|
||||
return row < m_currentRoom->pendingEvents().size();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -966,6 +981,9 @@ QVariant MessageEventModel::getLatestMessageFromIndex(const int baseline)
|
||||
for (auto it = timelineBottom; it != limit; ++it) {
|
||||
auto evt = it->event();
|
||||
auto e = eventCast<const RoomMessageEvent>(evt);
|
||||
if (!e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto content = (*it)->contentJson();
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
AnnotationRole,
|
||||
UserMarkerRole,
|
||||
FormattedBodyRole,
|
||||
GenericDisplayRole,
|
||||
|
||||
MimeTypeRole,
|
||||
FileMimetypeIcon,
|
||||
@@ -72,6 +73,7 @@ public:
|
||||
IsNameChangeRole,
|
||||
IsAvatarChangeRole,
|
||||
IsRedactedRole,
|
||||
IsPendingRole,
|
||||
LastRole, // Keep this last
|
||||
};
|
||||
Q_ENUM(EventRoles)
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "roomlistmodel.h"
|
||||
|
||||
#include "controller.h"
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatroom.h"
|
||||
#include "roommanager.h"
|
||||
@@ -143,6 +144,7 @@ void RoomListModel::doAddRoom(Room *r)
|
||||
m_rooms.append(room);
|
||||
connectRoomSignals(room);
|
||||
Q_EMIT roomAdded(room);
|
||||
Q_EMIT Controller::instance().roomAdded(room);
|
||||
} else {
|
||||
qCritical() << "Attempt to add nullptr to the room list";
|
||||
Q_ASSERT(false);
|
||||
@@ -200,7 +202,11 @@ void RoomListModel::connectRoomSignals(NeoChatRoom *room)
|
||||
}
|
||||
Q_EMIT newHighlight(room->id(), lastEvent->id(), room->displayName(), sender->displayname(), room->eventToString(*lastEvent), room->avatar(128));
|
||||
});
|
||||
#ifndef QUOTIENT_07
|
||||
connect(room, &Room::notificationCountChanged, this, &RoomListModel::refreshNotificationCount);
|
||||
#else
|
||||
connect(room, &Room::unreadStatsChanged, this, &RoomListModel::refreshNotificationCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef QUOTIENT_07
|
||||
@@ -229,10 +235,13 @@ void RoomListModel::handleNotifications()
|
||||
continue;
|
||||
}
|
||||
oldNotifications += notification["event"].toObject()["event_id"].toString();
|
||||
|
||||
auto room = m_connection->room(notification["room_id"].toString());
|
||||
auto currentRoom = RoomManager::instance().currentRoom();
|
||||
bool roomIsActive = currentRoom && room->id() == currentRoom->id();
|
||||
|
||||
// If room exists, room is NOT active OR the application is NOT active, show notification
|
||||
if (room && !(room->id() == RoomManager::instance().currentRoom()->id() && QGuiApplication::applicationState() == Qt::ApplicationActive)) {
|
||||
if (room && !(roomIsActive && QGuiApplication::applicationState() == Qt::ApplicationActive)) {
|
||||
// The room might have been deleted (for example rejected invitation).
|
||||
auto sender = room->user(notification["event"].toObject()["sender"].toString());
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "searchmodel.h"
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user