Compare commits

..

1 Commits

Author SHA1 Message Date
Carl Schwan
2e42abd7c9 Add emoji model for other language
Signed-off-by: Carl Schwan <carl@carlschwan.eu>
2023-09-23 19:39:01 +00:00
400 changed files with 301270 additions and 132364 deletions

View File

@@ -1,10 +0,0 @@
; SPDX-FileCopyrightText: None
; SPDX-License-Identifier: CC0-1.0
[BlueprintSettings]
kde/unreleased/kirigami-addons.version=master
kde/frameworks.version=master
kde/libs.version=master
kde/plasma.version=master
kde/unreleased.version=master
libs/qt.qtMajorVersion=6

View File

@@ -19,7 +19,6 @@
"--talk-name=org.freedesktop.Notifications", "--talk-name=org.freedesktop.Notifications",
"--talk-name=org.kde.kwalletd5", "--talk-name=org.kde.kwalletd5",
"--talk-name=org.kde.StatusNotifierWatcher", "--talk-name=org.kde.StatusNotifierWatcher",
"--talk-name=org.freedesktop.secrets",
"--own-name=org.kde.StatusNotifierItem-2-2" "--own-name=org.kde.StatusNotifierItem-2-2"
], ],
"modules": [ "modules": [

View File

@@ -2,12 +2,9 @@
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
include: include:
- project: sysadmin/ci-utilities - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/reuse-lint.yml
file: # - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
- /gitlab-templates/reuse-lint.yml - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
- /gitlab-templates/android-qt6.yml # - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-qt6.yml
- /gitlab-templates/linux-qt6.yml - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
- /gitlab-templates/windows-qt6.yml # - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/flatpak.yml
- /gitlab-templates/freebsd-qt6.yml
# - /gitlab-templates/flatpak.yml
- /gitlab-templates/craft-android-qt6-apks.yml

View File

@@ -13,10 +13,8 @@ Dependencies:
'frameworks/kitemmodels': '@latest-kf6' 'frameworks/kitemmodels': '@latest-kf6'
'frameworks/kquickcharts': '@latest-kf6' 'frameworks/kquickcharts': '@latest-kf6'
'frameworks/knotifications': '@latest-kf6' 'frameworks/knotifications': '@latest-kf6'
'frameworks/kcolorscheme': '@latest-kf6'
'libraries/kquickimageeditor': '@latest-kf6' 'libraries/kquickimageeditor': '@latest-kf6'
'frameworks/sonnet': '@latest-kf6' 'frameworks/sonnet': '@latest-kf6'
'frameworks/prison': '@latest-kf6'
'libraries/kirigami-addons': '@latest-kf6' 'libraries/kirigami-addons': '@latest-kf6'
'third-party/libquotient': '@latest' 'third-party/libquotient': '@latest'
'third-party/qtkeychain': '@latest' 'third-party/qtkeychain': '@latest'
@@ -27,10 +25,11 @@ Dependencies:
'frameworks/qqc2-desktop-style': '@latest-kf6' 'frameworks/qqc2-desktop-style': '@latest-kf6'
'frameworks/kio': '@latest-kf6' 'frameworks/kio': '@latest-kf6'
'frameworks/kwindowsystem': '@latest-kf6' 'frameworks/kwindowsystem': '@latest-kf6'
'frameworks/kstatusnotifieritem': '@latest-kf6' 'frameworks/kconfigwidgets': '@latest-kf6'
- 'on': ['Linux', 'FreeBSD'] - 'on': ['Linux', 'FreeBSD']
'require': 'require':
'frameworks/kdbusaddons': '@latest-kf6' 'frameworks/kdbusaddons': '@latest-kf6'
'frameworks/kstatusnotifieritem': '@latest-kf6'
- 'on': ['Linux'] - 'on': ['Linux']
'require': 'require':

View File

@@ -41,11 +41,3 @@ License: CC0-1.0
Files: .flatpak-manifest.json Files: .flatpak-manifest.json
Copyright: 2020-2022 Tobias Fella <tobias.fella@kde.org> Copyright: 2020-2022 Tobias Fella <tobias.fella@kde.org>
License: BSD-2-Clause License: BSD-2-Clause
Files: autotests/data/*
Copyright: none
License: CC0-1.0
Files: appiumtests/data/*
Copyright: 2023 Tobias Fella <tobias.fella@kde.org>
License: CC0-1.0

View File

@@ -7,9 +7,9 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
# KDE Applications version, managed by release script. # KDE Applications version, managed by release script.
set(RELEASE_SERVICE_VERSION_MAJOR "24") set(RELEASE_SERVICE_VERSION_MAJOR "23")
set(RELEASE_SERVICE_VERSION_MINOR "01") set(RELEASE_SERVICE_VERSION_MINOR "11")
set(RELEASE_SERVICE_VERSION_MICRO "80") set(RELEASE_SERVICE_VERSION_MICRO "70")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION}) project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
@@ -37,7 +37,6 @@ include(ECMAddAppIcon)
include(KDEGitCommitHooks) include(KDEGitCommitHooks)
include(ECMCheckOutboundLicense) include(ECMCheckOutboundLicense)
include(ECMQtDeclareLoggingCategory) include(ECMQtDeclareLoggingCategory)
include(ECMAddAndroidApk)
if (NOT ANDROID) if (NOT ANDROID)
include(KDEClangFormat) include(KDEClangFormat)
endif() endif()
@@ -58,15 +57,15 @@ set_package_properties(Qt6 PROPERTIES
TYPE REQUIRED TYPE REQUIRED
PURPOSE "Basic application components" PURPOSE "Basic application components"
) )
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme) find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami2 I18n Notifications Config CoreAddons Sonnet ItemModels)
set_package_properties(KF6 PROPERTIES set_package_properties(KF6 PROPERTIES
TYPE REQUIRED TYPE REQUIRED
PURPOSE "Basic application components" PURPOSE "Basic application components"
) )
set_package_properties(KF6Kirigami PROPERTIES set_package_properties(KF6Kirigami2 PROPERTIES
TYPE REQUIRED TYPE REQUIRED
PURPOSE "Kirigami application UI framework" PURPOSE "Kirigami application UI framework"
) )
find_package(KF6KirigamiAddons 0.7.2 REQUIRED) find_package(KF6KirigamiAddons 0.7.2 REQUIRED)
if(ANDROID) if(ANDROID)
@@ -77,17 +76,11 @@ if(ANDROID)
) )
else() else()
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets) find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem) find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle ConfigWidgets KIO WindowSystem StatusNotifierItem)
set_package_properties(KF6QQC2DesktopStyle PROPERTIES set_package_properties(KF6QQC2DesktopStyle PROPERTIES
TYPE RUNTIME TYPE RUNTIME
) )
ecm_find_qmlmodule(org.kde.syntaxhighlighting 1.0) ecm_find_qmlmodule(org.kde.syntaxhighlighting 1.0)
find_package(ICU 61.0 COMPONENTS uc)
set_package_properties(ICU PROPERTIES
TYPE REQUIRED
PURPOSE "Unicode library"
)
endif() endif()
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE) if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
@@ -118,8 +111,7 @@ set_package_properties(cmark PROPERTIES
ecm_find_qmlmodule(org.kde.kquickimageeditor 1.0) ecm_find_qmlmodule(org.kde.kquickimageeditor 1.0)
ecm_find_qmlmodule(org.kde.kitemmodels 1.0) ecm_find_qmlmodule(org.kde.kitemmodels 1.0)
ecm_find_qmlmodule(org.kde.quickcharts 1.0) ecm_find_qmlmodule(org.kde.quickcharts 1.0)
ecm_find_qmlmodule(QtLocation) ecm_find_qmlmodule(QtLocation ${QTLOCATION_MODULE_QML_VERSION})
ecm_find_qmlmodule(org.kde.prison)
find_package(KQuickImageEditor COMPONENTS) find_package(KQuickImageEditor COMPONENTS)
set_package_properties(KQuickImageEditor PROPERTIES set_package_properties(KQuickImageEditor PROPERTIES
@@ -129,7 +121,7 @@ set_package_properties(KQuickImageEditor PROPERTIES
PURPOSE "Add image editing capability to image attachments" PURPOSE "Add image editing capability to image attachments"
) )
find_package(QCoro6 0.4 COMPONENTS Core Network REQUIRED) find_package(QCoro6 0.4 COMPONENTS Core REQUIRED)
qcoro_enable_coroutines() qcoro_enable_coroutines()
@@ -139,13 +131,6 @@ set_package_properties(KF6DocTools PROPERTIES DESCRIPTION
TYPE OPTIONAL TYPE OPTIONAL
) )
find_package(KUnifiedPush QUIET)
set_package_properties(KUnifiedPush PROPERTIES
TYPE OPTIONAL
PURPOSE "Push notification support"
URL "https://invent.kde.org/libraries/kunifiedpush"
)
if(ANDROID) if(ANDROID)
find_package(Sqlite3) find_package(Sqlite3)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/android/version.gradle.in ${CMAKE_BINARY_DIR}/version.gradle) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/android/version.gradle.in ${CMAKE_BINARY_DIR}/version.gradle)

View File

@@ -11,7 +11,6 @@ A Qt/QML based Matrix client.
<a href='https://matrix.org'><img src='https://matrix.org/docs/legacy/made-for-matrix.png' alt='Made for Matrix' height=64 target=_blank /></a> <a href='https://matrix.org'><img src='https://matrix.org/docs/legacy/made-for-matrix.png' alt='Made for Matrix' height=64 target=_blank /></a>
<a href='https://flathub.org/apps/details/org.kde.neochat'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a> <a href='https://flathub.org/apps/details/org.kde.neochat'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a>
<a href='https://snapcraft.io/neochat'><img width='190px' alt='Download on the Snap Store' src='https://snapcraft.io/static/images/badges/en/snap-store-black.svg'/></a>
## Introduction ## Introduction
@@ -96,7 +95,7 @@ As is the case throughout the KDE ecosystem contributions are welcome from all.
## Contact ## Contact
The best place to reach the maintainers is on the KDE Matrix instance in the NeoChat channel, [#neochat:kde.org](https://go.kde.org/matrix/#/#neochat:kde.org). See [Matrix](https://community.kde.org/Matrix) for more details. The best place to reach the maintainers is on the KDE Matrix instance in the NeoChat channel, [#neochat:kde.org](https://matrix.to/#/#neochat:kde.org).
## Acknowledgement ## Acknowledgement

View File

@@ -9,9 +9,9 @@
android:versionName="${versionName}" android:versionName="${versionName}"
android:versionCode="${versionCode}" android:versionCode="${versionCode}"
android:installLocation="auto"> android:installLocation="auto">
<application android:name="org.qtproject.qt.android.bindings.QtApplication" android:label="NeoChat" android:icon="@drawable/neochat" android:usesCleartextTraffic="true"> <application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="NeoChat" android:icon="@drawable/neochat" android:usesCleartextTraffic="true">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
android:name="org.qtproject.qt.android.bindings.QtActivity" android:name="org.qtproject.qt5.android.bindings.QtActivity"
android:label="NeoChat" android:label="NeoChat"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:launchMode="singleTop" android:launchMode="singleTop"

View File

@@ -12,7 +12,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.4.1' classpath 'com.android.tools.build:gradle:7.0.2'
} }
} }
@@ -35,7 +35,7 @@ android {
* The following variables: * The following variables:
* - androidBuildToolsVersion, * - androidBuildToolsVersion,
* - androidCompileSdkVersion * - androidCompileSdkVersion
* - qtAndroidDir - holds the path to qt android files * - qt5AndroidDir - holds the path to qt android files
* needed to build any Qt application * needed to build any Qt application
* on Android. * on Android.
* *
@@ -44,20 +44,17 @@ android {
* Changing them manually might break the compilation! * Changing them manually might break the compilation!
*******************************************************/ *******************************************************/
compileSdkVersion androidCompileSdkVersion compileSdkVersion androidCompileSdkVersion.toInteger()
buildToolsVersion androidBuildToolsVersion buildToolsVersion androidBuildToolsVersion
ndkVersion androidNdkVersion ndkVersion androidNdkVersion
// Extract native libraries from the APK
packagingOptions.jniLibs.useLegacyPackaging true
sourceSets { sourceSets {
main { main {
manifest.srcFile 'AndroidManifest.xml' manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = [qtAndroidDir + '/src', 'src', 'java'] java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl'] aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
res.srcDirs = [qtAndroidDir + '/res', 'res'] res.srcDirs = [qt5AndroidDir + '/res', 'res']
resources.srcDirs = ['src'] resources.srcDirs = ['src']
renderscript.srcDirs = ['src'] renderscript.srcDirs = ['src']
assets.srcDirs = ['assets'] assets.srcDirs = ['assets']

View File

@@ -21,8 +21,3 @@ add_test(
NAME logintest NAME logintest
COMMAND selenium-webdriver-at-spi-run ${CMAKE_CURRENT_SOURCE_DIR}/logintest.py COMMAND selenium-webdriver-at-spi-run ${CMAKE_CURRENT_SOURCE_DIR}/logintest.py
) )
add_test(
NAME openuserdetailstest
COMMAND selenium-webdriver-at-spi-run ${CMAKE_CURRENT_SOURCE_DIR}/openuserdetailstest.py
)

View File

@@ -1,3 +0,0 @@
{
"next_batch": "batch1234"
}

View File

@@ -1,50 +0,0 @@
{
"next_batch": "batch1234",
"rooms": {
"join": {
"!room_id_1234:localhost:1234": {
"state": {
"events": [
{
"type": "m.room.member",
"state_key": "@user:localhost:1234",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_0:localhost:1234",
"room_id": "!room_id_1234:localhost:1234",
"content": {
"avatar_url": "",
"displayname": "A Display Name",
"membership": "join",
"reason": "Nothing"
},
"unsigned": {
"age": 1234
}
}
]
},
"timeline": {
"events": [
{
"type": "m.room.message",
"sender": "@user:localhost:1234",
"origin_server_ts": 1432735824653,
"event_id": "$event_id_1234_1:localhost:1234",
"room_id": "!room_id_1234:localhost:1234",
"content": {
"body": "This is a message",
"format": "org.matrix.custom.html",
"formatted_body": "<a href=\"https://matrix.to/#/@user:localhost:1234\">User</a>:",
"msgtype": "m.text"
},
"unsigned": {
"age": 1234
}
}
]
}
}
}
}
}

View File

@@ -1,11 +1,9 @@
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org> # SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
import json
from flask import Flask, request, abort
import os
app = Flask(__name__)
from flask import Flask, request, abort
app = Flask(__name__)
@app.route("/_matrix/client/v3/login", methods=["GET"]) @app.route("/_matrix/client/v3/login", methods=["GET"])
def login_get(): def login_get():
@@ -14,13 +12,6 @@ def login_get():
result["flows"][0]["type"] = "m.login.password" result["flows"][0]["type"] = "m.login.password"
return result return result
@app.route("/_matrix/client/v3/account/whoami", methods=["GET"])
def whoami():
result = dict()
result["device_id"] = "device_id_1234"
result["user_id"] = "@user:localhost:1234"
return result
@app.route("/_matrix/client/v3/login", methods=["POST"]) @app.route("/_matrix/client/v3/login", methods=["POST"])
def login_post(): def login_post():
data = request.get_json() data = request.get_json()
@@ -28,22 +19,15 @@ def login_post():
abort(403) abort(403)
print(data) print(data)
result = dict() result = dict()
result["access_token"] = "token_login" result["access_token"] = "token_1234"
result["device_id"] = "device_1234" result["device_id"] = "device_1234"
result["user_id"] = "@user:localhost:1234" result["user_id"] = "@user:localhost:1234"
return result return result
def load_json(name):
parts = __file__.split("/")
parts.pop()
datadir = "/".join(parts)
return json.loads(open(f"{datadir}/data/{name}.json").read())
@app.route("/_matrix/client/r0/sync") @app.route("/_matrix/client/r0/sync")
def sync(): def sync():
result = dict()
result = load_json("sync_response_no_rooms") if ("login" in request.headers.get("Authorization")) else load_json("sync_response_rooms") result["next_batch"] = "batch1234"
return result return result
@app.route("/.well-known/matrix/client") @app.route("/.well-known/matrix/client")
@@ -53,18 +37,6 @@ def well_known():
reply["m.homeserver"]["base_url"] = "https://localhost:1234" reply["m.homeserver"]["base_url"] = "https://localhost:1234"
return reply return reply
@app.route("/_matrix/client/v3/profile/<id>")
def profile(id):
reply = dict()
reply["avatar_url"] = "mxc://localhost:1234/asdf1234"
reply["displayname"] = "User123"
return reply
@app.route("/_matrix/client/v3/keys/upload", methods=["POST"])
def upload_keys():
reply = dict()
return reply
if __name__ == "__main__": if __name__ == "__main__":
app.run(ssl_context='adhoc', port=1234) app.run(ssl_context='adhoc', port=1234)

View File

@@ -4,26 +4,25 @@
# SPDX-FileCopyrightText: 2021-2022 Harald Sitter <sitter@kde.org> # SPDX-FileCopyrightText: 2021-2022 Harald Sitter <sitter@kde.org>
# SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org> # SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
import unittest
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
import os import os
import time
import subprocess import subprocess
import sys import sys
import unittest
from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
class LoginTest(unittest.TestCase): class LoginTest(unittest.TestCase):
mockServerProcess: subprocess.Popen
@classmethod @classmethod
def setUpClass(cls): def setUpClass(self):
options = AppiumOptions() desired_caps = {}
options.set_capability("app", "neochat --ignore-ssl-errors") desired_caps["app"] = "neochat --ignore-ssl-errors"
cls.driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', options=options) desired_caps["timeouts"] = {'implicit': 10000}
cls.mockServerProcess = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), "login-server.py")]) self.driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723',
desired_capabilities=desired_caps)
self.mockServerProcess = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), "login-server.py")])
def setUp(self): def setUp(self):
pass pass
@@ -46,6 +45,5 @@ class LoginTest(unittest.TestCase):
self.driver.find_element(by=AppiumBy.NAME, value="Login").click() self.driver.find_element(by=AppiumBy.NAME, value="Login").click()
self.driver.find_element(by=AppiumBy.NAME, value="Join some rooms to get started").click() self.driver.find_element(by=AppiumBy.NAME, value="Join some rooms to get started").click()
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@@ -1,48 +0,0 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2021-2022 Harald Sitter <sitter@kde.org>
# SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
import os
import subprocess
import sys
import unittest
from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
class OpenUserDetailsTest(unittest.TestCase):
mockServerProcess: subprocess.Popen
@classmethod
def setUpClass(cls):
cls.mockServerProcess = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), "login-server.py")])
options = AppiumOptions()
options.set_capability("app", "neochat --ignore-ssl-errors --test")
cls.driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', options=options)
def setUp(self):
pass
def tearDown(self):
if not self._outcome.result.wasSuccessful():
self.driver.get_screenshot_as_file("failed_test_shot_{}.png".format(self.id()))
@classmethod
def tearDownClass(self):
self.mockServerProcess.terminate()
self.driver.quit()
def test_open_sheet(self):
self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click()
self.driver.find_element(by=AppiumBy.NAME, value="Empty room (!room_id_1234:localhost:1234)").click()
self.driver.find_element(by=AppiumBy.NAME, value="A Display Name").click()
self.driver.find_element(by=AppiumBy.NAME, value="Account Details")
if __name__ == '__main__':
unittest.main()

View File

@@ -3,8 +3,6 @@
enable_testing() enable_testing()
add_definitions(-DDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" )
ecm_add_test( ecm_add_test(
neochatroomtest.cpp neochatroomtest.cpp
LINK_LIBRARIES neochat Qt::Test LINK_LIBRARIES neochat Qt::Test
@@ -34,15 +32,3 @@ ecm_add_test(
LINK_LIBRARIES neochat Qt::Test LINK_LIBRARIES neochat Qt::Test
TEST_NAME eventhandlertest TEST_NAME eventhandlertest
) )
ecm_add_test(
chatbarcachetest.cpp
LINK_LIBRARIES neochat Qt::Test
TEST_NAME chatbarcachetest
)
ecm_add_test(
chatdocumenthandlertest.cpp
LINK_LIBRARIES neochat Qt::Test
TEST_NAME chatdocumenthandlertest
)

View File

@@ -1,157 +0,0 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QJsonDocument>
#include <QJsonObject>
#include <QObject>
#include <QTest>
#include <Quotient/syncdata.h>
#include <qtestcase.h>
#include "chatbarcache.h"
#include "neochatroom.h"
using namespace Quotient;
class TestRoom : public NeoChatRoom
{
public:
using NeoChatRoom::NeoChatRoom;
void update(SyncRoomData &&data, bool fromCache = false)
{
Room::updateData(std::move(data), fromCache);
}
};
class ChatBarCacheTest : public QObject
{
Q_OBJECT
private:
Connection *connection = nullptr;
TestRoom *room = nullptr;
private Q_SLOTS:
void initTestCase();
void empty();
void noRoom();
void badParent();
void reply();
void edit();
void attachment();
};
void ChatBarCacheTest::initTestCase()
{
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
QFile testMinSyncFile;
testMinSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-min-sync.json"));
testMinSyncFile.open(QIODevice::ReadOnly);
const auto testMinSyncJson = QJsonDocument::fromJson(testMinSyncFile.readAll());
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testMinSyncJson.object());
room->update(std::move(roomData));
}
void ChatBarCacheTest::empty()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
QCOMPARE(chatBarCache->text(), QString());
QCOMPARE(chatBarCache->isReplying(), false);
QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
QCOMPARE(chatBarCache->relationMessage(), QString());
QCOMPARE(chatBarCache->attachmentPath(), QString());
}
void ChatBarCacheTest::noRoom()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache());
chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
// These should return empty even though a reply ID has been set because the
// ChatBarCache has no parent.
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationMessage(), QString());
}
void ChatBarCacheTest::badParent()
{
QScopedPointer<QObject> badParent(new QObject());
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(badParent.get()));
chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
// These should return empty even though a reply ID has been set because the
// ChatBarCache has no parent.
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationUser(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.");
QCOMPARE(chatBarCache->relationMessage(), QString());
}
void ChatBarCacheTest::reply()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(QLatin1String("some text"));
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
chatBarCache->setReplyId(QLatin1String("$153456789:example.org"));
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
QCOMPARE(chatBarCache->isReplying(), true);
QCOMPARE(chatBarCache->replyId(), QLatin1String("$153456789:example.org"));
QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
QCOMPARE(chatBarCache->attachmentPath(), QString());
}
void ChatBarCacheTest::edit()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(QLatin1String("some text"));
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
QCOMPARE(chatBarCache->isReplying(), false);
QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), true);
QCOMPARE(chatBarCache->editId(), QLatin1String("$153456789:example.org"));
QCOMPARE(chatBarCache->relationUser(), room->getUser(room->user(QLatin1String("@example:example.org"))));
QCOMPARE(chatBarCache->relationMessage(), QLatin1String("This is an example\ntext message"));
QCOMPARE(chatBarCache->attachmentPath(), QString());
}
void ChatBarCacheTest::attachment()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(QLatin1String("some text"));
chatBarCache->setEditId(QLatin1String("$153456789:example.org"));
chatBarCache->setAttachmentPath(QLatin1String("some/path"));
QCOMPARE(chatBarCache->text(), QLatin1String("some text"));
QCOMPARE(chatBarCache->isReplying(), false);
QCOMPARE(chatBarCache->replyId(), QString());
QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationUser(), room->getUser(nullptr));
QCOMPARE(chatBarCache->relationMessage(), QString());
QCOMPARE(chatBarCache->attachmentPath(), QLatin1String("some/path"));
}
QTEST_MAIN(ChatBarCacheTest)
#include "chatbarcachetest.moc"

View File

@@ -1,36 +0,0 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QObject>
#include <QTest>
#include "chatdocumenthandler.h"
#include "neochatconfig.h"
class ChatDocumentHandlerTest : public QObject
{
Q_OBJECT
private:
ChatDocumentHandler emptyHandler;
private Q_SLOTS:
void initTestCase();
void nullComplete();
};
void ChatDocumentHandlerTest::initTestCase()
{
// HACK: this is to stop KStatusNotifierItem SEGFAULTING on cleanup.
NeoChatConfig::self()->setSystemTray(false);
}
void ChatDocumentHandlerTest::nullComplete()
{
QTest::ignoreMessage(QtWarningMsg, "complete called with m_document set to nullptr.");
emptyHandler.complete(0);
}
QTEST_MAIN(ChatDocumentHandlerTest)
#include "chatdocumenthandlertest.moc"

View File

@@ -1,410 +0,0 @@
{
"account_data": {
"events": [
{
"content": {
"tags": {
"u.work": {
"order": 0.9
}
}
},
"type": "m.tag"
},
{
"content": {
"custom_config_key": "custom_config_value"
},
"type": "org.example.custom.room.config"
}
]
},
"ephemeral": {
"events": [
{
"content": {
"user_ids": [
"@alice:matrix.org",
"@bob:example.com"
]
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"type": "m.typing"
},
{
"content": {
"$153456789:example.org": {
"m.read": {
"@alice:matrix.org": {
"ts": 1436451550453
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@bob:example.com": {
"ts": 1436451550453
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@tim:example.com": {
"ts": 1436451550454
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@jeff:example.com": {
"ts": 1436451550455
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@tina:example.com": {
"ts": 1436451550456
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@sally:example.com": {
"ts": 1436451550457
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@fred:example.com": {
"ts": 1436451550458
}
}
}
},
"type": "m.receipt"
}
]
},
"state": {
"events": [
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"membership": "join",
"reason": "Looking for support"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@alice:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
},
{
"content": {
"displayname": "Look\nat\nme\nI\nput\nnewlines\nin\nmy\ndisplay name",
"membership": "join"
},
"event_id": "$143273582443PhrSh:example.org",
"origin_server_ts": 1432735824659,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@newline:example.org",
"state_key": "@newline:example.org",
"type": "m.room.member",
"unsigned": {
"age": 12345
}
}
]
},
"summary": {
"m.heroes": [
"@alice:example.com",
"@bob:example.com"
],
"m.invited_member_count": 0,
"m.joined_member_count": 2
},
"timeline": {
"events": [
{
"content": {
"body": "This is an example\ntext message",
"format": "org.matrix.custom.html",
"formatted_body": "<b>This is an example<br>text message</b>",
"msgtype": "m.text"
},
"event_id": "$153456789:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"avatar_url": "mxc://kde.org/123456",
"displayname": "after",
"membership": "join"
},
"origin_server_ts": 1690651134736,
"sender": "@example:example.org",
"state_key": "@example:example.org",
"type": "m.room.member",
"unsigned": {
"replaces_state": "$1234567890:example.org",
"prev_content": {
"avatar_url": "mxc://kde.org/12345",
"displayname": "before",
"membership": "join"
},
"prev_sender": "@example:example.orgg",
"age": 1234
},
"event_id": "$143273583553PhrSn:example.org",
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
},
{
"content": {
"body": "This is a highlight @bob:kde.org and this is a link https://kde.org",
"format": "org.matrix.custom.html",
"msgtype": "m.text"
},
"event_id": "$1532735824654:example.org",
"origin_server_ts": 1532735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1233
}
},
{
"content": {
"m.relates_to": {
"event_id": "$153456789:example.org",
"key": "👍",
"rel_type": "m.annotation"
}
},
"origin_server_ts": 1690322545182,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@alice:matrix.org",
"type": "m.reaction",
"unsigned": {
"age": 390159120
},
"event_id": "$163456789:example.org",
"age": 390159120
},
{
"age": 4926305285,
"content": {
"body": "video caption",
"filename": "video.mp4",
"info": {
"duration": 10,
"h": 1080,
"mimetype": "video/mp4",
"size": 62650636,
"w": 1920,
"thumbnail_info": {
"h": 450,
"mimetype": "image/jpeg",
"size": 382249,
"w": 800
},
"thumbnail_url": "mxc://kde.org/2234567"
},
"msgtype": "m.video",
"url": "mxc://kde.org/1234567"
},
"event_id": "$263456789:example.org",
"origin_server_ts": 1685793783330,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 4926305285
},
"user_id": "@example:example.org"
},
{
"content": {
"body": "> <@example:example.org> This is an example\ntext message\n\nreply",
"format": "org.matrix.custom.html",
"formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!jEsUZKDJdhlrceRyVU:example.org/$153456789:example.org?via=kde.org&via=matrix.org\">In reply to</a> <a href=\"https://matrix.to/#/@example:example.org\">@example:example.org</a><br><b>This is an example<br>text message</b></blockquote></mx-reply>reply",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$153456789:example.org"
}
},
"msgtype": "m.text"
},
"origin_server_ts": 1690725965572,
"sender": "@alice:matrix.org",
"type": "m.room.message",
"unsigned": {
"age": 98
},
"event_id": "$154456789:example.org",
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
},
{
"content": {
"body": "> <@example:example.org> video caption\n\nreply",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$263456789:example.org"
}
},
"msgtype": "m.text"
},
"origin_server_ts": 1690725965573,
"sender": "@alice:matrix.org",
"type": "m.room.message",
"unsigned": {
"age": 98
},
"event_id": "$154456799:example.org",
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
},
{
"age": 96845207,
"content": {
"body": "Lat: 51.7035, Lon: -1.14394",
"geo_uri": "geo:51.7035,-1.14394",
"msgtype": "m.location",
"org.matrix.msc1767.text": "Lat: 51.7035, Lon: -1.14394",
"org.matrix.msc3488.asset": {
"type": "m.pin"
},
"org.matrix.msc3488.location": {
"uri": "geo:51.7035,-1.14394"
}
},
"event_id": "$1544567999:example.org",
"origin_server_ts": 1690821582876,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 96845207
}
},
{
"content": {
"body": "Thread root",
"format": "org.matrix.custom.html",
"msgtype": "m.text"
},
"event_id": "$threadroot:example.org",
"origin_server_ts": 1690821582879,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "Thread message 1",
"msgtype": "m.text",
"m.relates_to": {
"rel_type": "m.thread",
"event_id": "$threadroot:example.org",
"m.in_reply_to": {
"event_id": "$threadroot:example.org"
},
"is_falling_back": true
}
},
"event_id": "$threadmessage1:example.org",
"origin_server_ts": 1690821582890,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1238
}
},
{
"content": {
"body": "Thread message 2",
"msgtype": "m.text",
"m.relates_to": {
"rel_type": "m.thread",
"event_id": "$threadroot:example.org",
"m.in_reply_to": {
"event_id": "$threadmessage1:example.org"
},
"is_falling_back": true
}
},
"event_id": "$threadmessage2:example.org",
"origin_server_ts": 1690821582890,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1238
}
},
{
"content": {
"body": "A message from someone who thought it was a good idea to put newlines in their display name.",
"msgtype": "m.text"
},
"event_id": "$153456889:example.org",
"origin_server_ts": 14327358246589,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@newline:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1230
}
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
}
}

View File

@@ -1,87 +0,0 @@
{
"account_data": {
"events": [
{
"content": {
"tags": {
"u.work": {
"order": 0.9
}
}
},
"type": "m.tag"
},
{
"content": {
"custom_config_key": "custom_config_value"
},
"type": "org.example.custom.room.config"
}
]
},
"ephemeral": {
"events": [
{
"content": {
"user_ids": [
"@alice:matrix.org",
"@bob:example.com"
]
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"type": "m.typing"
}
]
},
"state": {
"events": [
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"membership": "join",
"reason": "Looking for support"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@alice:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
}
]
},
"summary": {
"m.heroes": [
"@alice:example.com",
"@bob:example.com"
],
"m.invited_member_count": 0,
"m.joined_member_count": 2
},
"timeline": {
"events": [
{
"content": {
"body": "This is an example\ntext message",
"format": "org.matrix.custom.html",
"formatted_body": "<b>This is an example<br>text message</b>",
"msgtype": "m.text"
},
"event_id": "$153456789:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
}
}

View File

@@ -1,124 +0,0 @@
{
"account_data": {
"events": [
{
"content": {
"tags": {
"u.work": {
"order": 0.9
}
}
},
"type": "m.tag"
},
{
"content": {
"custom_config_key": "custom_config_value"
},
"type": "org.example.custom.room.config"
}
]
},
"ephemeral": {
"events": [
{
"content": {
"user_ids": [
"@alice:matrix.org",
"@bob:example.com"
]
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"type": "m.typing"
}
]
},
"state": {
"events": [
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"membership": "join",
"reason": "Looking for support"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@alice:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
}
]
},
"summary": {
"m.heroes": [
"@alice:example.com",
"@bob:example.com"
],
"m.invited_member_count": 0,
"m.joined_member_count": 2
},
"timeline": {
"events": [
{
"content": {
"body": "This is an **example** text message",
"format": "org.matrix.custom.html",
"formatted_body": "<b>This is an example text message</b>",
"msgtype": "m.text"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "/me This is an emote.",
"format": "org.matrix.custom.html",
"formatted_body": "This is an emote.",
"msgtype": "m.emote"
},
"event_id": "$153273582443PhrSn:example.org",
"origin_server_ts": 1532735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1231
}
},
{
"content": {
"body": "tested",
"msgtype": "m.text"
},
"event_id": "$zrCiBxBnqqTn0Z5FY78qSZAszno_w8nJJXzfBULG-3E",
"origin_server_ts": 1680948575928,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1747776,
"m.relations": {
"m.replace": {
"event_id": "$UX0PlpyI7vYO32iHMuuYEP7ECMh4sX3XLGiB2SwM4mQ",
"origin_server_ts": 1680948580992,
"sender": "@example:example.org"
}
}
}
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
}
}

View File

@@ -39,63 +39,33 @@ private:
Connection *connection = nullptr; Connection *connection = nullptr;
TestRoom *room = nullptr; TestRoom *room = nullptr;
EventHandler eventHandler; EventHandler eventHandler;
EventHandler emptyHandler;
EventHandler noEventHandler;
private Q_SLOTS: private Q_SLOTS:
void initTestCase(); void initTestCase();
void nullSetEvent();
void eventId(); void eventId();
void nullEventId();
void delegateType_data(); void delegateType_data();
void delegateType(); void delegateType();
void nullDelegateType();
void author(); void author();
void nullAuthor();
void authorDisplayName(); void authorDisplayName();
void nullAuthorDisplayName();
void singleLineSidplayName();
void nullSingleLineDisplayName();
void time(); void time();
void nullTime();
void timeString(); void timeString();
void nullTimeString();
void highlighted(); void highlighted();
void nullHighlighted();
void hidden(); void hidden();
void nullHidden();
void body(); void body();
void nullBody();
void genericBody_data(); void genericBody_data();
void genericBody(); void genericBody();
void nullGenericBody();
void mediaInfo(); void mediaInfo();
void nullMediaInfo();
void linkPreviewer(); void linkPreviewer();
void nullLinkPreviewer();
void reactions(); void reactions();
void nullReactions();
void hasReply(); void hasReply();
void nullHasReply();
void replyId(); void replyId();
void nullReplyId();
void replyDelegateType(); void replyDelegateType();
void nullReplyDelegateType();
void replyAuthor(); void replyAuthor();
void nullReplyAuthor();
void replyBody(); void replyBody();
void nullReplyBody();
void replyMediaInfo(); void replyMediaInfo();
void nullReplyMediaInfo();
void thread();
void nullThread();
void location(); void location();
void nullLocation();
void readMarkers(); void readMarkers();
void nullReadMarkers();
void cleanup();
}; };
void EventHandlerTest::initTestCase() void EventHandlerTest::initTestCase()
@@ -103,21 +73,332 @@ void EventHandlerTest::initTestCase()
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org")); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join); room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
QFile testEventHandlerSyncFile; const auto json = QJsonDocument::fromJson(R"EVENT({
testEventHandlerSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-eventhandler-sync.json")); "account_data": {
testEventHandlerSyncFile.open(QIODevice::ReadOnly); "events": [
const auto testEventHandlerSyncJson = QJsonDocument::fromJson(testEventHandlerSyncFile.readAll()); {
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testEventHandlerSyncJson.object()); "content": {
"tags": {
"u.work": {
"order": 0.9
}
}
},
"type": "m.tag"
},
{
"content": {
"custom_config_key": "custom_config_value"
},
"type": "org.example.custom.room.config"
}
]
},
"ephemeral": {
"events": [
{
"content": {
"user_ids": [
"@alice:matrix.org",
"@bob:example.com"
]
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"type": "m.typing"
},
{
"content": {
"$153456789:example.org": {
"m.read": {
"@alice:matrix.org": {
"ts": 1436451550453
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@bob:example.com": {
"ts": 1436451550453
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@tim:example.com": {
"ts": 1436451550454
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@jeff:example.com": {
"ts": 1436451550455
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@tina:example.com": {
"ts": 1436451550456
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@sally:example.com": {
"ts": 1436451550457
}
}
}
},
"type": "m.receipt"
},
{
"content": {
"$1532735824654:example.org": {
"m.read": {
"@fred:example.com": {
"ts": 1436451550458
}
}
}
},
"type": "m.receipt"
}
]
},
"state": {
"events": [
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"membership": "join",
"reason": "Looking for support"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@alice:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
}
]
},
"summary": {
"m.heroes": [
"@alice:example.com",
"@bob:example.com"
],
"m.invited_member_count": 0,
"m.joined_member_count": 2
},
"timeline": {
"events": [
{
"content": {
"body": "This is an example\ntext message",
"format": "org.matrix.custom.html",
"formatted_body": "<b>This is an example<br>text message</b>",
"msgtype": "m.text"
},
"event_id": "$153456789:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"avatar_url": "mxc://kde.org/123456",
"displayname": "after",
"membership": "join"
},
"origin_server_ts": 1690651134736,
"sender": "@example:example.org",
"state_key": "@example:example.org",
"type": "m.room.member",
"unsigned": {
"replaces_state": "$1234567890:example.org",
"prev_content": {
"avatar_url": "mxc://kde.org/12345",
"displayname": "before",
"membership": "join"
},
"prev_sender": "@example:example.orgg",
"age": 1234
},
"event_id": "$143273583553PhrSn:example.org",
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
},
{
"content": {
"body": "This is a highlight @bob:kde.org and this is a link https://kde.org",
"format": "org.matrix.custom.html",
"msgtype": "m.text"
},
"event_id": "$1532735824654:example.org",
"origin_server_ts": 1532735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1233
}
},
{
"content": {
"m.relates_to": {
"event_id": "$153456789:example.org",
"key": "👍",
"rel_type": "m.annotation"
}
},
"origin_server_ts": 1690322545182,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@alice:matrix.org",
"type": "m.reaction",
"unsigned": {
"age": 390159120
},
"event_id": "$163456789:example.org",
"age": 390159120
},
{
"age": 4926305285,
"content": {
"body": "video caption",
"filename": "video.mp4",
"info": {
"duration": 10,
"h": 1080,
"mimetype": "video/mp4",
"size": 62650636,
"w": 1920,
"thumbnail_info": {
"h": 450,
"mimetype": "image/jpeg",
"size": 382249,
"w": 800
},
"thumbnail_url": "mxc://kde.org/2234567"
},
"msgtype": "m.video",
"url": "mxc://kde.org/1234567"
},
"event_id": "$263456789:example.org",
"origin_server_ts": 1685793783330,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 4926305285
},
"user_id": "@example:example.org"
},
{
"content": {
"body": "> <@example:example.org> This is an example\ntext message\n\nreply",
"format": "org.matrix.custom.html",
"formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!jEsUZKDJdhlrceRyVU:example.org/$153456789:example.org?via=kde.org&via=matrix.org\">In reply to</a> <a href=\"https://matrix.to/#/@example:example.org\">@example:example.org</a><br><b>This is an example<br>text message</b></blockquote></mx-reply>reply",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$153456789:example.org"
}
},
"msgtype": "m.text"
},
"origin_server_ts": 1690725965572,
"sender": "@alice:matrix.org",
"type": "m.room.message",
"unsigned": {
"age": 98
},
"event_id": "$154456789:example.org",
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
},
{
"content": {
"body": "> <@example:example.org> video caption\n\nreply",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$263456789:example.org"
}
},
"msgtype": "m.text"
},
"origin_server_ts": 1690725965573,
"sender": "@alice:matrix.org",
"type": "m.room.message",
"unsigned": {
"age": 98
},
"event_id": "$154456799:example.org",
"room_id": "!jEsUZKDJdhlrceRyVU:example.org"
},
{
"age": 96845207,
"content": {
"body": "Lat: 51.7035, Lon: -1.14394",
"geo_uri": "geo:51.7035,-1.14394",
"msgtype": "m.location",
"org.matrix.msc1767.text": "Lat: 51.7035, Lon: -1.14394",
"org.matrix.msc3488.asset": {
"type": "m.pin"
},
"org.matrix.msc3488.location": {
"uri": "geo:51.7035,-1.14394"
}
},
"event_id": "$1544567999:example.org",
"origin_server_ts": 1690821582876,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 96845207
}
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
}
})EVENT");
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, json.object());
room->update(std::move(roomData)); room->update(std::move(roomData));
eventHandler.setRoom(room); eventHandler.setRoom(room);
noEventHandler.setRoom(room);
}
void EventHandlerTest::nullSetEvent()
{
QTest::ignoreMessage(QtWarningMsg, "cannot setEvent when m_room is set to nullptr.");
emptyHandler.setEvent(room->messageEvents().at(0).get());
} }
void EventHandlerTest::eventId() void EventHandlerTest::eventId()
@@ -127,12 +408,6 @@ void EventHandlerTest::eventId()
QCOMPARE(eventHandler.getId(), QStringLiteral("$153456789:example.org")); QCOMPARE(eventHandler.getId(), QStringLiteral("$153456789:example.org"));
} }
void EventHandlerTest::nullEventId()
{
QTest::ignoreMessage(QtWarningMsg, "getId called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getId(), QString());
}
void EventHandlerTest::delegateType_data() void EventHandlerTest::delegateType_data()
{ {
QTest::addColumn<int>("eventNum"); QTest::addColumn<int>("eventNum");
@@ -156,12 +431,6 @@ void EventHandlerTest::delegateType()
QCOMPARE(eventHandler.getDelegateType(), delegateType); QCOMPARE(eventHandler.getDelegateType(), delegateType);
} }
void EventHandlerTest::nullDelegateType()
{
QTest::ignoreMessage(QtWarningMsg, "getDelegateType called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getDelegateType(), DelegateType::Other);
}
void EventHandlerTest::author() void EventHandlerTest::author()
{ {
auto event = room->messageEvents().at(0).get(); auto event = room->messageEvents().at(0).get();
@@ -179,15 +448,6 @@ void EventHandlerTest::author()
QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(author)); QCOMPARE(eventHandlerAuthor["object"_ls], QVariant::fromValue(author));
} }
void EventHandlerTest::nullAuthor()
{
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getAuthor(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
QCOMPARE(noEventHandler.getAuthor(), room->getUser(nullptr));
}
void EventHandlerTest::authorDisplayName() void EventHandlerTest::authorDisplayName()
{ {
auto event = room->messageEvents().at(1).get(); auto event = room->messageEvents().at(1).get();
@@ -196,32 +456,6 @@ void EventHandlerTest::authorDisplayName()
QCOMPARE(eventHandler.getAuthorDisplayName(), QStringLiteral("before")); QCOMPARE(eventHandler.getAuthorDisplayName(), QStringLiteral("before"));
} }
void EventHandlerTest::nullAuthorDisplayName()
{
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getAuthorDisplayName(), QString());
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getAuthorDisplayName(), QString());
}
void EventHandlerTest::singleLineSidplayName()
{
auto event = room->messageEvents().at(11).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.singleLineAuthorDisplayname(), QStringLiteral("Look at me I put newlines in my display name"));
}
void EventHandlerTest::nullSingleLineDisplayName()
{
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_room set to nullptr.");
QCOMPARE(emptyHandler.singleLineAuthorDisplayname(), QString());
QTest::ignoreMessage(QtWarningMsg, "getAuthorDisplayName called with m_event set to nullptr.");
QCOMPARE(noEventHandler.singleLineAuthorDisplayname(), QString());
}
void EventHandlerTest::time() void EventHandlerTest::time()
{ {
auto event = room->messageEvents().at(0).get(); auto event = room->messageEvents().at(0).get();
@@ -231,16 +465,6 @@ void EventHandlerTest::time()
QCOMPARE(eventHandler.getTime(true, QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC)), QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC)); QCOMPARE(eventHandler.getTime(true, QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC)), QDateTime::fromMSecsSinceEpoch(1234, Qt::UTC));
} }
void EventHandlerTest::nullTime()
{
QTest::ignoreMessage(QtWarningMsg, "getTime called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getTime(), QDateTime());
eventHandler.setEvent(room->messageEvents().at(0).get());
QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
QCOMPARE(eventHandler.getTime(true), QDateTime());
}
void EventHandlerTest::timeString() void EventHandlerTest::timeString()
{ {
auto event = room->messageEvents().at(0).get(); auto event = room->messageEvents().at(0).get();
@@ -262,16 +486,6 @@ void EventHandlerTest::timeString()
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat)); format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat));
} }
void EventHandlerTest::nullTimeString()
{
QTest::ignoreMessage(QtWarningMsg, "getTimeString called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getTimeString(false), QString());
eventHandler.setEvent(room->messageEvents().at(0).get());
QTest::ignoreMessage(QtWarningMsg, "a value must be provided for lastUpdated for a pending event.");
QCOMPARE(eventHandler.getTimeString(false, QLocale::ShortFormat, true), QString());
}
void EventHandlerTest::highlighted() void EventHandlerTest::highlighted()
{ {
auto event = room->messageEvents().at(2).get(); auto event = room->messageEvents().at(2).get();
@@ -285,15 +499,6 @@ void EventHandlerTest::highlighted()
QCOMPARE(eventHandler.isHighlighted(), false); QCOMPARE(eventHandler.isHighlighted(), false);
} }
void EventHandlerTest::nullHighlighted()
{
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with m_room set to nullptr.");
QCOMPARE(emptyHandler.isHighlighted(), false);
QTest::ignoreMessage(QtWarningMsg, "isHighlighted called with m_event set to nullptr.");
QCOMPARE(noEventHandler.isHighlighted(), false);
}
void EventHandlerTest::hidden() void EventHandlerTest::hidden()
{ {
auto event = room->messageEvents().at(3).get(); auto event = room->messageEvents().at(3).get();
@@ -307,15 +512,6 @@ void EventHandlerTest::hidden()
QCOMPARE(eventHandler.isHidden(), false); QCOMPARE(eventHandler.isHidden(), false);
} }
void EventHandlerTest::nullHidden()
{
QTest::ignoreMessage(QtWarningMsg, "isHidden called with m_room set to nullptr.");
QCOMPARE(emptyHandler.isHidden(), false);
QTest::ignoreMessage(QtWarningMsg, "isHidden called with m_event set to nullptr.");
QCOMPARE(noEventHandler.isHidden(), false);
}
void EventHandlerTest::body() void EventHandlerTest::body()
{ {
auto event = room->messageEvents().at(0).get(); auto event = room->messageEvents().at(0).get();
@@ -327,15 +523,6 @@ void EventHandlerTest::body()
QCOMPARE(eventHandler.getPlainBody(true), QStringLiteral("This is an example text message")); QCOMPARE(eventHandler.getPlainBody(true), QStringLiteral("This is an example text message"));
} }
void EventHandlerTest::nullBody()
{
QTest::ignoreMessage(QtWarningMsg, "getRichBody called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getRichBody(), QString());
QTest::ignoreMessage(QtWarningMsg, "getPlainBody called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getPlainBody(), QString());
}
void EventHandlerTest::genericBody_data() void EventHandlerTest::genericBody_data()
{ {
QTest::addColumn<int>("eventNum"); QTest::addColumn<int>("eventNum");
@@ -358,12 +545,6 @@ void EventHandlerTest::genericBody()
QCOMPARE(eventHandler.getGenericBody(), output); QCOMPARE(eventHandler.getGenericBody(), output);
} }
void EventHandlerTest::nullGenericBody()
{
QTest::ignoreMessage(QtWarningMsg, "getGenericBody called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getGenericBody(), QString());
}
void EventHandlerTest::mediaInfo() void EventHandlerTest::mediaInfo()
{ {
auto event = room->messageEvents().at(4).get(); auto event = room->messageEvents().at(4).get();
@@ -387,15 +568,6 @@ void EventHandlerTest::mediaInfo()
QCOMPARE(thumbnailInfo["height"_ls], 450); QCOMPARE(thumbnailInfo["height"_ls], 450);
} }
void EventHandlerTest::nullMediaInfo()
{
QTest::ignoreMessage(QtWarningMsg, "getMediaInfo called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getMediaInfo(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "getMediaInfo called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getMediaInfo(), QVariantMap());
}
void EventHandlerTest::linkPreviewer() void EventHandlerTest::linkPreviewer()
{ {
auto event = room->messageEvents().at(2).get(); auto event = room->messageEvents().at(2).get();
@@ -409,15 +581,6 @@ void EventHandlerTest::linkPreviewer()
QCOMPARE(eventHandler.getLinkPreviewer(), nullptr); QCOMPARE(eventHandler.getLinkPreviewer(), nullptr);
} }
void EventHandlerTest::nullLinkPreviewer()
{
QTest::ignoreMessage(QtWarningMsg, "getLinkPreviewer called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getLinkPreviewer(), nullptr);
QTest::ignoreMessage(QtWarningMsg, "getLinkPreviewer called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getLinkPreviewer(), nullptr);
}
void EventHandlerTest::reactions() void EventHandlerTest::reactions()
{ {
auto event = room->messageEvents().at(0).get(); auto event = room->messageEvents().at(0).get();
@@ -426,15 +589,6 @@ void EventHandlerTest::reactions()
QCOMPARE(eventHandler.getReactions()->rowCount(), 1); QCOMPARE(eventHandler.getReactions()->rowCount(), 1);
} }
void EventHandlerTest::nullReactions()
{
QTest::ignoreMessage(QtWarningMsg, "getReactions called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReactions(), nullptr);
QTest::ignoreMessage(QtWarningMsg, "getReactions called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReactions(), nullptr);
}
void EventHandlerTest::hasReply() void EventHandlerTest::hasReply()
{ {
auto event = room->messageEvents().at(5).get(); auto event = room->messageEvents().at(5).get();
@@ -448,12 +602,6 @@ void EventHandlerTest::hasReply()
QCOMPARE(eventHandler.hasReply(), false); QCOMPARE(eventHandler.hasReply(), false);
} }
void EventHandlerTest::nullHasReply()
{
QTest::ignoreMessage(QtWarningMsg, "hasReply called with m_event set to nullptr.");
QCOMPARE(noEventHandler.hasReply(), false);
}
void EventHandlerTest::replyId() void EventHandlerTest::replyId()
{ {
auto event = room->messageEvents().at(5).get(); auto event = room->messageEvents().at(5).get();
@@ -467,12 +615,6 @@ void EventHandlerTest::replyId()
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("")); QCOMPARE(eventHandler.getReplyId(), QStringLiteral(""));
} }
void EventHandlerTest::nullReplyId()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyId called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyId(), QString());
}
void EventHandlerTest::replyDelegateType() void EventHandlerTest::replyDelegateType()
{ {
auto event = room->messageEvents().at(5).get(); auto event = room->messageEvents().at(5).get();
@@ -486,15 +628,6 @@ void EventHandlerTest::replyDelegateType()
QCOMPARE(eventHandler.getReplyDelegateType(), DelegateType::Other); QCOMPARE(eventHandler.getReplyDelegateType(), DelegateType::Other);
} }
void EventHandlerTest::nullReplyDelegateType()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyDelegateType called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReplyDelegateType(), DelegateType::Other);
QTest::ignoreMessage(QtWarningMsg, "getReplyDelegateType called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyDelegateType(), DelegateType::Other);
}
void EventHandlerTest::replyAuthor() void EventHandlerTest::replyAuthor()
{ {
auto event = room->messageEvents().at(5).get(); auto event = room->messageEvents().at(5).get();
@@ -518,15 +651,6 @@ void EventHandlerTest::replyAuthor()
QCOMPARE(eventHandler.getReplyAuthor(), room->getUser(nullptr)); QCOMPARE(eventHandler.getReplyAuthor(), room->getUser(nullptr));
} }
void EventHandlerTest::nullReplyAuthor()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReplyAuthor(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "getReplyAuthor called with m_event set to nullptr. Returning empty user.");
QCOMPARE(noEventHandler.getReplyAuthor(), room->getUser(nullptr));
}
void EventHandlerTest::replyBody() void EventHandlerTest::replyBody()
{ {
auto event = room->messageEvents().at(5).get(); auto event = room->messageEvents().at(5).get();
@@ -538,15 +662,6 @@ void EventHandlerTest::replyBody()
QCOMPARE(eventHandler.getReplyPlainBody(true), QStringLiteral("This is an example text message")); QCOMPARE(eventHandler.getReplyPlainBody(true), QStringLiteral("This is an example text message"));
} }
void EventHandlerTest::nullReplyBody()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyRichBody called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyRichBody(), QString());
QTest::ignoreMessage(QtWarningMsg, "getReplyPlainBody called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyPlainBody(), QString());
}
void EventHandlerTest::replyMediaInfo() void EventHandlerTest::replyMediaInfo()
{ {
auto event = room->messageEvents().at(6).get(); auto event = room->messageEvents().at(6).get();
@@ -571,47 +686,6 @@ void EventHandlerTest::replyMediaInfo()
QCOMPARE(thumbnailInfo["height"_ls], 450); QCOMPARE(thumbnailInfo["height"_ls], 450);
} }
void EventHandlerTest::nullReplyMediaInfo()
{
QTest::ignoreMessage(QtWarningMsg, "getReplyMediaInfo called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReplyMediaInfo(), QVariantMap());
QTest::ignoreMessage(QtWarningMsg, "getReplyMediaInfo called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReplyMediaInfo(), QVariantMap());
}
void EventHandlerTest::thread()
{
auto event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.isThreaded(), false);
QCOMPARE(eventHandler.threadRoot(), QString());
event = room->messageEvents().at(9).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.isThreaded(), true);
QCOMPARE(eventHandler.threadRoot(), QStringLiteral("$threadroot:example.org"));
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$threadroot:example.org"));
event = room->messageEvents().at(10).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.isThreaded(), true);
QCOMPARE(eventHandler.threadRoot(), QStringLiteral("$threadroot:example.org"));
QCOMPARE(eventHandler.getReplyId(), QStringLiteral("$threadmessage1:example.org"));
}
void EventHandlerTest::nullThread()
{
QTest::ignoreMessage(QtWarningMsg, "isThreaded called with m_event set to nullptr.");
QCOMPARE(emptyHandler.isThreaded(), false);
QTest::ignoreMessage(QtWarningMsg, "threadRoot called with m_event set to nullptr.");
QCOMPARE(noEventHandler.threadRoot(), QString());
}
void EventHandlerTest::location() void EventHandlerTest::location()
{ {
auto event = room->messageEvents().at(7).get(); auto event = room->messageEvents().at(7).get();
@@ -622,18 +696,6 @@ void EventHandlerTest::location()
QCOMPARE(eventHandler.getLocationAssetType(), QStringLiteral("m.pin")); QCOMPARE(eventHandler.getLocationAssetType(), QStringLiteral("m.pin"));
} }
void EventHandlerTest::nullLocation()
{
QTest::ignoreMessage(QtWarningMsg, "getLatitude called with m_event set to nullptr.");
QCOMPARE(emptyHandler.getLatitude(), -100.0);
QTest::ignoreMessage(QtWarningMsg, "getLongitude called with m_event set to nullptr.");
QCOMPARE(emptyHandler.getLongitude(), -200.0);
QTest::ignoreMessage(QtWarningMsg, "getLocationAssetType called with m_event set to nullptr.");
QCOMPARE(emptyHandler.getLocationAssetType(), QString());
}
void EventHandlerTest::readMarkers() void EventHandlerTest::readMarkers()
{ {
auto event = room->messageEvents().at(0).get(); auto event = room->messageEvents().at(0).get();
@@ -663,37 +725,5 @@ void EventHandlerTest::readMarkers()
QCOMPARE(eventHandler.getReadMarkersString().startsWith(QStringLiteral("6 users:")), true); QCOMPARE(eventHandler.getReadMarkersString().startsWith(QStringLiteral("6 users:")), true);
} }
void EventHandlerTest::nullReadMarkers()
{
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.hasReadMarkers(), false);
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReadMarkers(), QVariantList());
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getNumberExcessReadMarkers(), QString());
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReadMarkersString(), QString());
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.hasReadMarkers(), false);
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReadMarkers(), QVariantList());
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getNumberExcessReadMarkers(), QString());
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReadMarkersString(), QString());
}
void EventHandlerTest::cleanup()
{
eventHandler.setEvent(nullptr);
}
QTEST_MAIN(EventHandlerTest) QTEST_MAIN(EventHandlerTest)
#include "eventhandlertest.moc" #include "eventhandlertest.moc"

View File

@@ -42,18 +42,101 @@ void NeoChatRoomTest::initTestCase()
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org")); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join); room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
QFile testMinSyncFile; auto json = QJsonDocument::fromJson(R"EVENT({
testMinSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-min-sync.json")); "account_data": {
testMinSyncFile.open(QIODevice::ReadOnly); "events": [
const auto testMinSyncJson = QJsonDocument::fromJson(testMinSyncFile.readAll()); {
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testMinSyncJson.object()); "content": {
"tags": {
"u.work": {
"order": 0.9
}
}
},
"type": "m.tag"
},
{
"content": {
"custom_config_key": "custom_config_value"
},
"type": "org.example.custom.room.config"
}
]
},
"ephemeral": {
"events": [
{
"content": {
"user_ids": [
"@alice:matrix.org",
"@bob:example.com"
]
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"type": "m.typing"
}
]
},
"state": {
"events": [
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"membership": "join",
"reason": "Looking for support"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@alice:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
}
]
},
"summary": {
"m.heroes": [
"@alice:example.com",
"@bob:example.com"
],
"m.invited_member_count": 0,
"m.joined_member_count": 2
},
"timeline": {
"events": [
{
"content": {
"body": "This is an **example** text message",
"format": "org.matrix.custom.html",
"formatted_body": "<b>This is an example text message</b>",
"msgtype": "m.text"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1235
}
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
}
})EVENT");
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, json.object());
room->update(std::move(roomData)); room->update(std::move(roomData));
} }
void NeoChatRoomTest::subtitleTextTest() void NeoChatRoomTest::subtitleTextTest()
{ {
QCOMPARE(room->timelineSize(), 1); QCOMPARE(room->timelineSize(), 1);
QCOMPARE(room->lastEventToString(), QStringLiteral("@example:example.org: This is an example\ntext message")); QCOMPARE(room->lastEventToString(), QStringLiteral("@example:example.org: This is an example text message"));
} }
void NeoChatRoomTest::eventTest() void NeoChatRoomTest::eventTest()

View File

@@ -40,7 +40,6 @@ private Q_SLOTS:
void stripDisallowedTags(); void stripDisallowedTags();
void stripDisallowedAttributes(); void stripDisallowedAttributes();
void emptyCodeTags(); void emptyCodeTags();
void formatBlockQuote();
void sendSimpleStringCase(); void sendSimpleStringCase();
void sendSingleParaMarkup(); void sendSingleParaMarkup();
@@ -67,7 +66,6 @@ private Q_SLOTS:
void receiveRichEdited_data(); void receiveRichEdited_data();
void receiveRichEdited(); void receiveRichEdited();
void receiveLineSeparator(); void receiveLineSeparator();
void receiveRichCodeUrl();
void linkPreviewsMatch_data(); void linkPreviewsMatch_data();
void linkPreviewsMatch(); void linkPreviewsMatch();
@@ -80,11 +78,131 @@ void TextHandlerTest::initTestCase()
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org")); connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join); room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join);
QFile testTextHandlerSyncFile; const auto json = QJsonDocument::fromJson(R"EVENT({
testTextHandlerSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-texthandler-sync.json")); "account_data": {
testTextHandlerSyncFile.open(QIODevice::ReadOnly); "events": [
const auto testTextHandlerSyncJson = QJsonDocument::fromJson(testTextHandlerSyncFile.readAll()); {
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testTextHandlerSyncJson.object()); "content": {
"tags": {
"u.work": {
"order": 0.9
}
}
},
"type": "m.tag"
},
{
"content": {
"custom_config_key": "custom_config_value"
},
"type": "org.example.custom.room.config"
}
]
},
"ephemeral": {
"events": [
{
"content": {
"user_ids": [
"@alice:matrix.org",
"@bob:example.com"
]
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"type": "m.typing"
}
]
},
"state": {
"events": [
{
"content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"membership": "join",
"reason": "Looking for support"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@alice:example.org",
"type": "m.room.member",
"unsigned": {
"age": 1234
}
}
]
},
"summary": {
"m.heroes": [
"@alice:example.com",
"@bob:example.com"
],
"m.invited_member_count": 0,
"m.joined_member_count": 2
},
"timeline": {
"events": [
{
"content": {
"body": "This is an **example** text message",
"format": "org.matrix.custom.html",
"formatted_body": "<b>This is an example text message</b>",
"msgtype": "m.text"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1232
}
},
{
"content": {
"body": "/me This is an emote.",
"format": "org.matrix.custom.html",
"formatted_body": "This is an emote.",
"msgtype": "m.emote"
},
"event_id": "$153273582443PhrSn:example.org",
"origin_server_ts": 1532735824654,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1231
}
},
{
"content": {
"body": "tested",
"msgtype": "m.text"
},
"event_id": "$zrCiBxBnqqTn0Z5FY78qSZAszno_w8nJJXzfBULG-3E",
"origin_server_ts": 1680948575928,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1747776,
"m.relations": {
"m.replace": {
"event_id": "$UX0PlpyI7vYO32iHMuuYEP7ECMh4sX3XLGiB2SwM4mQ",
"origin_server_ts": 1680948580992,
"sender": "@example:example.org"
}
}
}
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
}
})EVENT");
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, json.object());
room->update(std::move(roomData)); room->update(std::move(roomData));
} }
@@ -147,16 +265,6 @@ void TextHandlerTest::emptyCodeTags()
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString); QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
} }
void TextHandlerTest::formatBlockQuote()
{
auto input = QStringLiteral("<blockquote>\n<p>Lorem Ispum</p>\n</blockquote>");
auto expectedOutput = QStringLiteral("<blockquote><table><tr><td>\u201CLorem Ispum\u201D</td></tr></table></blockquote>");
TextHandler testTextHandler;
testTextHandler.setData(input);
QCOMPARE(testTextHandler.handleRecieveRichText(), expectedOutput);
}
void TextHandlerTest::sendSimpleStringCase() void TextHandlerTest::sendSimpleStringCase()
{ {
const QString testInputString = QStringLiteral("This data should just be put in a paragraph."); const QString testInputString = QStringLiteral("This data should just be put in a paragraph.");
@@ -469,9 +577,8 @@ void TextHandlerTest::receiveRichEdited_data()
QTest::newRow("basic") << QStringLiteral("Edited") << QStringLiteral("Edited <span style=\"color:#000000\">(edited)</span>"); QTest::newRow("basic") << QStringLiteral("Edited") << QStringLiteral("Edited <span style=\"color:#000000\">(edited)</span>");
QTest::newRow("multiple paragraphs") << QStringLiteral("<p>Edited</p>\n<p>Edited</p>") QTest::newRow("multiple paragraphs") << QStringLiteral("<p>Edited</p>\n<p>Edited</p>")
<< QStringLiteral("<p>Edited</p>\n<p>Edited <span style=\"color:#000000\">(edited)</span></p>"); << QStringLiteral("<p>Edited</p>\n<p>Edited <span style=\"color:#000000\">(edited)</span></p>");
QTest::newRow("blockquote") QTest::newRow("blockquote") << QStringLiteral("<blockquote>Edited</blockquote>")
<< QStringLiteral("<blockquote>Edited</blockquote>") << QStringLiteral("<blockquote>Edited</blockquote><p> <span style=\"color:#000000\">(edited)</span></p>");
<< QStringLiteral("<blockquote><table><tr><td>\u201CEdited\u201D</td></tr></table></blockquote><p> <span style=\"color:#000000\">(edited)</span></p>");
} }
void TextHandlerTest::receiveRichEdited() void TextHandlerTest::receiveRichEdited()
@@ -540,13 +647,5 @@ void TextHandlerTest::linkPreviewsReject()
QCOMPARE(testTextHandler.getLinkPreviews(), testOutputLinks); QCOMPARE(testTextHandler.getLinkPreviews(), testOutputLinks);
} }
void TextHandlerTest::receiveRichCodeUrl()
{
auto input = QStringLiteral("<code>https://kde.org</code>");
TextHandler testTextHandler;
testTextHandler.setData(input);
QCOMPARE(testTextHandler.handleRecieveRichText(), input);
}
QTEST_MAIN(TextHandlerTest) QTEST_MAIN(TextHandlerTest)
#include "texthandlertest.moc" #include "texthandlertest.moc"

View File

@@ -2,4 +2,4 @@
# #
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
kdoctools_create_manpage(man-neochat.1.docbook 1 INSTALL_DESTINATION ${KDE_INSTALL_MANDIR}) kdoctools_create_manpage(man-neochat.1.docbook 1 INSTALL_DESTINATION ${MAN_INSTALL_DIR})

View File

@@ -11,7 +11,6 @@
</provides> </provides>
<name>NeoChat</name> <name>NeoChat</name>
<name xml:lang="ar">نيوتشات</name> <name xml:lang="ar">نيوتشات</name>
<name xml:lang="ast">NeoChat</name>
<name xml:lang="az">NeoChat</name> <name xml:lang="az">NeoChat</name>
<name xml:lang="ca">NeoChat</name> <name xml:lang="ca">NeoChat</name>
<name xml:lang="ca-valencia">NeoChat</name> <name xml:lang="ca-valencia">NeoChat</name>
@@ -54,7 +53,6 @@
<summary xml:lang="eo">Babilu kun viaj amikoj sur matrix</summary> <summary xml:lang="eo">Babilu kun viaj amikoj sur matrix</summary>
<summary xml:lang="es">Charle con sus amigos en matrix</summary> <summary xml:lang="es">Charle con sus amigos en matrix</summary>
<summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary> <summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary>
<summary xml:lang="fi">Keskustelu ystäviesi kanssa Matrixissa</summary>
<summary xml:lang="fr">Discuter avec vos ami(e)s sur le réseau Matrix</summary> <summary xml:lang="fr">Discuter avec vos ami(e)s sur le réseau Matrix</summary>
<summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary> <summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary>
<summary xml:lang="ia">Starta Conversation conntu amicos sur matrix</summary> <summary xml:lang="ia">Starta Conversation conntu amicos sur matrix</summary>
@@ -99,7 +97,7 @@ to provide a convergent experience across multiple platforms.</p>
<p>NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p> <p>NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p>
<p xml:lang="ar">يهدف نيوتشات إلى أن يكون تطبيقًا كامل الميزات لمواصفات ماتركس. على هذا النحو يتم دعم كل شيء في المواصفات المستقرة الحالية مع الاستثناءات الملحوظة لـ VoIP والخيوط وبعض جوانب التشفير من طرف إلى طرف. هناك عدد قليل من الإغفالات الصغيرة الأخرى بسبب حقيقة أن مواصفات ماتركس تتطور باستمرار ، ولكن يبقى الهدف توفير الدعم النهائي للمواصفات بأكملها.</p> <p xml:lang="ar">يهدف نيوتشات إلى أن يكون تطبيقًا كامل الميزات لمواصفات ماتركس. على هذا النحو يتم دعم كل شيء في المواصفات المستقرة الحالية مع الاستثناءات الملحوظة لـ VoIP والخيوط وبعض جوانب التشفير من طرف إلى طرف. هناك عدد قليل من الإغفالات الصغيرة الأخرى بسبب حقيقة أن مواصفات ماتركس تتطور باستمرار ، ولكن يبقى الهدف توفير الدعم النهائي للمواصفات بأكملها.</p>
<p xml:lang="ca">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptatge d'extrem a extrem. Hi ha algunes altres omissions més petites a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu segueix sent proporcionar suport eventual per a tota l'especificació.</p> <p xml:lang="ca">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptatge d'extrem a extrem. Hi ha algunes altres omissions més petites a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu segueix sent proporcionar suport eventual per a tota l'especificació.</p>
<p xml:lang="ca-valencia">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptació d'extrem a extrem. Hi ha algunes altres omissions més xicotetes a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu seguix sent proporcionar suport eventual per a tota l'especificació.</p> <p xml:lang="ca-valencia">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de VoIP, fils i alguns aspectes de l'encriptació d'extrem a extrem. Hi ha algunes altres omissions més xicotetes a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu seguix sent proporcionar suport eventual per a tota l'especificació.</p>
<p xml:lang="en-GB">NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p> <p xml:lang="en-GB">NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly evolving but the aim remains to provide eventual support for the entire spec.</p>
<p xml:lang="eo">NeoChat celas esti plene kapabla aplikaĵo por la Matrix-specifo. Kiel tia, ĉio en la nuna stabila specifo kun la rimarkindaj esceptoj de VoIP, fadenoj kaj kelkaj aspektoj de Fin-al-Fina Ĉifrado estas subtenataj. Estas kelkaj aliaj pli malgrandaj preterlasoj pro la fakto, ke la Matrix-speco konstante evoluas, sed la celo restas provizi finfine subtenon por la tuta specifaĵo.</p> <p xml:lang="eo">NeoChat celas esti plene kapabla aplikaĵo por la Matrix-specifo. Kiel tia, ĉio en la nuna stabila specifo kun la rimarkindaj esceptoj de VoIP, fadenoj kaj kelkaj aspektoj de Fin-al-Fina Ĉifrado estas subtenataj. Estas kelkaj aliaj pli malgrandaj preterlasoj pro la fakto, ke la Matrix-speco konstante evoluas, sed la celo restas provizi finfine subtenon por la tuta specifaĵo.</p>
<p xml:lang="es">NeoChat pretende ser una aplicación con todas las funciones para la especificación de Matrix. Como tal, admite todo en la especificación estable actual, con las notables excepciones de VoIP, subprocesos y algunas funciones de cifrado de extremo a extremo. Existen algunas omisiones menos importantes debido al hecho de que la especificación de Matrix está en constante evolución, pero el objetivo sigue siendo brindar compatibilidad final con toda la especificación.</p> <p xml:lang="es">NeoChat pretende ser una aplicación con todas las funciones para la especificación de Matrix. Como tal, admite todo en la especificación estable actual, con las notables excepciones de VoIP, subprocesos y algunas funciones de cifrado de extremo a extremo. Existen algunas omisiones menos importantes debido al hecho de que la especificación de Matrix está en constante evolución, pero el objetivo sigue siendo brindar compatibilidad final con toda la especificación.</p>
@@ -284,7 +282,7 @@ to provide a convergent experience across multiple platforms.</p>
<screenshot type="default"> <screenshot type="default">
<image>https://cdn.kde.org/screenshots/neochat/application.png</image> <image>https://cdn.kde.org/screenshots/neochat/application.png</image>
</screenshot> </screenshot>
<screenshot environment="windows"> <screenshot x-kde-os="windows">
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</image> <image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</image>
<caption>Main view with room list, chat, and room information</caption> <caption>Main view with room list, chat, and room information</caption>
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption> <caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
@@ -311,7 +309,7 @@ to provide a convergent experience across multiple platforms.</p>
<caption xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</caption> <caption xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</caption>
<caption xml:lang="x-test">xxMain view with room list, chat, and room informationxx</caption> <caption xml:lang="x-test">xxMain view with room list, chat, and room informationxx</caption>
</screenshot> </screenshot>
<screenshot environment="windows"> <screenshot x-kde-os="windows">
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Login.png</image> <image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Login.png</image>
<caption>Login screen</caption> <caption>Login screen</caption>
<caption xml:lang="ar">شاشة الدخول</caption> <caption xml:lang="ar">شاشة الدخول</caption>
@@ -343,8 +341,6 @@ to provide a convergent experience across multiple platforms.</p>
<content_attribute id="social-chat">intense</content_attribute> <content_attribute id="social-chat">intense</content_attribute>
</content_rating> </content_rating>
<releases> <releases>
<release version="23.08.3" date="2023-11-09"/>
<release version="23.08.2" date="2023-10-12"/>
<release version="23.08.0" date="2023-08-24"> <release version="23.08.0" date="2023-08-24">
<url>https://kde.org/announcements/gear/23.08.0/#neochathttpsappskdeorgneochat</url> <url>https://kde.org/announcements/gear/23.08.0/#neochathttpsappskdeorgneochat</url>
<description> <description>

View File

@@ -4,7 +4,6 @@
Version=1.5 Version=1.5
Name=NeoChat Name=NeoChat
Name[ar]=نيوتشات Name[ar]=نيوتشات
Name[ast]=NeoChat
Name[az]=NeoChat Name[az]=NeoChat
Name[ca]=NeoChat Name[ca]=NeoChat
Name[ca@valencia]=NeoChat Name[ca@valencia]=NeoChat

View File

@@ -1,8 +1 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="22" height="22" fill="none" version="1.1" id="svg13" xmlns="http://www.w3.org/2000/svg"><style type="text/css" id="current-color-scheme">.ColorScheme-Text{color:#232629}</style><path class="ColorScheme-Text" style="fill:currentColor;fill-opacity:1;stroke:none" fill-rule="evenodd" clip-rule="evenodd" d="M2 4h18v11H6.681L3 18.067V15H2zm1 10h1v1.933L6.319 14H19V5H3z" id="path3"/><path class="ColorScheme-Text" style="fill:currentColor;fill-opacity:1;stroke:none" id="rect5" d="M4 7h9v1H4z"/><path class="ColorScheme-Text" style="fill:currentColor;fill-opacity:1;stroke:none" id="rect7" d="M4 9h7v1H4z"/><path class="ColorScheme-Text" style="fill:currentColor;fill-opacity:1;stroke:none" id="rect9" d="M4 11h5v1H4z"/><path class="ColorScheme-Text" style="fill:currentColor;fill-opacity:1;stroke:none" fill-rule="evenodd" clip-rule="evenodd" d="m16 15.293-1.147-1.146-.707.707 2.853 2.853V14.5h-1z" id="path11"/></svg>
<style type="text/css" id="current-color-scheme">.ColorScheme-Text{color:#232629}</style>
<path class="ColorScheme-Text" fill-rule="evenodd" clip-rule="evenodd" d="M3 3H19V14H8.68787L4 18.1019V14H3V3ZM4 13H5V15.8981L8.31213 13H18V4H4V13Z" fill="currentColor"/>
<path class="ColorScheme-Text" fill-rule="evenodd" clip-rule="evenodd" d="M17 15.2929L14.8536 13.1465L14.1465 13.8536L18 17.7071V13.5H17V15.2929Z" fill="currentColor"/>
<path class="ColorScheme-Text" d="M5 6H15V7H5V6Z" fill="currentColor"/>
<path class="ColorScheme-Text" d="M5 8H13V9H5V8Z" fill="currentColor"/>
<path class="ColorScheme-Text" d="M5 10H11V11H5V10Z" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 752 B

After

Width:  |  Height:  |  Size: 928 B

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -40,12 +40,6 @@ add_library(neochat STATIC
models/userfiltermodel.h models/userfiltermodel.h
models/publicroomlistmodel.cpp models/publicroomlistmodel.cpp
models/publicroomlistmodel.h models/publicroomlistmodel.h
models/spacechildrenmodel.cpp
models/spacechildrenmodel.h
models/spacechildsortfiltermodel.cpp
models/spacechildsortfiltermodel.h
models/spacetreeitem.cpp
models/spacetreeitem.h
models/userdirectorylistmodel.cpp models/userdirectorylistmodel.cpp
models/userdirectorylistmodel.h models/userdirectorylistmodel.h
models/pushrulemodel.cpp models/pushrulemodel.cpp
@@ -133,16 +127,6 @@ add_library(neochat STATIC
mediasizehelper.h mediasizehelper.h
eventhandler.cpp eventhandler.cpp
enums/delegatetype.h enums/delegatetype.h
roomlastmessageprovider.cpp
roomlastmessageprovider.h
chatbarcache.cpp
chatbarcache.h
colorschemer.cpp
colorschemer.h
models/notificationsmodel.cpp
models/notificationsmodel.h
models/timelinemodel.cpp
models/timelinemodel.h
) )
qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
@@ -150,33 +134,33 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/main.qml qml/main.qml
qml/AccountMenu.qml qml/AccountMenu.qml
qml/ExploreComponent.qml qml/ExploreComponent.qml
qml/ExploreComponentMobile.qml
qml/ContextMenu.qml qml/ContextMenu.qml
qml/CollapsedRoomDelegate.qml qml/CollapsedRoomDelegate.qml
qml/RoomDelegate.qml qml/RoomDelegate.qml
qml/RoomListPage.qml qml/RoomListPage.qml
qml/SpaceListContextMenu.qml qml/SpaceListContextMenu.qml
qml/UserInfo.qml qml/UserInfo.qml
qml/UserInfoDesktop.qml qml/LoadingPage.qml
qml/RoomPage.qml qml/RoomPage.qml
qml/RoomWindow.qml qml/RoomWindow.qml
qml/JoinRoomPage.qml qml/JoinRoomPage.qml
qml/ManualRoomDialog.qml
qml/ExplorerDelegate.qml qml/ExplorerDelegate.qml
qml/InviteUserPage.qml qml/InviteUserPage.qml
qml/StartChatPage.qml qml/StartChatPage.qml
qml/ImageEditorPage.qml qml/ImageEditorPage.qml
qml/WelcomePage.qml qml/WelcomePage.qml
qml/General.qml qml/General.qml
qml/RoomSecurity.qml qml/Security.qml
qml/PushNotification.qml qml/PushNotification.qml
qml/Categories.qml qml/Categories.qml
qml/Permissions.qml qml/Permissions.qml
qml/NeochatMaximizeComponent.qml qml/NeochatMaximizeComponent.qml
qml/FancyEffectsContainer.qml qml/FancyEffectsContainer.qml
qml/TypingPane.qml qml/TypingPane.qml
qml/ShimmerGradient.qml
qml/QuickSwitcher.qml qml/QuickSwitcher.qml
qml/HoverActions.qml qml/HoverActions.qml
qml/ChatBox.qml
qml/ChatBar.qml qml/ChatBar.qml
qml/AttachmentPane.qml qml/AttachmentPane.qml
qml/ReplyPane.qml qml/ReplyPane.qml
@@ -223,6 +207,7 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/Sso.qml qml/Sso.qml
qml/UserDetailDialog.qml qml/UserDetailDialog.qml
qml/CreateRoomDialog.qml qml/CreateRoomDialog.qml
qml/CreateSpaceDialog.qml
qml/EmojiDialog.qml qml/EmojiDialog.qml
qml/OpenFileDialog.qml qml/OpenFileDialog.qml
qml/KeyVerificationDialog.qml qml/KeyVerificationDialog.qml
@@ -286,26 +271,11 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/RoomMedia.qml qml/RoomMedia.qml
qml/ChooseRoomDialog.qml qml/ChooseRoomDialog.qml
qml/ShareAction.qml qml/ShareAction.qml
qml/SpaceHomePage.qml
qml/SpaceHierarchyDelegate.qml
qml/RemoveChildDialog.qml
qml/SelectParentDialog.qml
qml/Security.qml
qml/QrCodeMaximizeComponent.qml
qml/SelectSpacesDialog.qml
qml/AttachDialog.qml
qml/NotificationsView.qml
qml/LoadingDelegate.qml
qml/TimelineEndDelegate.qml
RESOURCES RESOURCES
qml/confetti.png qml/confetti.png
qml/glowdot.png qml/glowdot.png
) )
if(WIN32)
set_target_properties(neochat PROPERTIES OUTPUT_NAME "neochatlib")
endif()
ecm_qt_declare_logging_category(neochat ecm_qt_declare_logging_category(neochat
HEADER "messageeventmodel_logging.h" HEADER "messageeventmodel_logging.h"
IDENTIFIER "MessageEvent" IDENTIFIER "MessageEvent"
@@ -322,13 +292,6 @@ ecm_qt_declare_logging_category(neochat
DEFAULT_SEVERITY Info DEFAULT_SEVERITY Info
) )
ecm_qt_declare_logging_category(neochat
HEADER "chatdocumenthandler_logging.h"
IDENTIFIER "ChatDocumentHandling"
CATEGORY_NAME "org.kde.neochat.chatdocumenthandler"
DEFAULT_SEVERITY Info
)
add_executable(neochat-app add_executable(neochat-app
main.cpp main.cpp
) )
@@ -349,15 +312,16 @@ ecm_add_app_icon(NEOCHAT_ICON ICONS ${CMAKE_SOURCE_DIR}/128-logo.png)
target_sources(neochat-app PRIVATE ${NEOCHAT_ICON}) target_sources(neochat-app PRIVATE ${NEOCHAT_ICON})
if(NOT ANDROID) if(NOT ANDROID)
target_sources(neochat PRIVATE colorschemer.cpp colorschemer.h)
if (NOT WIN32 AND NOT APPLE) if (NOT WIN32 AND NOT APPLE)
target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h) target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h)
target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem) target_link_libraries(neochat PRIVATE KF6::StatusNotifierItem)
else() else()
target_sources(neochat PRIVATE trayicon.cpp trayicon.h) target_sources(neochat PRIVATE trayicon.cpp trayicon.h)
endif() endif()
target_link_libraries(neochat PUBLIC KF6::WindowSystem ICU::uc) target_link_libraries(neochat PUBLIC KF6::ConfigWidgets KF6::WindowSystem)
target_compile_definitions(neochat PUBLIC -DHAVE_COLORSCHEME)
target_compile_definitions(neochat PUBLIC -DHAVE_WINDOWSYSTEM) target_compile_definitions(neochat PUBLIC -DHAVE_WINDOWSYSTEM)
target_compile_definitions(neochat PUBLIC -DHAVE_ICU)
endif() endif()
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE) if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
@@ -367,28 +331,7 @@ if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
endif() endif()
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums) target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
target_link_libraries(neochat PUBLIC target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF6::I18n KF6::Kirigami2 KF6::Notifications KF6::ConfigCore KF6::ConfigGui KF6::CoreAddons KF6::SonnetCore KF6::ItemModels QuotientQt6 cmark::cmark QCoro::Core)
Qt::Core
Qt::Quick
Qt::Qml
Qt::Gui
Qt::Multimedia
Qt::Network
Qt::QuickControls2
KF6::I18n
KF6::Kirigami
KF6::Notifications
KF6::ConfigCore
KF6::ConfigGui
KF6::CoreAddons
KF6::SonnetCore
KF6::ColorScheme
KF6::ItemModels
QuotientQt6
cmark::cmark
QCoro::Core
QCoro::Network
)
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc) kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
@@ -474,9 +417,7 @@ if(ANDROID)
"preferences-desktop-notification" "preferences-desktop-notification"
"computer-symbolic" "computer-symbolic"
"gps" "gps"
"system-users-symbolic"
) )
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
else() else()
target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets) target_link_libraries(neochat PUBLIC Qt::Widgets KF6::KIOWidgets)
install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR}) install(FILES neochat.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
@@ -495,18 +436,9 @@ if (TARGET KF6::KIOWidgets)
target_compile_definitions(neochat PUBLIC -DHAVE_KIO) target_compile_definitions(neochat PUBLIC -DHAVE_KIO)
endif() endif()
if (TARGET KUnifiedPush)
target_compile_definitions(neochat PUBLIC -DHAVE_KUNIFIEDPUSH)
target_link_libraries(neochat PUBLIC KUnifiedPush)
if (NOT ANDROID)
configure_file(org.kde.neochat.service.in ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.service)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.neochat.service DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR})
endif()
endif()
install(TARGETS neochat-app ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS neochat-app ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE) if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins) install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins)
endif() endif()

View File

@@ -38,33 +38,45 @@ void ActionsHandler::setRoom(NeoChatRoom *room)
Q_EMIT roomChanged(); Q_EMIT roomChanged();
} }
void ActionsHandler::handleMessageEvent(ChatBarCache *chatBarCache) void ActionsHandler::handleNewMessage()
{ {
if (!chatBarCache) { checkEffects(m_room->chatBoxText());
return; if (!m_room->chatBoxAttachmentPath().isEmpty()) {
} QUrl url(m_room->chatBoxAttachmentPath());
checkEffects(chatBarCache->text());
if (!chatBarCache->attachmentPath().isEmpty()) {
QUrl url(chatBarCache->attachmentPath());
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString(); auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
m_room->uploadFile(QUrl(path), chatBarCache->text().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : chatBarCache->text()); m_room->uploadFile(QUrl(path), m_room->chatBoxText().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : m_room->chatBoxText());
chatBarCache->setAttachmentPath({}); m_room->setChatBoxAttachmentPath({});
chatBarCache->setText({}); m_room->setChatBoxText({});
return; return;
} }
QString handledText = chatBarCache->text(); QString handledText = m_room->chatBoxText();
handledText = handleMentions(handledText, chatBarCache->mentions()); handledText = handleMentions(handledText);
handleMessage(m_room->mainCache()->text(), handledText, chatBarCache); handleMessage(m_room->chatBoxText(), handledText);
} }
QString ActionsHandler::handleMentions(QString handledText, QList<Mention> *mentions) void ActionsHandler::handleEdit()
{
checkEffects(m_room->editText());
QString handledText = m_room->editText();
handledText = handleMentions(handledText, true);
handleMessage(m_room->editText(), handledText, true);
}
QString ActionsHandler::handleMentions(QString handledText, const bool &isEdit)
{ {
if (!m_room) { if (!m_room) {
return QString(); return QString();
} }
QVector<Mention> *mentions;
if (isEdit) {
mentions = m_room->editMentions();
} else {
mentions = m_room->mentions();
}
std::sort(mentions->begin(), mentions->end(), [](const auto &a, const auto &b) -> bool { std::sort(mentions->begin(), mentions->end(), [](const auto &a, const auto &b) -> bool {
return a.cursor.anchor() > b.cursor.anchor(); return a.cursor.anchor() > b.cursor.anchor();
}); });
@@ -75,14 +87,14 @@ QString ActionsHandler::handleMentions(QString handledText, QList<Mention> *ment
} }
handledText = handledText.replace(mention.cursor.anchor(), handledText = handledText.replace(mention.cursor.anchor(),
mention.cursor.position() - mention.cursor.anchor(), mention.cursor.position() - mention.cursor.anchor(),
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text.toHtmlEscaped(), mention.id)); QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text, mention.id));
} }
mentions->clear(); mentions->clear();
return handledText; return handledText;
} }
void ActionsHandler::handleMessage(const QString &text, QString handledText, ChatBarCache *chatBarCache) void ActionsHandler::handleMessage(const QString &text, QString handledText, const bool &isEdit)
{ {
if (NeoChatConfig::allowQuickEdit()) { if (NeoChatConfig::allowQuickEdit()) {
QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$")); QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$"));
@@ -122,7 +134,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
for (const auto &action : ActionsModel::instance().allActions()) { for (const auto &action : ActionsModel::instance().allActions()) {
if (handledText.indexOf(action.prefix) == 1 if (handledText.indexOf(action.prefix) == 1
&& (handledText.indexOf(" "_ls) == action.prefix.length() + 1 || handledText.length() == action.prefix.length() + 1)) { && (handledText.indexOf(" "_ls) == action.prefix.length() + 1 || handledText.length() == action.prefix.length() + 1)) {
handledText = action.handle(handledText.mid(action.prefix.length() + 1).trimmed(), m_room, chatBarCache); handledText = action.handle(handledText.mid(action.prefix.length() + 1).trimmed(), m_room);
if (action.messageType.has_value()) { if (action.messageType.has_value()) {
messageType = *action.messageType; messageType = *action.messageType;
} }
@@ -149,7 +161,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
return; return;
} }
m_room->postMessage(text, handledText, messageType, chatBarCache->replyId(), chatBarCache->editId(), chatBarCache->threadId()); m_room->postMessage(text, handledText, messageType, m_room->chatBoxReplyId(), isEdit ? m_room->chatBoxEditId() : QString());
} }
void ActionsHandler::checkEffects(const QString &text) void ActionsHandler::checkEffects(const QString &text)

View File

@@ -8,7 +8,6 @@
#include <Quotient/events/roommessageevent.h> #include <Quotient/events/roommessageevent.h>
#include "chatbarcache.h"
#include "neochatroom.h" #include "neochatroom.h"
class NeoChatRoom; class NeoChatRoom;
@@ -52,15 +51,21 @@ Q_SIGNALS:
void showEffect(const QString &effect); void showEffect(const QString &effect);
public Q_SLOTS: public Q_SLOTS:
/** /**
* @brief Pre-process text and send message event. * @brief Pre-process text and send message.
*/ */
void handleMessageEvent(ChatBarCache *chatBarCache); void handleNewMessage();
/**
* @brief Pre-process text and send edit.
*/
void handleEdit();
private: private:
NeoChatRoom *m_room = nullptr; NeoChatRoom *m_room = nullptr;
void checkEffects(const QString &text); void checkEffects(const QString &text);
QString handleMentions(QString handledText, QList<Mention> *mentions); QString handleMentions(QString handledText, const bool &isEdit = false);
void handleMessage(const QString &text, QString handledText, ChatBarCache *chatBarCache); void handleMessage(const QString &text, QString handledText, const bool &isEdit = false);
}; };

View File

@@ -177,7 +177,7 @@ uint8_t *decode(const char *blurhash, int width, int height, int punch, int nCha
uint8_t *pixelArray = createByteArray(bytesPerRow * height); uint8_t *pixelArray = createByteArray(bytesPerRow * height);
if (decodeToArray(blurhash, width, height, punch, nChannels, pixelArray) == -1) { if (decodeToArray(blurhash, width, height, punch, nChannels, pixelArray) == -1) {
return nullptr; return NULL;
} }
return pixelArray; return pixelArray;
} }

View File

@@ -1,177 +0,0 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include "chatbarcache.h"
#include "eventhandler.h"
#include "neochatroom.h"
ChatBarCache::ChatBarCache(QObject *parent)
: QObject(parent)
{
}
QString ChatBarCache::text() const
{
return m_text;
}
void ChatBarCache::setText(const QString &text)
{
if (text == m_text) {
return;
}
m_text = text;
Q_EMIT textChanged();
}
bool ChatBarCache::isReplying() const
{
return m_relationType == Reply && !m_relationId.isEmpty();
}
QString ChatBarCache::replyId() const
{
if (m_relationType != Reply) {
return {};
}
return m_relationId;
}
void ChatBarCache::setReplyId(const QString &replyId)
{
if (m_relationType == Reply && m_relationId == replyId) {
return;
}
m_relationId = replyId;
if (m_relationId.isEmpty()) {
m_relationType = None;
} else {
m_relationType = Reply;
}
m_attachmentPath = QString();
Q_EMIT relationIdChanged();
Q_EMIT attachmentPathChanged();
}
bool ChatBarCache::isEditing() const
{
return m_relationType == Edit && !m_relationId.isEmpty();
}
QString ChatBarCache::editId() const
{
if (m_relationType != Edit) {
return {};
}
return m_relationId;
}
void ChatBarCache::setEditId(const QString &editId)
{
if (m_relationType == Edit && m_relationId == editId) {
return;
}
m_relationId = editId;
if (m_relationId.isEmpty()) {
m_relationType = None;
} else {
m_relationType = Edit;
}
m_attachmentPath = QString();
Q_EMIT relationIdChanged();
Q_EMIT attachmentPathChanged();
}
QVariantMap ChatBarCache::relationUser() const
{
if (parent() == nullptr) {
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
return {};
}
auto room = dynamic_cast<NeoChatRoom *>(parent());
if (room == nullptr) {
qWarning() << "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.";
return {};
}
if (m_relationId.isEmpty()) {
return room->getUser(nullptr);
}
return room->getUser(room->user((*room->findInTimeline(m_relationId))->senderId()));
}
QString ChatBarCache::relationMessage() const
{
if (parent() == nullptr) {
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
return {};
}
if (m_relationId.isEmpty()) {
return {};
}
auto room = dynamic_cast<NeoChatRoom *>(parent());
if (room == nullptr) {
qWarning() << "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.";
return {};
}
EventHandler eventhandler;
eventhandler.setRoom(room);
if (auto event = room->findInTimeline(m_relationId); event != room->historyEdge()) {
eventhandler.setEvent(&**event);
return eventhandler.getPlainBody();
}
return {};
}
bool ChatBarCache::isThreaded() const
{
return !m_threadId.isEmpty();
}
QString ChatBarCache::threadId() const
{
return m_threadId;
}
void ChatBarCache::setThreadId(const QString &threadId)
{
if (m_threadId == threadId) {
return;
}
m_threadId = threadId;
Q_EMIT threadIdChanged();
}
QString ChatBarCache::attachmentPath() const
{
return m_attachmentPath;
}
void ChatBarCache::setAttachmentPath(const QString &attachmentPath)
{
if (attachmentPath == m_attachmentPath) {
return;
}
m_attachmentPath = attachmentPath;
m_relationType = None;
m_relationId = QString();
Q_EMIT attachmentPathChanged();
Q_EMIT relationIdChanged();
}
QList<Mention> *ChatBarCache::mentions()
{
return &m_mentions;
}
QString ChatBarCache::savedText() const
{
return m_savedText;
}
void ChatBarCache::setSavedText(const QString &savedText)
{
m_savedText = savedText;
}
#include "moc_chatbarcache.cpp"

View File

@@ -1,201 +0,0 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <QObject>
#include <QQmlEngine>
#include <QTextCursor>
/**
* @brief Defines a user mention in the current chat or edit text.
*/
struct Mention {
QTextCursor cursor; /**< Contains the mention's text and position in the text. */
QString text; /**< The inserted text of the mention. */
int start = 0; /**< Start position of the mention. */
int position = 0; /**< End position of the mention. */
QString id; /**< The id the mention (used to create link when sending the message). */
};
/**
* @class ChatBarCache
*
* A class to cache data from a chat bar.
*
* A chat bar can be anything that allows users to compose or edit message, it doesn't
* necessarily have to use the ChatBar component, e.g. MessageEditComponent.
*
* This object is intended to allow the current contents of a chat bar to be cached
* between different rooms, i.e. there is an expectation that each NeoChatRoom could
* have a separate cache for each chat bar.
*
* @note The NeoChatRoom which this component is created in is expected to be set
* as it's parent. This is necessary for certain functions which need to get
* relevant room information.
*
* @sa ChatBar, MessageEditComponent, NeoChatRoom
*/
class ChatBarCache : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
/**
* @brief The text in the chat bar.
*
* Due to problems with QTextDocument, unlike the other properties here,
* text is *not* used to store the text when switching rooms.
*/
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
/**
* @brief Whether the chat bar is currently replying to a message.
*/
Q_PROPERTY(bool isReplying READ isReplying NOTIFY relationIdChanged)
/**
* @brief The Matrix message ID of an event being replied to, if any.
*
* Will return empty if the RelationType is currently set to None or Edit.
*
* @note Replying, editing and attachments are exclusive so setting this will
* clear an edit or attachment.
*
* @sa RelationType
*/
Q_PROPERTY(QString replyId READ replyId WRITE setReplyId NOTIFY relationIdChanged)
/**
* @brief Whether the chat bar is currently editing a message.
*/
Q_PROPERTY(bool isEditing READ isEditing NOTIFY relationIdChanged)
/**
* @brief The Matrix message ID of an event being edited, if any.
*
* Will return empty if the RelationType is currently set to None or Reply.
*
* @note Replying, editing and attachments are exclusive so setting this will
* clear an reply or attachment.
*
* @sa RelationType
*/
Q_PROPERTY(QString editId READ editId WRITE setEditId NOTIFY relationIdChanged)
/**
* @brief Get the user for the message being replied to.
*
* This is different to getting a Quotient::User object
* as neither of those can provide details like the displayName or avatarMediaId
* without the room context as these can vary from room to room.
*
* Returns an empty user if not replying to a message.
*
* The user QVariantMap has the following properties:
* - isLocalUser - Whether the user is the local user.
* - id - The matrix ID of the user.
* - displayName - Display name in the context of this room.
* - avatarSource - The mxc URL for the user's avatar in the current room.
* - avatarMediaId - Avatar id in the context of this room.
* - color - Color for the user.
* - object - The Quotient::User object for the user.
*
* @sa getUser, Quotient::User
*/
Q_PROPERTY(QVariantMap relationUser READ relationUser NOTIFY relationIdChanged)
/**
* @brief The content of the related message.
*
* Will be QString() if no related message.
*/
Q_PROPERTY(QString relationMessage READ relationMessage NOTIFY relationIdChanged)
/**
* @brief Whether the chat bar is replying in a thread.
*/
Q_PROPERTY(bool isThreaded READ isThreaded NOTIFY threadIdChanged)
/**
* @brief The Matrix message ID of thread root event, if any.
*/
Q_PROPERTY(QString threadId READ threadId WRITE setThreadId NOTIFY threadIdChanged)
/**
* @brief The local path for a file to send, if any.
*
* @note Replying, editing and attachments are exclusive so setting this will
* clear an edit or reply.
*/
Q_PROPERTY(QString attachmentPath READ attachmentPath WRITE setAttachmentPath NOTIFY attachmentPathChanged)
public:
/**
* @brief Describes the type of relation which relationId can refer to.
*
* A chat bar can only be relating to a single message at a time making these
* exclusive.
*/
enum RelationType {
Reply, /**< The current relation is a message being replied to. */
Edit, /**< The current relation is a message being edited. */
None, /**< There is currently no relation event */
};
Q_ENUM(RelationType)
explicit ChatBarCache(QObject *parent = nullptr);
QString text() const;
void setText(const QString &text);
bool isReplying() const;
QString replyId() const;
void setReplyId(const QString &replyId);
bool isEditing() const;
QString editId() const;
void setEditId(const QString &editId);
QVariantMap relationUser() const;
QString relationMessage() const;
bool isThreaded() const;
QString threadId() const;
void setThreadId(const QString &threadId);
QString attachmentPath() const;
void setAttachmentPath(const QString &attachmentPath);
/**
* @brief Retrieve the mentions for the current chat bar text.
*/
QList<Mention> *mentions();
/**
* @brief Get the saved chat bar text.
*/
QString savedText() const;
/**
* @brief Save the chat bar text.
*/
void setSavedText(const QString &savedText);
Q_SIGNALS:
void textChanged();
void relationIdChanged();
void threadIdChanged();
void attachmentPathChanged();
private:
QString m_text = QString();
QString m_relationId = QString();
RelationType m_relationType = RelationType::None;
QString m_threadId = QString();
QString m_attachmentPath = QString();
QList<Mention> m_mentions;
QString m_savedText;
};

View File

@@ -14,8 +14,6 @@
#include <Sonnet/BackgroundChecker> #include <Sonnet/BackgroundChecker>
#include <Sonnet/Settings> #include <Sonnet/Settings>
#include "chatdocumenthandler_logging.h"
class SyntaxHighlighter : public QSyntaxHighlighter class SyntaxHighlighter : public QSyntaxHighlighter
{ {
public: public:
@@ -59,12 +57,11 @@ public:
setFormat(error.first, error.second.size(), errorFormat); setFormat(error.first, error.second.size(), errorFormat);
} }
} }
auto handler = dynamic_cast<ChatDocumentHandler *>(parent()); auto room = dynamic_cast<ChatDocumentHandler *>(parent())->room();
auto room = handler->room();
if (!room) { if (!room) {
return; return;
} }
auto mentions = handler->chatBarCache()->mentions(); auto mentions = room->mentions();
mentions->erase(std::remove_if(mentions->begin(), mentions->erase(std::remove_if(mentions->begin(),
mentions->end(), mentions->end(),
[this](auto &mention) { [this](auto &mention) {
@@ -100,16 +97,21 @@ ChatDocumentHandler::ChatDocumentHandler(QObject *parent)
, m_document(nullptr) , m_document(nullptr)
, m_cursorPosition(-1) , m_cursorPosition(-1)
, m_highlighter(new SyntaxHighlighter(this)) , m_highlighter(new SyntaxHighlighter(this))
, m_completionModel(new CompletionModel(this)) , m_completionModel(new CompletionModel())
{ {
connect(this, &ChatDocumentHandler::roomChanged, this, [this]() { connect(this, &ChatDocumentHandler::roomChanged, this, [this]() {
m_completionModel->setRoom(m_room); m_completionModel->setRoom(m_room);
static QPointer<NeoChatRoom> previousRoom = nullptr; static QPointer<NeoChatRoom> previousRoom = nullptr;
if (previousRoom) { if (previousRoom) {
disconnect(m_chatBarCache, &ChatBarCache::textChanged, this, nullptr); disconnect(previousRoom, &NeoChatRoom::chatBoxTextChanged, this, nullptr);
disconnect(previousRoom, &NeoChatRoom::editTextChanged, this, nullptr);
} }
previousRoom = m_room; previousRoom = m_room;
connect(m_chatBarCache, &ChatBarCache::textChanged, this, [this]() { connect(m_room, &NeoChatRoom::chatBoxTextChanged, this, [this]() {
int start = completionStartIndex();
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
});
connect(m_room, &NeoChatRoom::editTextChanged, this, [this]() {
int start = completionStartIndex(); int start = completionStartIndex();
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start)); m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
}); });
@@ -132,7 +134,11 @@ int ChatDocumentHandler::completionStartIndex() const
return 0; return 0;
} }
const qsizetype cursor = cursorPosition(); #if !defined(Q_OS_ANDROID)
const long long cursor = cursorPosition();
#else
const auto cursor = cursorPosition();
#endif
const auto &text = getText(); const auto &text = getText();
auto start = std::min(cursor, text.size()) - 1; auto start = std::min(cursor, text.size()) - 1;
@@ -146,6 +152,20 @@ int ChatDocumentHandler::completionStartIndex() const
return start; return start;
} }
bool ChatDocumentHandler::isEdit() const
{
return m_isEdit;
}
void ChatDocumentHandler::setIsEdit(bool edit)
{
if (edit == m_isEdit) {
return;
}
m_isEdit = edit;
Q_EMIT isEditChanged();
}
QQuickTextDocument *ChatDocumentHandler::document() const QQuickTextDocument *ChatDocumentHandler::document() const
{ {
return m_document; return m_document;
@@ -195,31 +215,8 @@ void ChatDocumentHandler::setRoom(NeoChatRoom *room)
Q_EMIT roomChanged(); Q_EMIT roomChanged();
} }
ChatBarCache *ChatDocumentHandler::chatBarCache() const
{
return m_chatBarCache;
}
void ChatDocumentHandler::setChatBarCache(ChatBarCache *chatBarCache)
{
if (m_chatBarCache == chatBarCache) {
return;
}
m_chatBarCache = chatBarCache;
Q_EMIT chatBarCacheChanged();
}
void ChatDocumentHandler::complete(int index) void ChatDocumentHandler::complete(int index)
{ {
if (m_document == nullptr) {
qCWarning(ChatDocumentHandling) << "complete called with m_document set to nullptr.";
return;
}
if (m_completionModel->autoCompletionType() == CompletionModel::None) {
qCWarning(ChatDocumentHandling) << "complete called with m_completionModel->autoCompletionType() == CompletionModel::None.";
return;
}
if (m_completionModel->autoCompletionType() == CompletionModel::User) { if (m_completionModel->autoCompletionType() == CompletionModel::User) {
auto name = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::DisplayNameRole).toString(); auto name = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::DisplayNameRole).toString();
auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::SubtitleRole).toString(); auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::SubtitleRole).toString();
@@ -303,20 +300,26 @@ void ChatDocumentHandler::setSelectionEnd(int position)
QString ChatDocumentHandler::getText() const QString ChatDocumentHandler::getText() const
{ {
if (!m_chatBarCache) { if (!m_room) {
qCWarning(ChatDocumentHandling) << "getText called with m_chatBarCache set to nullptr."; return QString();
return {}; }
if (m_isEdit) {
return m_room->editText();
} else {
return m_room->chatBoxText();
} }
return m_chatBarCache->text();
} }
void ChatDocumentHandler::pushMention(const Mention mention) const void ChatDocumentHandler::pushMention(const Mention mention) const
{ {
if (!m_chatBarCache) { if (!m_room) {
qCWarning(ChatDocumentHandling) << "pushMention called with m_chatBarCache set to nullptr.";
return; return;
} }
m_chatBarCache->mentions()->push_back(mention); if (m_isEdit) {
m_room->editMentions()->push_back(mention);
} else {
m_room->mentions()->push_back(mention);
}
} }
QColor ChatDocumentHandler::mentionColor() const QColor ChatDocumentHandler::mentionColor() const

View File

@@ -8,7 +8,6 @@
#include <QQuickTextDocument> #include <QQuickTextDocument>
#include <QTextCursor> #include <QTextCursor>
#include "chatbarcache.h"
#include "models/completionmodel.h" #include "models/completionmodel.h"
#include "neochatroom.h" #include "neochatroom.h"
@@ -62,6 +61,14 @@ class ChatDocumentHandler : public QObject
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
/**
* @brief Is the instance being used to handle an edit message.
*
* This is needed to ensure that the text and mentions are saved and retrieved
* from the correct parameters in the assigned room.
*/
Q_PROPERTY(bool isEdit READ isEdit WRITE setIsEdit NOTIFY isEditChanged)
/** /**
* @brief The QQuickTextDocument that is being handled. * @brief The QQuickTextDocument that is being handled.
*/ */
@@ -88,18 +95,13 @@ class ChatDocumentHandler : public QObject
* This is typically provided to a qml component to visualise the current * This is typically provided to a qml component to visualise the current
* completion results. * completion results.
*/ */
Q_PROPERTY(CompletionModel *completionModel READ completionModel CONSTANT) Q_PROPERTY(CompletionModel *completionModel READ completionModel NOTIFY completionModelChanged)
/** /**
* @brief The current room that the the text document is being handled for. * @brief The current room that the the text document is being handled for.
*/ */
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged) Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
/**
* @brief The cache for the chat bar the text document is being handled for.
*/
Q_PROPERTY(ChatBarCache *chatBarCache READ chatBarCache WRITE setChatBarCache NOTIFY chatBarCacheChanged)
/** /**
* @brief The color to highlight user mentions. * @brief The color to highlight user mentions.
*/ */
@@ -113,6 +115,9 @@ class ChatDocumentHandler : public QObject
public: public:
explicit ChatDocumentHandler(QObject *parent = nullptr); explicit ChatDocumentHandler(QObject *parent = nullptr);
[[nodiscard]] bool isEdit() const;
void setIsEdit(bool edit);
[[nodiscard]] QQuickTextDocument *document() const; [[nodiscard]] QQuickTextDocument *document() const;
void setDocument(QQuickTextDocument *document); void setDocument(QQuickTextDocument *document);
@@ -128,11 +133,9 @@ public:
[[nodiscard]] NeoChatRoom *room() const; [[nodiscard]] NeoChatRoom *room() const;
void setRoom(NeoChatRoom *room); void setRoom(NeoChatRoom *room);
[[nodiscard]] ChatBarCache *chatBarCache() const;
void setChatBarCache(ChatBarCache *chatBarCache);
Q_INVOKABLE void complete(int index); Q_INVOKABLE void complete(int index);
void updateCompletions();
CompletionModel *completionModel() const; CompletionModel *completionModel() const;
[[nodiscard]] QColor mentionColor() const; [[nodiscard]] QColor mentionColor() const;
@@ -142,10 +145,11 @@ public:
void setErrorColor(const QColor &color); void setErrorColor(const QColor &color);
Q_SIGNALS: Q_SIGNALS:
void isEditChanged();
void documentChanged(); void documentChanged();
void cursorPositionChanged(); void cursorPositionChanged();
void roomChanged(); void roomChanged();
void chatBarCacheChanged(); void completionModelChanged();
void selectionStartChanged(); void selectionStartChanged();
void selectionEndChanged(); void selectionEndChanged();
void errorColorChanged(); void errorColorChanged();
@@ -154,10 +158,12 @@ Q_SIGNALS:
private: private:
int completionStartIndex() const; int completionStartIndex() const;
bool m_isEdit = false;
QPointer<QQuickTextDocument> m_document; QPointer<QQuickTextDocument> m_document;
QPointer<NeoChatRoom> m_room; QPointer<NeoChatRoom> m_room;
QPointer<ChatBarCache> m_chatBarCache; bool completionVisible = false;
QColor m_mentionColor; QColor m_mentionColor;
QColor m_errorColor; QColor m_errorColor;
@@ -171,5 +177,7 @@ private:
SyntaxHighlighter *m_highlighter = nullptr; SyntaxHighlighter *m_highlighter = nullptr;
CompletionModel::AutoCompletionType m_completionType = CompletionModel::None;
CompletionModel *m_completionModel = nullptr; CompletionModel *m_completionModel = nullptr;
}; };

View File

@@ -6,8 +6,13 @@
#include <qt6keychain/keychain.h> #include <qt6keychain/keychain.h>
#include <KConfig>
#include <KConfigGroup>
#include <KLocalizedString> #include <KLocalizedString>
#include <KWindowConfig> #include <KWindowConfig>
#ifdef HAVE_WINDOWSYSTEM
#include <KWindowEffects>
#endif
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
@@ -42,8 +47,6 @@
#include "trayicon_sni.h" #include "trayicon_sni.h"
#endif #endif
bool testMode = false;
using namespace Quotient; using namespace Quotient;
Controller::Controller(QObject *parent) Controller::Controller(QObject *parent)
@@ -58,22 +61,11 @@ Controller::Controller(QObject *parent)
connect(NeoChatConfig::self(), &NeoChatConfig::SystemTrayChanged, this, &Controller::setQuitOnLastWindowClosed); connect(NeoChatConfig::self(), &NeoChatConfig::SystemTrayChanged, this, &Controller::setQuitOnLastWindowClosed);
#endif #endif
if (!testMode) { QTimer::singleShot(0, this, [this] {
QTimer::singleShot(0, this, [this] { invokeLogin();
invokeLogin(); });
});
} else {
auto c = new NeoChatConnection(this);
c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("token_1234"));
connect(c, &Connection::connected, this, [c, this]() {
m_accountRegistry.add(c);
c->syncLoop();
Q_EMIT initiated();
});
}
QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [this] { QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit, QGuiApplication::instance(), [] {
delete m_trayIcon;
NeoChatConfig::self()->save(); NeoChatConfig::self()->save();
}); });
@@ -105,30 +97,16 @@ Controller::Controller(QObject *parent)
connect(&m_accountRegistry, &AccountRegistry::accountCountChanged, this, [this]() { connect(&m_accountRegistry, &AccountRegistry::accountCountChanged, this, [this]() {
if (m_accountRegistry.size() > oldAccountCount) { if (m_accountRegistry.size() > oldAccountCount) {
auto connection = dynamic_cast<NeoChatConnection *>(m_accountRegistry.accounts()[m_accountRegistry.size() - 1]); auto connection = dynamic_cast<NeoChatConnection *>(m_accountRegistry.accounts()[m_accountRegistry.size() - 1]);
connect(connection, &NeoChatConnection::syncDone, this, [this, connection]() { connect(connection, &NeoChatConnection::syncDone, this, [connection]() {
NotificationsManager::instance().handleNotifications(connection); NotificationsManager::instance().handleNotifications(connection);
}); });
connectSingleShot(connection, &NeoChatConnection::syncDone, this, [this, connection] {
connection->setupPushNotifications(m_endpoint);
});
} }
oldAccountCount = m_accountRegistry.size(); oldAccountCount = m_accountRegistry.size();
}); });
#ifdef HAVE_KUNIFIEDPUSH QTimer::singleShot(0, this, [this] {
auto connector = new KUnifiedPush::Connector(QStringLiteral("org.kde.neochat")); m_pushRuleModel = new PushRuleModel;
connect(connector, &KUnifiedPush::Connector::endpointChanged, this, [this](const QString &endpoint) {
m_endpoint = endpoint;
for (auto &quotientConnection : m_accountRegistry) {
auto connection = dynamic_cast<NeoChatConnection *>(quotientConnection);
connection->setupPushNotifications(endpoint);
}
}); });
connector->registerClient(i18n("Receiving push notifications"));
m_endpoint = connector->endpoint();
#endif
} }
Controller &Controller::instance() Controller &Controller::instance()
@@ -197,8 +175,6 @@ void Controller::invokeLogin()
QString id = NeoChatConfig::self()->activeConnection(); QString id = NeoChatConfig::self()->activeConnection();
for (const auto &accountId : accounts) { for (const auto &accountId : accounts) {
AccountSettings account{accountId}; AccountSettings account{accountId};
m_accountsLoading += accountId;
Q_EMIT accountsLoadingChanged();
if (id.isEmpty()) { if (id.isEmpty()) {
// handle case where the account config is empty // handle case where the account config is empty
id = accountId; id = accountId;
@@ -218,8 +194,6 @@ void Controller::invokeLogin()
connect(connection, &NeoChatConnection::connected, this, [this, connection, id] { connect(connection, &NeoChatConnection::connected, this, [this, connection, id] {
connection->loadState(); connection->loadState();
addConnection(connection); addConnection(connection);
m_accountsLoading.removeAll(connection->userId());
Q_EMIT accountsLoadingChanged();
if (connection->userId() == id) { if (connection->userId() == id) {
setActiveConnection(connection); setActiveConnection(connection);
connectSingleShot(connection, &NeoChatConnection::syncDone, this, &Controller::initiated); connectSingleShot(connection, &NeoChatConnection::syncDone, this, &Controller::initiated);
@@ -330,6 +304,9 @@ void Controller::setQuitOnLastWindowClosed()
m_trayIcon = nullptr; m_trayIcon = nullptr;
} }
} }
QGuiApplication::setQuitOnLastWindowClosed(!NeoChatConfig::self()->systemTray());
#else
return;
#endif #endif
} }
@@ -353,6 +330,20 @@ void Controller::setActiveConnection(NeoChatConnection *connection)
m_connection = connection; m_connection = connection;
if (connection != nullptr) { if (connection != nullptr) {
NeoChatConfig::self()->setActiveConnection(connection->userId()); NeoChatConfig::self()->setActiveConnection(connection->userId());
connect(connection, &NeoChatConnection::networkError, this, [this]() {
if (!m_isOnline) {
return;
}
m_isOnline = false;
Q_EMIT isOnlineChanged(false);
});
connect(connection, &NeoChatConnection::syncDone, this, [this] {
if (m_isOnline) {
return;
}
m_isOnline = true;
Q_EMIT isOnlineChanged(true);
});
connect(connection, &NeoChatConnection::requestFailed, this, [](BaseJob *job) { connect(connection, &NeoChatConnection::requestFailed, this, [](BaseJob *job) {
if (dynamic_cast<DownloadFileJob *>(job) && job->jsonData()["errcode"_ls].toString() == "M_TOO_LARGE"_ls) { if (dynamic_cast<DownloadFileJob *>(job) && job->jsonData()["errcode"_ls].toString() == "M_TOO_LARGE"_ls) {
RoomManager::instance().warning(i18n("File too large to download."), i18n("Contact your matrix server administrator for support.")); RoomManager::instance().warning(i18n("File too large to download."), i18n("Contact your matrix server administrator for support."));
@@ -363,6 +354,12 @@ void Controller::setActiveConnection(NeoChatConnection *connection)
} }
NeoChatConfig::self()->save(); NeoChatConfig::self()->save();
Q_EMIT activeConnectionChanged(); Q_EMIT activeConnectionChanged();
Q_EMIT activeConnectionIndexChanged();
}
PushRuleModel *Controller::pushRuleModel() const
{
return m_pushRuleModel;
} }
void Controller::saveWindowGeometry() void Controller::saveWindowGeometry()
@@ -370,25 +367,79 @@ void Controller::saveWindowGeometry()
WindowController::instance().saveGeometry(); WindowController::instance().saveGeometry();
} }
bool Controller::isOnline() const
{
return m_isOnline;
}
// TODO: Remove in favor of RoomManager::joinRoom
void Controller::joinRoom(const QString &alias)
{
if (!alias.contains(":"_ls)) {
Q_EMIT errorOccured(i18n("The room id you are trying to join is not valid"));
return;
}
const auto knownServer = alias.mid(alias.indexOf(":"_ls) + 1);
RoomManager::instance().joinRoom(m_connection, alias, QStringList{knownServer});
}
void Controller::openOrCreateDirectChat(User *user)
{
const auto existing = activeConnection()->directChats();
if (existing.contains(user)) {
const auto &room = static_cast<NeoChatRoom *>(activeConnection()->room(existing.value(user)));
if (room) {
RoomManager::instance().enterRoom(room);
return;
}
}
activeConnection()->requestDirectChat(user);
}
QString Controller::formatByteSize(double size, int precision) const
{
return QLocale().formattedDataSize(size, precision);
}
QString Controller::formatDuration(quint64 msecs, KFormat::DurationFormatOptions options) const
{
return KFormat().formatDuration(msecs, options);
}
void Controller::setBlur(QQuickItem *item, bool blur)
{
#ifdef HAVE_WINDOWSYSTEM
auto setWindows = [item, blur]() {
auto reg = QRect(QPoint(0, 0), item->window()->size());
KWindowEffects::enableBackgroundContrast(item->window(), blur, 1, 1, 1, reg);
KWindowEffects::enableBlurBehind(item->window(), blur, reg);
};
disconnect(item->window(), &QQuickWindow::heightChanged, this, nullptr);
disconnect(item->window(), &QQuickWindow::widthChanged, this, nullptr);
connect(item->window(), &QQuickWindow::heightChanged, this, setWindows);
connect(item->window(), &QQuickWindow::widthChanged, this, setWindows);
setWindows();
#endif
}
bool Controller::hasWindowSystem() const
{
#ifdef HAVE_WINDOWSYSTEM
return true;
#else
return false;
#endif
}
void Controller::forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item) void Controller::forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item)
{ {
// HACK: Workaround bug QTBUG 93281 // HACK: Workaround bug QTBUG 93281
connect(textDocument->textDocument(), SIGNAL(imagesLoaded()), item, SLOT(updateWholeDocument())); connect(textDocument->textDocument(), SIGNAL(imagesLoaded()), item, SLOT(updateWholeDocument()));
} }
void Controller::listenForNotifications()
{
#ifdef HAVE_KUNIFIEDPUSH
auto connector = new KUnifiedPush::Connector(QStringLiteral("org.kde.neochat"));
connect(connector, &KUnifiedPush::Connector::messageReceived, [](const QByteArray &data) {
NotificationsManager::instance().postPushNotification(data);
});
connector->registerClient(i18n("Receiving push notifications"));
#endif
}
void Controller::setApplicationProxy() void Controller::setApplicationProxy()
{ {
NeoChatConfig *cfg = NeoChatConfig::self(); NeoChatConfig *cfg = NeoChatConfig::self();
@@ -419,6 +470,14 @@ void Controller::setApplicationProxy()
QNetworkProxy::setApplicationProxy(proxy); QNetworkProxy::setApplicationProxy(proxy);
} }
int Controller::activeConnectionIndex() const
{
auto result = std::find_if(m_accountRegistry.accounts().begin(), m_accountRegistry.accounts().end(), [this](const auto &it) {
return it == m_connection;
});
return result - m_accountRegistry.accounts().begin();
}
bool Controller::isFlatpak() const bool Controller::isFlatpak() const
{ {
#ifdef NEOCHAT_FLATPAK #ifdef NEOCHAT_FLATPAK
@@ -434,8 +493,3 @@ AccountRegistry &Controller::accounts()
} }
#include "moc_controller.cpp" #include "moc_controller.cpp"
void Controller::setTestMode(bool test)
{
testMode = test;
}

View File

@@ -3,19 +3,18 @@
#pragma once #pragma once
#include "models/pushrulemodel.h"
#include <QObject> #include <QObject>
#include <QQmlEngine> #include <QQmlEngine>
#include <QQuickItem> #include <QQuickItem>
#include <KFormat>
#include "neochatconnection.h" #include "neochatconnection.h"
#include <Quotient/accountregistry.h> #include <Quotient/accountregistry.h>
#include <Quotient/jobs/basejob.h> #include <Quotient/jobs/basejob.h>
#include <Quotient/settings.h> #include <Quotient/settings.h>
#ifdef HAVE_KUNIFIEDPUSH
#include <kunifiedpush/connector.h>
#endif
class NeoChatRoom; class NeoChatRoom;
class TrayIcon; class TrayIcon;
class QQuickTextDocument; class QQuickTextDocument;
@@ -50,11 +49,31 @@ class Controller : public QObject
*/ */
Q_PROPERTY(NeoChatConnection *activeConnection READ activeConnection WRITE setActiveConnection NOTIFY activeConnectionChanged) Q_PROPERTY(NeoChatConnection *activeConnection READ activeConnection WRITE setActiveConnection NOTIFY activeConnectionChanged)
/**
* @brief The PushRuleModel that has the active connection's push rules.
*/
Q_PROPERTY(PushRuleModel *pushRuleModel READ pushRuleModel CONSTANT)
/**
* @brief The row number in the accounts directory of the active connection.
*/
Q_PROPERTY(int activeConnectionIndex READ activeConnectionIndex NOTIFY activeConnectionIndexChanged)
/** /**
* @brief Whether the OS NeoChat is running on supports sytem tray icons. * @brief Whether the OS NeoChat is running on supports sytem tray icons.
*/ */
Q_PROPERTY(bool supportSystemTray READ supportSystemTray CONSTANT) Q_PROPERTY(bool supportSystemTray READ supportSystemTray CONSTANT)
/**
* @brief Whether KWindowSystem specific features are available.
*/
Q_PROPERTY(bool hasWindowSystem READ hasWindowSystem CONSTANT)
/**
* @brief Whether NeoChat is currently able to connect to the server.
*/
Q_PROPERTY(bool isOnline READ isOnline NOTIFY isOnlineChanged)
/** /**
* @brief Whether NeoChat is running as a flatpak. * @brief Whether NeoChat is running as a flatpak.
* *
@@ -62,8 +81,6 @@ class Controller : public QObject
*/ */
Q_PROPERTY(bool isFlatpak READ isFlatpak CONSTANT) Q_PROPERTY(bool isFlatpak READ isFlatpak CONSTANT)
Q_PROPERTY(QStringList accountsLoading MEMBER m_accountsLoading NOTIFY accountsLoadingChanged)
public: public:
/** /**
* @brief Defines the status after an attempt to change the password on an account. * @brief Defines the status after an attempt to change the password on an account.
@@ -76,15 +93,16 @@ public:
Q_ENUM(PasswordStatus) Q_ENUM(PasswordStatus)
static Controller &instance(); static Controller &instance();
static Controller *create(QQmlEngine *engine, QJSEngine *) static Controller *create(QQmlEngine *, QJSEngine *)
{ {
engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership);
return &instance(); return &instance();
} }
void setActiveConnection(NeoChatConnection *connection); void setActiveConnection(NeoChatConnection *connection);
[[nodiscard]] NeoChatConnection *activeConnection() const; [[nodiscard]] NeoChatConnection *activeConnection() const;
[[nodiscard]] PushRuleModel *pushRuleModel() const;
/** /**
* @brief Add a new connection to the account registry. * @brief Add a new connection to the account registry.
*/ */
@@ -95,13 +113,34 @@ public:
*/ */
void dropConnection(NeoChatConnection *c); void dropConnection(NeoChatConnection *c);
int activeConnectionIndex() const;
/** /**
* @brief Save an access token to the keychain for the given account. * @brief Save an access token to the keychain for the given account.
*/ */
bool saveAccessTokenToKeyChain(const Quotient::AccountSettings &account, const QByteArray &accessToken); bool saveAccessTokenToKeyChain(const Quotient::AccountSettings &account, const QByteArray &accessToken);
/**
* @brief Join a room.
*/
Q_INVOKABLE void joinRoom(const QString &alias);
/**
* @brief Join a direct chat with the given user.
*
* If a direct chat with the user doesn't exist one is created and then joined.
*/
Q_INVOKABLE void openOrCreateDirectChat(Quotient::User *user);
[[nodiscard]] bool supportSystemTray() const; [[nodiscard]] bool supportSystemTray() const;
/**
* @brief Set the background blur status of the given item.
*/
Q_INVOKABLE void setBlur(QQuickItem *item, bool blur);
bool isOnline() const;
/** /**
* @brief Sets the QNetworkProxy for the application. * @brief Sets the QNetworkProxy for the application.
* *
@@ -111,6 +150,20 @@ public:
bool isFlatpak() const; bool isFlatpak() const;
/**
* @brief Return a string for the input timestamp.
*
* The output format depends on the KFormat::DurationFormatOptions chosen.
*
* @sa KFormat::DurationFormatOptions
*/
Q_INVOKABLE QString formatDuration(quint64 msecs, KFormat::DurationFormatOptions options = KFormat::DefaultDuration) const;
/**
* @brief Return a human readable string for a given input number of bytes.
*/
Q_INVOKABLE QString formatByteSize(double size, int precision = 1) const;
/** /**
* @brief Force a QQuickTextDocument to refresh when images are loaded. * @brief Force a QQuickTextDocument to refresh when images are loaded.
* *
@@ -118,16 +171,8 @@ public:
*/ */
Q_INVOKABLE void forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item); Q_INVOKABLE void forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item);
/**
* @brief Start listening for notifications in dbus-activated mode.
* These notifications will quit the application when closed.
*/
static void listenForNotifications();
Quotient::AccountRegistry &accounts(); Quotient::AccountRegistry &accounts();
static void setTestMode(bool testMode);
private: private:
explicit Controller(QObject *parent = nullptr); explicit Controller(QObject *parent = nullptr);
@@ -138,11 +183,13 @@ private:
void loadSettings(); void loadSettings();
void saveSettings() const; void saveSettings() const;
bool m_isOnline = true;
QMap<Quotient::Room *, int> m_notificationCounts; QMap<Quotient::Room *, int> m_notificationCounts;
bool hasWindowSystem() const;
QPointer<PushRuleModel> m_pushRuleModel;
Quotient::AccountRegistry m_accountRegistry; Quotient::AccountRegistry m_accountRegistry;
QStringList m_accountsLoading;
QString m_endpoint;
private Q_SLOTS: private Q_SLOTS:
void invokeLogin(); void invokeLogin();
@@ -164,7 +211,8 @@ Q_SIGNALS:
void activeConnectionChanged(); void activeConnectionChanged();
void passwordStatus(Controller::PasswordStatus status); void passwordStatus(Controller::PasswordStatus status);
void userConsentRequired(QUrl url); void userConsentRequired(QUrl url);
void accountsLoadingChanged(); void isOnlineChanged(bool isOnline);
void activeConnectionIndexChanged();
public Q_SLOTS: public Q_SLOTS:
void saveWindowGeometry(); void saveWindowGeometry();

1555
src/data/emoji/af.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/am.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/ar.cpp Normal file

File diff suppressed because it is too large Load Diff

193
src/data/emoji/ar_sa.cpp Normal file
View File

@@ -0,0 +1,193 @@
// SPDX-FileCopyrightText: None
// SPDX-License-Identifier: LGPL-2.0-or-later
// This file is auto-generated. All changes will be lost. See tools/README.md
// clang-format off
#include <QString>
#include <QHash>
#include "../../emojimap.h"
class ar_saEmojiMap: public EmojiMap {
public:
QHash<EmojiModel::Category, QVector<Emoji>> langEmojiMap()
{
QHash<EmojiModel::Category, QVector<Emoji>> _emojis;
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F91D\U0000200D\U0001F9D1"), QStringLiteral("أشخاص يمسكون بأيدي بعضهم")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F636\U0000200D\U0001F32B"), QStringLiteral("وجه في الغيوم")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F62E\U0000200D\U0001F4A8"), QStringLiteral("وجه يزفر الهواء")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F635\U0000200D\U0001F4AB"), QStringLiteral("وجه بعينين دائختين")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U00002764\U0000200D\U0001F525"), QStringLiteral("قلب يحترق")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U00002764\U0000200D\U0001FA79"), QStringLiteral("قلب يتعافى")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F441\U0000200D\U0001F5E8"), QStringLiteral("عين في فقاعة كلام")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D4\U0000200D\U00002642"), QStringLiteral("رجل بلحية")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F471\U0000200D\U00002642"), QStringLiteral("رجل أشقر")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D4\U0000200D\U00002640"), QStringLiteral("امرأة بلحية")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F471\U0000200D\U00002640"), QStringLiteral("امرأة شقراء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F64D\U0000200D\U00002642"), QStringLiteral("متجهم")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F64D\U0000200D\U00002640"), QStringLiteral("متجهمة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F64E\U0000200D\U00002642"), QStringLiteral("رجل عابس")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F64E\U0000200D\U00002640"), QStringLiteral("سيدة عابسة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F645\U0000200D\U00002642"), QStringLiteral("غير موافق")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F645\U0000200D\U00002640"), QStringLiteral("غير موافقة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F646\U0000200D\U00002642"), QStringLiteral("موافق")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F646\U0000200D\U00002640"), QStringLiteral("موافقة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F481\U0000200D\U00002642"), QStringLiteral("رجل بيد مائلة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F481\U0000200D\U00002640"), QStringLiteral("سيدة بيد مائلة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F64B\U0000200D\U00002642"), QStringLiteral("رجل يرفع يده")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F64B\U0000200D\U00002640"), QStringLiteral("سيدة ترفع يدها")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9CF\U0000200D\U00002642"), QStringLiteral("رجل أصم")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9CF\U0000200D\U00002640"), QStringLiteral("سيدة صماء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F647\U0000200D\U00002642"), QStringLiteral("رجل ينحني اعتذارًا")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F647\U0000200D\U00002640"), QStringLiteral("سيدة تنحني اعتذارًا")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F926\U0000200D\U00002642"), QStringLiteral("رجل يشعر بإحباط")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F926\U0000200D\U00002640"), QStringLiteral("سيدة تشعر بإحباط")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F937\U0000200D\U00002642"), QStringLiteral("رجل لا يبالي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F937\U0000200D\U00002640"), QStringLiteral("سيدة لا تبالي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U00002695"), QStringLiteral("موظف بقطاع الصحة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U00002695"), QStringLiteral("عامل بقطاع الصحة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U00002695"), QStringLiteral("عاملة بقطاع الصحة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F393"), QStringLiteral("طالِب")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F393"), QStringLiteral("طالب")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F393"), QStringLiteral("طالبة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F3EB"), QStringLiteral("أستاذ")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F3EB"), QStringLiteral("معلم")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F3EB"), QStringLiteral("معلمة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U00002696"), QStringLiteral("قاضي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U00002696"), QStringLiteral("قاضٍ")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U00002696"), QStringLiteral("قاضية")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F33E"), QStringLiteral("مُزارع")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F33E"), QStringLiteral("مزارع")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F33E"), QStringLiteral("مزارعة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F373"), QStringLiteral("طاهي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F373"), QStringLiteral("طباخ")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F373"), QStringLiteral("طباخة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F527"), QStringLiteral("خبير ميكانيكي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F527"), QStringLiteral("ميكانيكي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F527"), QStringLiteral("ميكانيكية")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F3ED"), QStringLiteral("عامل في مصنع")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F3ED"), QStringLiteral("عامل مصنع")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F3ED"), QStringLiteral("عاملة مصنع")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F4BC"), QStringLiteral("موظف مكتب")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F4BC"), QStringLiteral("موظف")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F4BC"), QStringLiteral("موظفة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F52C"), QStringLiteral("عالِم")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F52C"), QStringLiteral("عالم")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F52C"), QStringLiteral("عالِمة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F4BB"), QStringLiteral("خبير تكنولوجيا")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F4BB"), QStringLiteral("عالم تكنولوجيا")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F4BB"), QStringLiteral("عالِمة تكنولوجيا")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F3A4"), QStringLiteral("مغنّي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F3A4"), QStringLiteral("مطرب")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F3A4"), QStringLiteral("مطربة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F3A8"), QStringLiteral("فنان رسم")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F3A8"), QStringLiteral("رسام")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F3A8"), QStringLiteral("رسامة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U00002708"), QStringLiteral("ربان طائرة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U00002708"), QStringLiteral("طيار")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U00002708"), QStringLiteral("ربّانة طائرة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F680"), QStringLiteral("رائد الفضاء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F680"), QStringLiteral("رائد فضاء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F680"), QStringLiteral("رائدة فضاء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F692"), QStringLiteral("إطفائي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F692"), QStringLiteral("رجل إطفاء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F692"), QStringLiteral("سيدة إطفاء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F46E\U0000200D\U00002642"), QStringLiteral("شرطي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F46E\U0000200D\U00002640"), QStringLiteral("شرطية")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F575\U0000200D\U00002642"), QStringLiteral("محقّق")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F575\U0000200D\U00002640"), QStringLiteral("محقّقة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F482\U0000200D\U00002642"), QStringLiteral("رجل حراسة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F482\U0000200D\U00002640"), QStringLiteral("حارسة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F477\U0000200D\U00002642"), QStringLiteral("عامل بناء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F477\U0000200D\U00002640"), QStringLiteral("عاملة بناء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F473\U0000200D\U00002642"), QStringLiteral("رجل يرتدي عمامة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F473\U0000200D\U00002640"), QStringLiteral("سيدة ترتدي عمامة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F935\U0000200D\U00002642"), QStringLiteral("رجل يرتدي بدلة رسمية")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F935\U0000200D\U00002640"), QStringLiteral("امرأة ببدلة رسمية")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F470\U0000200D\U00002642"), QStringLiteral("رجل بطرحة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F470\U0000200D\U00002640"), QStringLiteral("امرأة بطرحة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F37C"), QStringLiteral("امرأة تُرضع طفلاً")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F37C"), QStringLiteral("رجل يُرضع طفلاً")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F37C"), QStringLiteral("شخص يُرضع طفلاً")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F384"), QStringLiteral("كلوز")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9B8\U0000200D\U00002642"), QStringLiteral("بطل خارق رجل")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9B8\U0000200D\U00002640"), QStringLiteral("بطلة خارقة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9B9\U0000200D\U00002642"), QStringLiteral("شرير خارق رجل")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9B9\U0000200D\U00002640"), QStringLiteral("شريرة خارقة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D9\U0000200D\U00002642"), QStringLiteral("ساحر")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D9\U0000200D\U00002640"), QStringLiteral("ساحرة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DA\U0000200D\U00002642"), QStringLiteral("جنّي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DA\U0000200D\U00002640"), QStringLiteral("جنّية")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DB\U0000200D\U00002642"), QStringLiteral("مصاص دماء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DB\U0000200D\U00002640"), QStringLiteral("مصّاصة دماء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DC\U0000200D\U00002642"), QStringLiteral("مخلوق له جسد رجل وذيل سمكة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DC\U0000200D\U00002640"), QStringLiteral("حورية بحر")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DD\U0000200D\U00002642"), QStringLiteral("جنّي صغير ذكر")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DD\U0000200D\U00002640"), QStringLiteral("جنيّة صغيرة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DE\U0000200D\U00002642"), QStringLiteral("مارد")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DE\U0000200D\U00002640"), QStringLiteral("ماردة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DF\U0000200D\U00002642"), QStringLiteral("رجل زومبي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DF\U0000200D\U00002640"), QStringLiteral("امرأة زومبي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F486\U0000200D\U00002642"), QStringLiteral("تدليك لرجل")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F486\U0000200D\U00002640"), QStringLiteral("تدليك لسيدة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F487\U0000200D\U00002642"), QStringLiteral("يقص شعره")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F487\U0000200D\U00002640"), QStringLiteral("تقص شعرها")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6B6\U0000200D\U00002642"), QStringLiteral("سائر")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6B6\U0000200D\U00002640"), QStringLiteral("سائرة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9CD\U0000200D\U00002642"), QStringLiteral("رجل واقف")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9CD\U0000200D\U00002640"), QStringLiteral("سيدة واقفة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9CE\U0000200D\U00002642"), QStringLiteral("رجل جالس على ركبتيه")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9CE\U0000200D\U00002640"), QStringLiteral("سيدة جالسة على ركبتيها")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F9AF"), QStringLiteral("شخص مع عصا سير")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F9AF"), QStringLiteral("رجل بعصا سير")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F9AF"), QStringLiteral("سيدة بعصا سير")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F9BC"), QStringLiteral("شخص على كرسي متحرك كهربائي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F9BC"), QStringLiteral("رجل على كرسي متحرك كهربائي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F9BC"), QStringLiteral("سيدة على كرسي متحرك كهربائي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F9BD"), QStringLiteral("شخص على كرسي متحرك يدوي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F9BD"), QStringLiteral("رجل على كرسي متحرك يدوي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F9BD"), QStringLiteral("سيدة على كرسي متحرك يدوي")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3C3\U0000200D\U00002642"), QStringLiteral("راكض")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3C3\U0000200D\U00002640"), QStringLiteral("راكضة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F46F\U0000200D\U00002642"), QStringLiteral("رجلان يرقصان")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F46F\U0000200D\U00002640"), QStringLiteral("امرأتان ترقصان")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D6\U0000200D\U00002642"), QStringLiteral("رجل في حمّام بخار")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D6\U0000200D\U00002640"), QStringLiteral("امرأة في حمّام بخار")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D7\U0000200D\U00002642"), QStringLiteral("رجل يتسلّق")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D7\U0000200D\U00002640"), QStringLiteral("امرأة تتسلّق")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3CC\U0000200D\U00002642"), QStringLiteral("لاعب غولف")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3CC\U0000200D\U00002640"), QStringLiteral("لاعبة غولف")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3C4\U0000200D\U00002642"), QStringLiteral("راكب أمواج")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3C4\U0000200D\U00002640"), QStringLiteral("راكبة أمواج")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6A3\U0000200D\U00002642"), QStringLiteral("رجل يجدف بقارب")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6A3\U0000200D\U00002640"), QStringLiteral("سيدة تجدف بقارب")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3CA\U0000200D\U00002642"), QStringLiteral("سباح")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3CA\U0000200D\U00002640"), QStringLiteral("سبَّاحة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U000026F9\U0000200D\U00002642"), QStringLiteral("رجل وكرة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U000026F9\U0000200D\U00002640"), QStringLiteral("سيدة وكرة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3CB\U0000200D\U00002642"), QStringLiteral("رافع أثقال")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F3CB\U0000200D\U00002640"), QStringLiteral("رافعة أثقال")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6B4\U0000200D\U00002642"), QStringLiteral("راكب دراجة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6B4\U0000200D\U00002640"), QStringLiteral("راكبة دراجة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6B5\U0000200D\U00002642"), QStringLiteral("متسلق جبال بدراجة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6B5\U0000200D\U00002640"), QStringLiteral("متسلقة جبال بدراجة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F938\U0000200D\U00002642"), QStringLiteral("رجل يفعل حركة العجلة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F938\U0000200D\U00002640"), QStringLiteral("سيدة تفعل حركة العجلة")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F93C\U0000200D\U00002642"), QStringLiteral("مصارعة رجال")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F93C\U0000200D\U00002640"), QStringLiteral("مصارعة سيدات")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F93D\U0000200D\U00002642"), QStringLiteral("لاعب كرة ماء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F93D\U0000200D\U00002640"), QStringLiteral("لاعبة كرة ماء")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F93E\U0000200D\U00002642"), QStringLiteral("لاعب كرة يد")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F93E\U0000200D\U00002640"), QStringLiteral("لاعبة كرة يد")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F939\U0000200D\U00002642"), QStringLiteral("لاعب قذف الكرات")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F939\U0000200D\U00002640"), QStringLiteral("لاعبة قذف كرات")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D8\U0000200D\U00002642"), QStringLiteral("رجل متربّع")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D8\U0000200D\U00002640"), QStringLiteral("امرأة متربّعة")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F415\U0000200D\U0001F9BA"), QStringLiteral("كلب مساعدة")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F408\U0000200D\U00002B1B"), QStringLiteral("هرّ أسود")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F43B\U0000200D\U00002744"), QStringLiteral("دب قطبي")});
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F3F3\U0000200D\U0001F308"), QStringLiteral("علم ألوان طيف")});
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F3F3\U0000200D\U000026A7"), QStringLiteral("علم المتحولين جنسيًا")});
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F3F4\U0000200D\U00002620"), QStringLiteral("علم قراصنة")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F377"), QStringLiteral("كأس عصير")});
};

1555
src/data/emoji/as.cpp Normal file

File diff suppressed because it is too large Load Diff

28
src/data/emoji/ast.cpp Normal file
View File

@@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: None
// SPDX-License-Identifier: LGPL-2.0-or-later
// This file is auto-generated. All changes will be lost. See tools/README.md
// clang-format off
#include <QString>
#include <QHash>
#include "../../emojimap.h"
class astEmojiMap: public EmojiMap {
public:
QHash<EmojiModel::Category, QVector<Emoji>> langEmojiMap()
{
QHash<EmojiModel::Category, QVector<Emoji>> _emojis;
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F923"), QStringLiteral("rodando pel suelu de risa")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F602"), QStringLiteral("cara llorando dallegría")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F618"), QStringLiteral("cara tirando un besu")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F617"), QStringLiteral("cara besando")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0000263A"), QStringLiteral("cara sorriendo")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F933"), QStringLiteral("selfie")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F445"), QStringLiteral("llingua")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F444"), QStringLiteral("boca")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F48F"), QStringLiteral("besu")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F46A"), QStringLiteral("familia")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F48D"), QStringLiteral("aniellu")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F48E"), QStringLiteral("piedra preciosa")});
};

1555
src/data/emoji/az.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/be.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/bg.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/bn.cpp Normal file

File diff suppressed because it is too large Load Diff

1029
src/data/emoji/br.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/bs.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/ca.cpp Normal file

File diff suppressed because it is too large Load Diff

247
src/data/emoji/ccp.cpp Normal file
View File

@@ -0,0 +1,247 @@
// SPDX-FileCopyrightText: None
// SPDX-License-Identifier: LGPL-2.0-or-later
// This file is auto-generated. All changes will be lost. See tools/README.md
// clang-format off
#include <QString>
#include <QHash>
#include "../../emojimap.h"
class ccpEmojiMap: public EmojiMap {
public:
QHash<EmojiModel::Category, QVector<Emoji>> langEmojiMap()
{
QHash<EmojiModel::Category, QVector<Emoji>> _emojis;
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F393"), QStringLiteral("𑄟𑄧𑄢𑄧𑄘𑄴 𑄍𑄖𑄳𑄢𑄧𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F393"), QStringLiteral("𑄟𑄨𑄣𑄬 𑄍𑄖𑄳𑄢𑄧𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F3EB"), QStringLiteral("𑄟𑄧𑄢𑄧𑄘𑄴 𑄟𑄌𑄴𑄑𑄧𑄢𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F3EB"), QStringLiteral("𑄟𑄨𑄣𑄬 𑄟𑄌𑄴𑄑𑄧𑄢𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F33E"), QStringLiteral("𑄟𑄧𑄢𑄧𑄘𑄴 𑄦𑄣𑄴𑄌𑄪𑄠𑄬")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F33E"), QStringLiteral("𑄦𑄣𑄴𑄣𑄮 𑄟𑄨𑄣𑄬")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F373"), QStringLiteral("𑄟𑄧𑄢𑄧𑄘𑄴 𑄝𑄉𑄮𑄌𑄴𑄨")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F373"), QStringLiteral("𑄟𑄨𑄣𑄬 𑄝𑄉𑄮𑄌𑄴𑄨")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F527"), QStringLiteral("𑄟𑄧𑄢𑄧𑄘𑄴 𑄇𑄣𑄨𑄉𑄧𑄢𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F527"), QStringLiteral("𑄟𑄨𑄣𑄬 𑄇𑄣𑄨𑄉𑄧𑄢𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F3ED"), QStringLiteral("𑄜𑄳𑄠𑄇𑄴𑄑𑄮𑄢𑄨𑄖𑄴 𑄇𑄟𑄴 𑄉𑄧𑄢𑄨𑄠𑄬 𑄟𑄧𑄢𑄧𑄘𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F3ED"), QStringLiteral("𑄜𑄳𑄠𑄇𑄴𑄑𑄮𑄢𑄨𑄖𑄴 𑄇𑄟𑄴 𑄉𑄧𑄢𑄨𑄠𑄬 𑄟𑄨𑄣𑄬")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U0001F52C"), QStringLiteral("𑄟𑄧𑄢𑄧𑄘𑄴 𑄝𑄨𑄉𑄳𑄠𑄴𑄚𑄨")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U0001F52C"), QStringLiteral("𑄟𑄨𑄣𑄬 𑄝𑄨𑄉𑄳𑄠𑄴𑄚𑄨")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468\U0000200D\U00002708"), QStringLiteral("𑄟𑄧𑄢𑄧𑄘𑄴 𑄝𑄨𑄟𑄚𑄴 𑄌𑄣𑄬𑄠𑄳𑄠")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469\U0000200D\U00002708"), QStringLiteral("𑄟𑄨𑄣𑄬 𑄝𑄨𑄟𑄚𑄴 𑄌𑄣𑄬𑄠𑄳𑄠")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F46E\U0000200D\U00002642"), QStringLiteral("𑄟𑄧𑄢𑄧𑄘𑄴 𑄛𑄪𑄣𑄨𑄌𑄴 𑄃𑄧𑄜𑄨𑄥𑄢𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F46E\U0000200D\U00002640"), QStringLiteral("𑄟𑄨𑄣𑄬 𑄛𑄪𑄣𑄨𑄌𑄴 𑄃𑄧𑄜𑄨𑄥𑄢𑄴")});
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F3F3\U0000200D\U0001F308"), QStringLiteral("𑄢𑄚𑄴𑄎𑄪𑄚𑄨 𑄝𑄝𑄧𑄘")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F600"), QStringLiteral("𑄞𑄬𑄁𑄌𑄨 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F603"), QStringLiteral("𑄞𑄧𑄢𑄴 𑄌𑄮𑄉𑄧 𑄉𑄎𑄧𑄌𑄬 𑄞𑄬𑄁𑄌𑄨 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F601"), QStringLiteral("𑄎𑄧𑄣𑄴𑄎𑄧𑄣𑄳𑄣𑄬 𑄟𑄪 𑄣𑄧𑄉𑄬 𑄦𑄎𑄳𑄎𑄬 𑄦𑄎𑄳𑄎𑄬 𑄌𑄮𑄉𑄧")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F923"), QStringLiteral("𑄦𑄎𑄧𑄘𑄬 𑄦𑄎𑄧𑄘𑄬 𑄟𑄘𑄨𑄖𑄴 𑄉𑄪𑄌𑄴𑄎𑄚")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F602"), QStringLiteral("𑄟𑄪 𑄦𑄚𑄴𑄖𑄴 𑄦𑄪𑄎𑄨𑄢𑄴 𑄌𑄮𑄉𑄮 𑄛𑄚𑄨")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F642"), QStringLiteral("𑄃𑄬𑄇𑄳𑄦𑄴 𑄃𑄬𑄇𑄳𑄦𑄴 𑄦𑄏𑄧𑄁 𑄦𑄏𑄧𑄁 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F60D"), QStringLiteral("𑄦𑄏𑄨 𑄟𑄪 𑄣𑄧𑄉𑄬 𑄛𑄧𑄢𑄚𑄴 𑄊𑄧𑄢𑄧 𑄌𑄮𑄇𑄴")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F618"), QStringLiteral("𑄌𑄪𑄟𑄬𑄢𑄴 𑄟𑄪 𑄍𑄪𑄌𑄬𑄋𑄴 𑄉𑄧𑄢𑄨")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F617"), QStringLiteral("𑄌𑄪𑄟𑄮 𑄥𑄪𑄟𑄨 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F61A"), QStringLiteral("𑄌𑄮𑄇𑄴 𑄦𑄖𑄳𑄠𑄬 𑄥𑄪𑄟𑄮 𑄥𑄪𑄟𑄨 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F619"), QStringLiteral("𑄥𑄪𑄟𑄮 𑄥𑄪𑄟𑄨 𑄟𑄪 𑄣𑄧𑄉𑄬 𑄦𑄏𑄨 𑄌𑄮𑄇𑄴")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F61B"), QStringLiteral("𑄎𑄨𑄣𑄴 𑄚𑄨𑄉𑄬𑄣𑄳𑄠𑄬 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F914"), QStringLiteral("𑄥𑄨𑄘𑄳𑄠𑄬𑄉𑄮𑄌𑄳𑄠𑄬 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F62A"), QStringLiteral("𑄊𑄪𑄟𑄴 𑄡𑄬𑄠𑄬 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F60E"), QStringLiteral("𑄦𑄏𑄨 𑄟𑄪 𑄣𑄧𑄉𑄬 𑄌𑄮𑄇𑄴𑄥𑄟𑄘𑄳𑄠𑄬")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F622"), QStringLiteral("𑄇𑄚𑄳𑄠𑄬 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F62D"), QStringLiteral("𑄎𑄮𑄢𑄬 𑄎𑄮𑄢𑄬 𑄇𑄚𑄳𑄠𑄬 𑄟𑄪")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F620"), QStringLiteral("𑄢𑄉𑄴𑄅𑄪𑄖𑄳𑄠𑄬 𑄟𑄪")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F476"), QStringLiteral("𑄇𑄪𑄏𑄨 𑄌𑄨𑄌𑄴𑄨𑄇𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D2"), QStringLiteral("𑄌𑄨𑄉𑄮𑄚𑄴 𑄉𑄪𑄢𑄮")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F466"), QStringLiteral("𑄟𑄧𑄢𑄧𑄘𑄴 𑄛𑄱")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F467"), QStringLiteral("𑄟𑄨𑄣𑄬 𑄛𑄱")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F468"), QStringLiteral("𑄟𑄚𑄪𑄌𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F469"), QStringLiteral("𑄟𑄨𑄣𑄬 𑄟𑄚𑄪𑄌𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D3"), QStringLiteral("𑄝𑄪𑄢𑄮 𑄉𑄝𑄪𑄢𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F474"), QStringLiteral("𑄝𑄪𑄢𑄮 𑄟𑄚𑄪𑄌𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F475"), QStringLiteral("𑄝𑄪𑄢𑄮 𑄟𑄨𑄣𑄬")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F46E"), QStringLiteral("𑄛𑄪𑄣𑄨𑄌𑄴 𑄃𑄧𑄜𑄨𑄥𑄢𑄴")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F934"), QStringLiteral("𑄢𑄎 𑄛𑄱")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F478"), QStringLiteral("𑄎𑄢 𑄏𑄨")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F435"), QStringLiteral("𑄝𑄚𑄴𑄘𑄧𑄢𑄴 𑄟𑄪")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F412"), QStringLiteral("𑄝𑄚𑄴𑄘𑄧𑄢𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F98D"), QStringLiteral("𑄉𑄬𑄢𑄨𑄣")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F436"), QStringLiteral("𑄇𑄪𑄉𑄪𑄢𑄴 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F415"), QStringLiteral("𑄇𑄪𑄉𑄪𑄢𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F429"), QStringLiteral("𑄛𑄪𑄖𑄴𑄣𑄨")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F43A"), QStringLiteral("𑄜𑄬𑄝𑄮 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F98A"), QStringLiteral("𑄥𑄨𑄠𑄬𑄣𑄳𑄠 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F431"), QStringLiteral("𑄝𑄨𑄣𑄬𑄭 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F408"), QStringLiteral("𑄝𑄨𑄣𑄬𑄭")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F981"), QStringLiteral("𑄥𑄨𑄁𑄦𑄧 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F42F"), QStringLiteral("𑄝𑄊𑄧 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F405"), QStringLiteral("𑄝𑄊𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F406"), QStringLiteral("𑄌𑄨𑄘𑄨𑄢𑄬 𑄝𑄇𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F434"), QStringLiteral("𑄊𑄮𑄢 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F40E"), QStringLiteral("𑄊𑄮𑄢")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F993"), QStringLiteral("𑄎𑄬𑄝𑄳𑄢𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F98C"), QStringLiteral("𑄅𑄢𑄨𑄁")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F42E"), QStringLiteral("𑄉𑄧𑄢𑄪 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F402"), QStringLiteral("𑄘𑄟𑄳𑄢𑄴 𑄉𑄧𑄢𑄪")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F403"), QStringLiteral("𑄛𑄚𑄨 𑄦𑄳𑄆𑄬𑄖𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F404"), QStringLiteral("𑄉𑄧𑄢𑄪")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F437"), QStringLiteral("𑄥𑄪𑄉𑄮𑄢𑄴 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F416"), QStringLiteral("𑄥𑄪𑄉𑄮𑄢𑄨")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F417"), QStringLiteral("𑄥𑄪𑄉𑄮𑄢𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F43D"), QStringLiteral("𑄥𑄪𑄉𑄮𑄢𑄴 𑄚𑄇𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F40F"), QStringLiteral("𑄞𑄬𑄢")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F411"), QStringLiteral("𑄞𑄬𑄢𑄨")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F410"), QStringLiteral("𑄍𑄉𑄧𑄣𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F42A"), QStringLiteral("𑄅𑄖𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F992"), QStringLiteral("𑄎𑄨𑄢𑄬𑄛𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F418"), QStringLiteral("𑄦𑄳𑄆𑄬𑄖𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F42D"), QStringLiteral("𑄅𑄚𑄴𑄘𑄪𑄢𑄴 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F401"), QStringLiteral("𑄅𑄚𑄴𑄘𑄪𑄢𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F400"), QStringLiteral("𑄝𑄌𑄴 𑄅𑄚𑄴𑄘𑄪𑄢𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F430"), QStringLiteral("𑄈𑄧𑄢𑄴𑄉𑄧𑄌𑄴 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F407"), QStringLiteral("𑄈𑄧𑄢𑄴𑄉𑄧𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F987"), QStringLiteral("𑄝𑄘𑄮𑄣𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F43B"), QStringLiteral("𑄞𑄣𑄪𑄇𑄴 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F428"), QStringLiteral("𑄇𑄮𑄠𑄣")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F43C"), QStringLiteral("𑄛𑄚𑄴𑄘 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F983"), QStringLiteral("𑄑𑄢𑄴𑄇𑄨 𑄛𑄪𑄢𑄯")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F414"), QStringLiteral("𑄛𑄪𑄢𑄯 𑄌𑄧")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F424"), QStringLiteral("𑄌𑄨𑄉𑄮𑄚𑄴 𑄛𑄪𑄢𑄯 𑄌𑄧")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F425"), QStringLiteral("𑄟𑄪𑄎𑄪𑄁𑄠𑄬 𑄟𑄱 𑄌𑄨𑄉𑄮𑄚𑄴 𑄛𑄪𑄢𑄯 𑄌𑄧")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F426"), QStringLiteral("𑄛𑄳𑄆𑄬𑄇𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F427"), QStringLiteral("𑄛𑄬𑄁𑄉𑄪𑄄𑄚𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F54A"), QStringLiteral("𑄇𑄧")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F985"), QStringLiteral("𑄄𑄉𑄧𑄣𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F986"), QStringLiteral("𑄃𑄏 𑄦𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F989"), QStringLiteral("𑄛𑄬𑄎")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F438"), QStringLiteral("𑄝𑄬𑄋𑄧 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F40A"), QStringLiteral("𑄇𑄪𑄟𑄮𑄢𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F422"), QStringLiteral("𑄘𑄪𑄢𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F98E"), QStringLiteral("𑄑𑄪𑄖𑄴𑄑𑄪𑄝𑄨")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F40D"), QStringLiteral("𑄥𑄛𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F432"), QStringLiteral("𑄓𑄳𑄢𑄉𑄧𑄚𑄴 𑄟𑄱")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F409"), QStringLiteral("𑄓𑄳𑄢𑄉𑄧𑄚𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F40B"), QStringLiteral("𑄖𑄨𑄟𑄨 𑄟𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F42C"), QStringLiteral("𑄓𑄧𑄣𑄴𑄜𑄨𑄚𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F41F"), QStringLiteral("𑄟𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F988"), QStringLiteral("𑄦𑄋𑄮𑄢𑄴 𑄟𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F419"), QStringLiteral("𑄃𑄧𑄇𑄴𑄑𑄮𑄛𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F40C"), QStringLiteral("𑄥𑄟𑄪𑄇𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F98B"), QStringLiteral("𑄛𑄖𑄳𑄦𑄴𑄛𑄧𑄖𑄴𑄨")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F41B"), QStringLiteral("𑄇𑄧𑄢𑄧𑄢𑄴 𑄛𑄪𑄇𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F41D"), QStringLiteral("𑄟𑄪 𑄛𑄪𑄇𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F41E"), QStringLiteral("𑄛𑄪𑄇𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F997"), QStringLiteral("𑄉𑄪𑄟𑄪𑄢𑄯")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F577"), QStringLiteral("𑄟𑄉𑄧𑄢𑄧𑄇𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F578"), QStringLiteral("𑄟𑄉𑄧𑄢𑄧𑄇𑄴 𑄎𑄣𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F982"), QStringLiteral("𑄝𑄨𑄎𑄳𑄠")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F4AE"), QStringLiteral("𑄘𑄪𑄛𑄴 𑄜𑄪𑄣𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F339"), QStringLiteral("𑄉𑄮𑄣𑄛𑄴 𑄜𑄪𑄣𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F331"), QStringLiteral("𑄉𑄎𑄧 𑄍𑄢")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F332"), QStringLiteral("𑄦𑄬𑄣𑄴 𑄉𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F333"), QStringLiteral("𑄎𑄮𑄝𑄪𑄢𑄴 𑄉𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F334"), QStringLiteral("𑄖𑄣𑄴 𑄉𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F335"), QStringLiteral("𑄇𑄳𑄠𑄇𑄴𑄑𑄌𑄴")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F341"), QStringLiteral("𑄟𑄳𑄠𑄛𑄧𑄣𑄴 𑄛𑄘")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F342"), QStringLiteral("𑄛𑄧𑄢𑄬𑄖𑄳𑄠𑄴 𑄛𑄘")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F347"), QStringLiteral("𑄃𑄋𑄴𑄉𑄪𑄢𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F348"), QStringLiteral("𑄖𑄮𑄢𑄴𑄟𑄮𑄌𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F349"), QStringLiteral("𑄛𑄚𑄳𑄠𑄴 𑄖𑄮𑄢𑄴𑄟𑄮𑄌𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F34A"), QStringLiteral("𑄖𑄁𑄉𑄬𑄢𑄭𑄚𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F34B"), QStringLiteral("𑄇𑄉𑄮𑄎𑄨")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F34C"), QStringLiteral("𑄇𑄧𑄣")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F34D"), QStringLiteral("𑄃𑅅𑄚𑄌𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F96D"), QStringLiteral("𑄃𑄟𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F34E"), QStringLiteral("𑄢𑄋 𑄃𑄛𑄬𑄣𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F34F"), QStringLiteral("𑄥𑄮𑄌𑄴 𑄃𑄛𑄬𑄣𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F350"), QStringLiteral("𑄛𑄨𑄠𑄢𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F351"), QStringLiteral("𑄛𑄨𑄌𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F352"), QStringLiteral("𑄌𑄬𑄢𑄨")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F353"), QStringLiteral("𑄆𑄌𑄴𑄖𑄳𑄢𑄧𑄝𑄬𑄢𑄨")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F95D"), QStringLiteral("𑄇𑄪𑄄 𑄜𑄧𑄣𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F345"), QStringLiteral("𑄈𑄧𑄢𑄧 𑄝𑄨𑄉𑄪𑄚𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F965"), QStringLiteral("𑄚𑄢𑄬𑄇𑄪𑄣𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F951"), QStringLiteral("𑄆𑄝𑄇𑄘𑄮")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F346"), QStringLiteral("𑄝𑄢𑄳𑄦𑄧 𑄟𑄌𑄳𑄠𑄴 𑄝𑄨𑄉𑄪𑄚𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F954"), QStringLiteral("𑄃𑄣𑄪")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F955"), QStringLiteral("𑄉𑄎𑄧𑄢𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F33D"), QStringLiteral("𑄟𑄮𑄇𑄳𑄠𑄴 𑄌𑄮𑄉𑄮𑄣")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F336"), QStringLiteral("𑄏𑄣𑄴 𑄟𑄧𑄢𑄨𑄌𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F952"), QStringLiteral("𑄜𑄧𑄣𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F96C"), QStringLiteral("𑄦𑄬𑄣𑄴 𑄛𑄘")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F966"), QStringLiteral("𑄝𑄳𑄢𑄧𑄪𑄇𑄴𑄧𑄣𑄨")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F344"), QStringLiteral("𑄥𑄟𑄴𑄮𑄅𑄣𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F95C"), QStringLiteral("𑄝𑄘𑄟𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F35E"), QStringLiteral("𑄢𑄪𑄖𑄨")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F95E"), QStringLiteral("𑄛𑄬𑄚𑄴𑄇𑄬𑄇𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F356"), QStringLiteral("𑄃𑄢𑄧𑄢𑄧𑄢𑄴 𑄦𑄬𑄢 𑄥𑄌𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F357"), QStringLiteral("𑄜𑄢𑄧𑄟𑄧 𑄛𑄪𑄢𑄯 𑄒𑄳𑄠𑄁")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F969"), QStringLiteral("𑄦𑄬𑄢 𑄘𑄮𑄟")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F953"), QStringLiteral("𑄝𑄇𑄧𑄚𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F35F"), QStringLiteral("𑄜𑄳𑄢𑄬𑄚𑄴𑄌𑄴 𑄞𑄎")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F355"), QStringLiteral("𑄛𑄨𑄎")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F32D"), QStringLiteral("𑄦𑄧𑄖𑄴 𑄓𑄧𑄇𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F32E"), QStringLiteral("𑄑𑄳𑄠𑄇𑄮")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F32F"), QStringLiteral("𑄝𑄪𑄢𑄨𑄖𑄮")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F95A"), QStringLiteral("𑄝𑄮𑄘")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F373"), QStringLiteral("𑄢𑄚𑄚")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F957"), QStringLiteral("𑄇𑄎 𑄣𑄘𑄖𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F359"), QStringLiteral("𑄞𑄖𑄴 𑄉𑄟𑄣")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F35A"), QStringLiteral("𑄢𑄚𑄳𑄠𑄴 𑄞𑄖𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F980"), QStringLiteral("𑄇𑄋𑄢")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F990"), QStringLiteral("𑄄𑄎𑄳𑄠")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F368"), QStringLiteral("𑄃𑄌𑄴𑄇𑄳𑄢𑄨𑄟𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F36F"), QStringLiteral("𑄟𑄧𑄙𑄪 𑄛𑄧𑄖𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F37C"), QStringLiteral("𑄇𑄪𑄏𑄨 𑄌𑄨𑄌𑄴𑄨𑄇𑄴𑄮𑄢𑄴 𑄝𑄧𑄘𑄧𑄣𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F95B"), QStringLiteral("𑄘𑄪𑄙𑄮 𑄉𑄧𑄣𑄧𑄌𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F376"), QStringLiteral("𑄟𑄪𑄉𑄪𑄎𑄮")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F377"), QStringLiteral("𑄟𑄧𑄘𑄧 𑄉𑄧𑄣𑄧𑄌𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F944"), QStringLiteral("𑄌𑄟𑄬𑄌𑄴")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F52A"), QStringLiteral("𑄛𑄇𑄴𑄊𑄧𑄢𑄧𑄢𑄴 𑄌𑄪𑄢𑄨")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F5FA"), QStringLiteral("𑄛𑄨𑄖𑄴𑄨𑄟𑄨 𑄟𑄳𑄠𑄛𑄴")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F5FE"), QStringLiteral("𑄎𑄛𑄚𑄧𑄢𑄴 𑄟𑄳𑄠𑄛𑄴")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F30B"), QStringLiteral("𑄃𑄉𑄪𑄚𑄮𑄢𑄴 𑄜𑄪𑄘𑄋𑄢𑄳𑄦")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F3D8"), QStringLiteral("𑄊𑄧𑄢𑄚𑄨")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F3E0"), QStringLiteral("𑄊𑄧𑄢𑄴")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F3EB"), QStringLiteral("𑄄𑄌𑄴𑄇𑄪𑄣𑄴")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F3ED"), QStringLiteral("𑄜𑄳𑄠𑄇𑄴𑄑𑄧𑄢𑄨")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F5FC"), QStringLiteral("𑄑𑄮𑄇𑄨𑄠𑄮 𑄑𑄅𑄠𑄢𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4E3"), QStringLiteral("𑄟𑄳𑄠𑄊𑄜𑄮𑄚𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F514"), QStringLiteral("𑄝𑄬𑄣𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F3A4"), QStringLiteral("𑄟𑄭𑄇𑄳𑄢𑄮𑄜𑄮𑄚𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F3A7"), QStringLiteral("𑄖𑄬𑄖𑄴𑄜𑄮𑄚𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4FB"), QStringLiteral("𑄢𑄬𑄓𑄨𑄠𑄮")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F3B8"), QStringLiteral("𑄉𑄨𑄑𑄢𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F941"), QStringLiteral("𑄓𑄳𑄢𑄟𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4F1"), QStringLiteral("𑄟𑄮𑄝𑄭𑄣𑄴𑄜𑄮𑄚𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0000260E"), QStringLiteral("𑄑𑄬𑄣𑄨𑄜𑄮𑄚𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4DE"), QStringLiteral("𑄑𑄬𑄣𑄨𑄜𑄮𑄚𑄴 𑄢𑄨𑄥𑄨𑄞𑄢𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4E0"), QStringLiteral("𑄜𑄳𑄠𑄇𑄴𑄌𑄴 𑄟𑄨𑄥𑄨𑄚𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F50B"), QStringLiteral("𑄝𑄬𑄑𑄢𑄨")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4BB"), QStringLiteral("𑄣𑄳𑄠𑄛𑄴𑄑𑄧𑄛𑄴 𑄇𑄧𑄟𑄴𑄛𑄅𑄑𑄢𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F5A5"), QStringLiteral("𑄓𑄬𑄌𑄴𑄇𑄴𑄑𑄧𑄛𑄴 𑄇𑄧𑄟𑄴𑄛𑄅𑄑𑄢𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F5A8"), QStringLiteral("𑄛𑄳𑄢𑄨𑄚𑄴𑄑𑄢𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U00002328"), QStringLiteral("𑄇𑄨𑄝𑄮𑄖𑄴𑄢𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F5B1"), QStringLiteral("𑄇𑄧𑄟𑄴𑄛𑄅𑄑𑄢𑄴 𑄟𑄅𑄌𑄴𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F5B2"), QStringLiteral("𑄑𑄳𑄢𑄇𑄴𑄝𑄧𑄣𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4BD"), QStringLiteral("𑄇𑄧𑄟𑄴𑄛𑄅𑄑𑄢𑄴 𑄓𑄨𑄌𑄴𑄇𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4BE"), QStringLiteral("𑄜𑄳𑄣𑄧𑄛𑄨 𑄓𑄨𑄌𑄴𑄇𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4BF"), QStringLiteral("𑄃𑄧𑄛𑄴𑄑𑄨𑄇𑄳𑄠𑄣𑄴 𑄓𑄨𑄌𑄴𑄇𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4C0"), QStringLiteral("𑄓𑄨𑄞𑄨𑄓𑄨")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F9EE"), QStringLiteral("𑄃𑄳𑄠𑄝𑄇𑄌𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F3A5"), QStringLiteral("𑄟𑄪𑄞𑄨 𑄇𑄬𑄟𑄬𑄢")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F39E"), QStringLiteral("𑄜𑄨𑄣𑄴𑄟𑄴 𑄜𑄳𑄢𑄬𑄟𑄴𑄌𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4FD"), QStringLiteral("𑄜𑄨𑄣𑄴𑄟𑄴 𑄛𑄳𑄢𑄧𑄎𑄬𑄇𑄴𑄑𑄧𑄢𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F3AC"), QStringLiteral("𑄇𑄳𑄣𑄳𑄠𑄛𑄢𑄴 𑄝𑄮𑄢𑄳𑄓𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4FA"), QStringLiteral("𑄑𑄬𑄣𑄨𑄞𑄨𑄥𑄧𑄚𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4F7"), QStringLiteral("𑄇𑄬𑄟𑄬𑄢")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4F8"), QStringLiteral("𑄇𑄬𑄟𑄬𑄢 𑄣𑄧𑄉𑄬 𑄜𑄳𑄣𑄌𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4F9"), QStringLiteral("𑄞𑄨𑄓𑄨𑄠𑄮 𑄇𑄬𑄟𑄬𑄢")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4FC"), QStringLiteral("𑄞𑄨𑄓𑄨𑄠𑄮𑄇𑄬𑄥𑄬𑄖𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F56F"), QStringLiteral("𑄟𑄪𑄟𑄴𑄝𑄖𑄴𑄨")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4A1"), QStringLiteral("𑄟𑄪𑄟𑄴𑄝𑄖𑄴𑄨 𑄝𑄣𑄳𑄛𑄴")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F526"), QStringLiteral("𑄑𑄨𑄛𑄴𑄝𑄨𑄖𑄴𑄨")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4E7"), QStringLiteral("𑄄-𑄟𑄬𑄭𑄣𑄴")});
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F38C"), QStringLiteral("𑄝𑄃𑄟𑄪𑄌𑄳𑄠𑄴 𑄝𑄝𑄧𑄘")});
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F3F4"), QStringLiteral("𑄇𑄣 𑄝𑄝𑄧𑄘")});
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F3F3"), QStringLiteral("𑄙𑄪𑄛𑄴 𑄝𑄝𑄧𑄘")});
};

17
src/data/emoji/ceb.cpp Normal file
View File

@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: None
// SPDX-License-Identifier: LGPL-2.0-or-later
// This file is auto-generated. All changes will be lost. See tools/README.md
// clang-format off
#include <QString>
#include <QHash>
#include "../../emojimap.h"
class cebEmojiMap: public EmojiMap {
public:
QHash<EmojiModel::Category, QVector<Emoji>> langEmojiMap()
{
QHash<EmojiModel::Category, QVector<Emoji>> _emojis;
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F3F3\U0000200D\U000026A7"), QStringLiteral("flag sa transgender")});
};

1548
src/data/emoji/chr.cpp Normal file

File diff suppressed because it is too large Load Diff

17
src/data/emoji/ckb.cpp Normal file
View File

@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: None
// SPDX-License-Identifier: LGPL-2.0-or-later
// This file is auto-generated. All changes will be lost. See tools/README.md
// clang-format off
#include <QString>
#include <QHash>
#include "../../emojimap.h"
class ckbEmojiMap: public EmojiMap {
public:
QHash<EmojiModel::Category, QVector<Emoji>> langEmojiMap()
{
QHash<EmojiModel::Category, QVector<Emoji>> _emojis;
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F52B"), QStringLiteral("دەمانچەی ئاوی")});
};

1555
src/data/emoji/cs.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/cy.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/da.cpp Normal file

File diff suppressed because it is too large Load Diff

1555
src/data/emoji/de.cpp Normal file

File diff suppressed because it is too large Load Diff

111
src/data/emoji/de_ch.cpp Normal file
View File

@@ -0,0 +1,111 @@
// SPDX-FileCopyrightText: None
// SPDX-License-Identifier: LGPL-2.0-or-later
// This file is auto-generated. All changes will be lost. See tools/README.md
// clang-format off
#include <QString>
#include <QHash>
#include "../../emojimap.h"
class de_chEmojiMap: public EmojiMap {
public:
QHash<EmojiModel::Category, QVector<Emoji>> langEmojiMap()
{
QHash<EmojiModel::Category, QVector<Emoji>> _emojis;
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F91D\U0000200D\U0001F9D1"), QStringLiteral("sich an den Händen haltende Personen")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F636\U0000200D\U0001F32B"), QStringLiteral("Kopf in den Wolken")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F62E\U0000200D\U0001F4A8"), QStringLiteral("ausatmendes Gesicht")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F635\U0000200D\U0001F4AB"), QStringLiteral("Gesicht mit Spiralaugen")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U00002764\U0000200D\U0001F525"), QStringLiteral("brennendes Herz")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U00002764\U0000200D\U0001FA79"), QStringLiteral("Herz mit Pflaster")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F3EB"), QStringLiteral("Lehrer(in)")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F4BC"), QStringLiteral("Büroangestellte(r)")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9DF\U0000200D\U00002642"), QStringLiteral("Zombiemann")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6B6\U0000200D\U00002642"), QStringLiteral("Fussgänger")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6B6\U0000200D\U00002640"), QStringLiteral("Fussgängerin")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9D1\U0000200D\U0001F9AF"), QStringLiteral("Person mit Langstock")});
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F3F3\U0000200D\U000026A7"), QStringLiteral("Transgenderflagge")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001FA7B"), QStringLiteral("Röntgen")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001FA7C"), QStringLiteral("Krücke")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001FAAA"), QStringLiteral("ID")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001FAD7"), QStringLiteral("Flüssigkeit ausgiessen")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001FAE0"), QStringLiteral("schmelzendes Gesicht")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001FAE1"), QStringLiteral("grüssendes Gesicht")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001FAE6"), QStringLiteral("Auf Lippe beissen")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001FAE7"), QStringLiteral("Seifenblasen")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F603"), QStringLiteral("grinsendes Gesicht mit grossen Augen")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F605"), QStringLiteral("Lachender Smiley mit kaltem Schweiss")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F910"), QStringLiteral("Smiley mit Reissverschlussmund")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F978"), QStringLiteral("Gesicht mit Maske")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F633"), QStringLiteral("Erröteter Smiley mit grossen Augen")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F630"), QStringLiteral("Smiley mit offenem Mund und kaltem Schweiss")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F613"), QStringLiteral("Smiley mit kaltem Schweiss")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F47D"), QStringLiteral("Ausserirdisches Wesen")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F90E"), QStringLiteral("braunes Herz")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F90D"), QStringLiteral("weisses Herz")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F4A5"), QStringLiteral("Zusammenstoss")});
_emojis[EmojiModel::Smileys].append(Emoji{QString::fromUtf8("\U0001F4A6"), QStringLiteral("Schweisstropfen")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F596"), QStringLiteral("Vulkanischer Gruss")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F918"), QStringLiteral("Teufelsgruss")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F9B6"), QStringLiteral("Fuss")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F6B6"), QStringLiteral("Fussgänger(in)")});
_emojis[EmojiModel::People].append(Emoji{QString::fromUtf8("\U0001F463"), QStringLiteral("Fussabdrücke")});
_emojis[EmojiModel::Component].append(Emoji{QString::fromUtf8("\U0001F9B3"), QStringLiteral("weisses Haar")});
_emojis[EmojiModel::Nature].append(Emoji{QString::fromUtf8("\U0001F490"), QStringLiteral("Blumenstrauss")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F336"), QStringLiteral("Chili")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001FAD1"), QStringLiteral("Peperoni")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F357"), QStringLiteral("Pouletschenkel")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001F360"), QStringLiteral("Geröstete Süsskartoffel")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U00002615"), QStringLiteral("Heissgetränk")});
_emojis[EmojiModel::Food].append(Emoji{QString::fromUtf8("\U0001FAD6"), QStringLiteral("Teekrug")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U00002668"), QStringLiteral("Heisse Quellen")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F68A"), QStringLiteral("Strassenbahn")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F68B"), QStringLiteral("Tramwagen")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U00002B50"), QStringLiteral("weisser mittelgrosser Stern")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F30C"), QStringLiteral("Milchstrasse")});
_emojis[EmojiModel::Travel].append(Emoji{QString::fromUtf8("\U0001F325"), QStringLiteral("Sonne hinter grosser Wolke")});
_emojis[EmojiModel::Activities].append(Emoji{QString::fromUtf8("\U000026BD"), QStringLiteral("Fussball")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F392"), QStringLiteral("Schulsack")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001FA74"), QStringLiteral("Flipflops")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U000026D1"), QStringLiteral("Helm mit weissem Kreuz")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4C6"), QStringLiteral("Abreisskalender")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4CC"), QStringLiteral("Reisszwecke")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F4CD"), QStringLiteral("runde Reisszwecke")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001FA9D"), QStringLiteral("Haken")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001F6D7"), QStringLiteral("Lift")});
_emojis[EmojiModel::Objects].append(Emoji{QString::fromUtf8("\U0001FAA0"), QStringLiteral("Saugglocke")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F6B8"), QStringLiteral("Kinder-queren-die-Strasse-Schild")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F6B7"), QStringLiteral("Fussgänger-verboten-Schild")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U00002622"), QStringLiteral("radioaktiv")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U00002795"), QStringLiteral("Plus")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U00002796"), QStringLiteral("Minus")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U00002754"), QStringLiteral("weisses Fragezeichen")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U00002755"), QStringLiteral("weisses Ausrufezeichen")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U00002705"), QStringLiteral("Weisses Häkchen")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F520"), QStringLiteral("Eingabesymbol lateinische Grossbuchstaben")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F170"), QStringLiteral("Grossbuchstabe A in Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F18E"), QStringLiteral("Grossbuchstaben AB in rotem Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F171"), QStringLiteral("Grossbuchstabe B in Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F191"), QStringLiteral("Grossbuchstaben CL in rotem Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F194"), QStringLiteral("Grossbuchstaben ID in lila Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F196"), QStringLiteral("Grossbuchstaben NG in blauem Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F17E"), QStringLiteral("Grossbuchstabe O in Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F197"), QStringLiteral("Grossbuchstaben OK in blauem Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F17F"), QStringLiteral("Grossbuchstabe P in Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F19A"), QStringLiteral("Grossbuchstaben VS in orangefarbenem Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F534"), QStringLiteral("Grosser roter Kreis")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F535"), QStringLiteral("Grosser blauer Kreis")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U000026AB"), QStringLiteral("Grosser schwarzer Kreis")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U000026AA"), QStringLiteral("Grosser weisser Kreis")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U00002B1B"), QStringLiteral("Grosses schwarzes Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U00002B1C"), QStringLiteral("Grosses weisses Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U000025FC"), QStringLiteral("Mittelgrosses schwarzes Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U000025FB"), QStringLiteral("Mittelgrosses weisses Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U000025FD"), QStringLiteral("Mittelkleines weisses Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U000025AB"), QStringLiteral("Kleines weisses Quadrat")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F536"), QStringLiteral("Grosse orangefarbene Raute")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F537"), QStringLiteral("Grosse blaue Raute")});
_emojis[EmojiModel::Symbols].append(Emoji{QString::fromUtf8("\U0001F533"), QStringLiteral("Weisse quadratische Schaltfläche")});
_emojis[EmojiModel::Flags].append(Emoji{QString::fromUtf8("\U0001F3F3"), QStringLiteral("Wehende weisse Fahne")});
};

Some files were not shown because too many files have changed in this diff Show More