Compare commits
2 Commits
release/24
...
work/redst
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80ebe71f6a | ||
|
|
02578dd38f |
@@ -110,7 +110,7 @@
|
|||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/quotient-im/libQuotient.git",
|
"url": "https://github.com/quotient-im/libQuotient.git",
|
||||||
"tag": "0.9.2",
|
"branch": "0.8.x",
|
||||||
"disable-submodules": true
|
"disable-submodules": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ Dependencies:
|
|||||||
'frameworks/kquickcharts': '@latest-kf6'
|
'frameworks/kquickcharts': '@latest-kf6'
|
||||||
'frameworks/knotifications': '@latest-kf6'
|
'frameworks/knotifications': '@latest-kf6'
|
||||||
'frameworks/kcolorscheme': '@latest-kf6'
|
'frameworks/kcolorscheme': '@latest-kf6'
|
||||||
'frameworks/kiconthemes': '@latest-kf6'
|
|
||||||
'libraries/kquickimageeditor': '@latest-kf6'
|
'libraries/kquickimageeditor': '@latest-kf6'
|
||||||
'frameworks/sonnet': '@latest-kf6'
|
'frameworks/sonnet': '@latest-kf6'
|
||||||
'frameworks/prison': '@latest-kf6'
|
'frameworks/prison': '@latest-kf6'
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ 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 "24")
|
||||||
set(RELEASE_SERVICE_VERSION_MINOR "12")
|
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
||||||
set(RELEASE_SERVICE_VERSION_MICRO "3")
|
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||||
|
|
||||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||||
@@ -66,7 +66,7 @@ if (QT_KNOWN_POLICY_QTP0004)
|
|||||||
qt_policy(SET QTP0004 NEW)
|
qt_policy(SET QTP0004 NEW)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels IconThemes ColorScheme)
|
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
|
||||||
set_package_properties(KF6 PROPERTIES
|
set_package_properties(KF6 PROPERTIES
|
||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
PURPOSE "Basic application components"
|
PURPOSE "Basic application components"
|
||||||
@@ -107,7 +107,7 @@ if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU)
|
|||||||
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
|
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(QuotientQt6 0.9)
|
find_package(QuotientQt6 0.8.2)
|
||||||
set_package_properties(QuotientQt6 PROPERTIES
|
set_package_properties(QuotientQt6 PROPERTIES
|
||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
DESCRIPTION "Qt wrapper around Matrix API"
|
DESCRIPTION "Qt wrapper around Matrix API"
|
||||||
@@ -115,6 +115,11 @@ set_package_properties(QuotientQt6 PROPERTIES
|
|||||||
PURPOSE "Talk with matrix server"
|
PURPOSE "Talk with matrix server"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (NOT TARGET Olm::Olm)
|
||||||
|
message(FATAL_ERROR "NeoChat requires Quotient with the E2EE feature enabled")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
find_package(cmark)
|
find_package(cmark)
|
||||||
set_package_properties(cmark PROPERTIES
|
set_package_properties(cmark PROPERTIES
|
||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ 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://apps.kde.org/store_badges/snapstore/en.svg'/></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
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.6.0'
|
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,26 +5,6 @@
|
|||||||
"!room_id_1234:localhost:1234": {
|
"!room_id_1234:localhost:1234": {
|
||||||
"state": {
|
"state": {
|
||||||
"events": [
|
"events": [
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"m.federate": true,
|
|
||||||
"predecessor": {
|
|
||||||
"event_id": "$something:example.org",
|
|
||||||
"room_id": "!oldroom:example.org"
|
|
||||||
},
|
|
||||||
"room_version": "11"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1432735824653,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "@example:example.org",
|
|
||||||
"state_key": "",
|
|
||||||
"type": "m.room.create",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234,
|
|
||||||
"membership": "join"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "m.room.member",
|
"type": "m.room.member",
|
||||||
"state_key": "@user:localhost:1234",
|
"state_key": "@user:localhost:1234",
|
||||||
@@ -46,26 +26,6 @@
|
|||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"events": [
|
"events": [
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"m.federate": true,
|
|
||||||
"predecessor": {
|
|
||||||
"event_id": "$something:example.org",
|
|
||||||
"room_id": "!oldroom:example.org"
|
|
||||||
},
|
|
||||||
"room_version": "11"
|
|
||||||
},
|
|
||||||
"event_id": "$143273582443PhrSn:example.org",
|
|
||||||
"origin_server_ts": 1432735824653,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "@example:example.org",
|
|
||||||
"state_key": "",
|
|
||||||
"type": "m.room.create",
|
|
||||||
"unsigned": {
|
|
||||||
"age": 1234,
|
|
||||||
"membership": "join"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "m.room.message",
|
"type": "m.room.message",
|
||||||
"sender": "@user:localhost:1234",
|
"sender": "@user:localhost:1234",
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ ecm_add_test(
|
|||||||
TEST_NAME neochatroomtest
|
TEST_NAME neochatroomtest
|
||||||
)
|
)
|
||||||
|
|
||||||
# ecm_add_test(
|
ecm_add_test(
|
||||||
# texthandlertest.cpp
|
texthandlertest.cpp
|
||||||
# LINK_LIBRARIES neochat Qt::Test
|
LINK_LIBRARIES neochat Qt::Test
|
||||||
# TEST_NAME texthandlertest
|
TEST_NAME texthandlertest
|
||||||
# )
|
)
|
||||||
|
|
||||||
ecm_add_test(
|
ecm_add_test(
|
||||||
delegatesizehelpertest.cpp
|
delegatesizehelpertest.cpp
|
||||||
@@ -53,6 +53,12 @@ ecm_add_test(
|
|||||||
TEST_NAME messageeventmodeltest
|
TEST_NAME messageeventmodeltest
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ecm_add_test(
|
||||||
|
actionshandlertest.cpp
|
||||||
|
LINK_LIBRARIES neochat Qt::Test
|
||||||
|
TEST_NAME actionshandlertest
|
||||||
|
)
|
||||||
|
|
||||||
ecm_add_test(
|
ecm_add_test(
|
||||||
windowcontrollertest.cpp
|
windowcontrollertest.cpp
|
||||||
LINK_LIBRARIES neochat Qt::Test
|
LINK_LIBRARIES neochat Qt::Test
|
||||||
|
|||||||
41
autotests/actionshandlertest.cpp
Normal file
41
autotests/actionshandlertest.cpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// 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 <QTest>
|
||||||
|
|
||||||
|
#include "actionshandler.h"
|
||||||
|
#include "chatbarcache.h"
|
||||||
|
|
||||||
|
#include "testutils.h"
|
||||||
|
|
||||||
|
class ActionsHandlerTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
Quotient::Connection *connection = Quotient::Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void nullObject();
|
||||||
|
};
|
||||||
|
|
||||||
|
void ActionsHandlerTest::nullObject()
|
||||||
|
{
|
||||||
|
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
|
||||||
|
ActionsHandler::handleMessageEvent(nullptr, nullptr);
|
||||||
|
|
||||||
|
auto chatBarCache = new ChatBarCache(this);
|
||||||
|
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
|
||||||
|
ActionsHandler::handleMessageEvent(nullptr, chatBarCache);
|
||||||
|
|
||||||
|
auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
|
||||||
|
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
|
||||||
|
ActionsHandler::handleMessageEvent(room, nullptr);
|
||||||
|
|
||||||
|
// The final one should throw no warning so we make sure.
|
||||||
|
QTest::failOnWarning("ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
|
||||||
|
ActionsHandler::handleMessageEvent(room, chatBarCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN(ActionsHandlerTest)
|
||||||
|
#include "actionshandlertest.moc"
|
||||||
@@ -63,7 +63,6 @@ private Q_SLOTS:
|
|||||||
void receiveRichEdited();
|
void receiveRichEdited();
|
||||||
void receiveLineSeparator();
|
void receiveLineSeparator();
|
||||||
void receiveRichCodeUrl();
|
void receiveRichCodeUrl();
|
||||||
void receiveRichColor();
|
|
||||||
|
|
||||||
void componentOutput_data();
|
void componentOutput_data();
|
||||||
void componentOutput();
|
void componentOutput();
|
||||||
@@ -521,25 +520,6 @@ void TextHandlerTest::receiveRichCodeUrl()
|
|||||||
QCOMPARE(testTextHandler.handleRecieveRichText(), input);
|
QCOMPARE(testTextHandler.handleRecieveRichText(), input);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::receiveRichColor()
|
|
||||||
{
|
|
||||||
const QString testInputString = QStringLiteral(
|
|
||||||
"<span data-mx-color=\"#ff00be\">¯</span><span data-mx-color=\"#ff3b1d\">\\</span><span data-mx-color=\"#ffa600\">_</span><span "
|
|
||||||
"data-mx-color=\"#64d200\">(</span><span data-mx-color=\"#00e261\">ツ</span><span data-mx-color=\"#00e7ff\">)</span><span "
|
|
||||||
"data-mx-color=\"#00e1ff\">_</span><span data-mx-color=\"#00bdff\">/</span><span data-mx-color=\"#ff60ff\">¯</span>");
|
|
||||||
const QString testOutputString = QStringLiteral(
|
|
||||||
"<span style=\"color: #ff00be;\">¯</span><span style=\"color: #ff3b1d;\">\\</span><span style=\"color: #ffa600;\">_</span><span style=\"color: "
|
|
||||||
"#64d200;\">(</span><span style=\"color: #00e261;\">ツ</span><span style=\"color: #00e7ff;\">)</span><span style=\"color: #00e1ff;\">_</span><span "
|
|
||||||
"style=\"color: #00bdff;\">/</span><span style=\"color: #ff60ff;\">¯</span>");
|
|
||||||
|
|
||||||
TextHandler testTextHandler;
|
|
||||||
testTextHandler.setData(testInputString);
|
|
||||||
|
|
||||||
qInfo() << testTextHandler.handleRecieveRichText();
|
|
||||||
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextHandlerTest::componentOutput_data()
|
void TextHandlerTest::componentOutput_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("testInputString");
|
QTest::addColumn<QString>("testInputString");
|
||||||
@@ -555,7 +535,7 @@ void TextHandlerTest::componentOutput_data()
|
|||||||
QVariantMap{{QStringLiteral("class"), QStringLiteral("html")}}}};
|
QVariantMap{{QStringLiteral("class"), QStringLiteral("html")}}}};
|
||||||
QTest::newRow("quote") << QStringLiteral("<p>Text</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>")
|
QTest::newRow("quote") << QStringLiteral("<p>Text</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>")
|
||||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}},
|
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}},
|
||||||
MessageComponent{MessageComponentType::Quote, QStringLiteral("“blockquote”"), {}}};
|
MessageComponent{MessageComponentType::Quote, QStringLiteral("\"blockquote\""), {}}};
|
||||||
QTest::newRow("no tag first paragraph") << QStringLiteral("Text\n<p>Text</p>")
|
QTest::newRow("no tag first paragraph") << QStringLiteral("Text\n<p>Text</p>")
|
||||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}},
|
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}},
|
||||||
MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}}};
|
MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}}};
|
||||||
|
|||||||
@@ -54,16 +54,9 @@
|
|||||||
<summary xml:lang="ar">دردش على ماتركس</summary>
|
<summary xml:lang="ar">دردش على ماتركس</summary>
|
||||||
<summary xml:lang="ca">Xat a Matrix</summary>
|
<summary xml:lang="ca">Xat a Matrix</summary>
|
||||||
<summary xml:lang="ca-valencia">Xat a Matrix</summary>
|
<summary xml:lang="ca-valencia">Xat a Matrix</summary>
|
||||||
<summary xml:lang="de">Über Matrix unterhalten</summary>
|
|
||||||
<summary xml:lang="en-GB">Chat on Matrix</summary>
|
|
||||||
<summary xml:lang="eo">Babilo en Matrix</summary>
|
|
||||||
<summary xml:lang="es">Charle en Matrix</summary>
|
<summary xml:lang="es">Charle en Matrix</summary>
|
||||||
<summary xml:lang="eu">Berriketa Matrix-en</summary>
|
<summary xml:lang="eu">Berriketa Matrix-en</summary>
|
||||||
<summary xml:lang="fi">Keskustelu Matrixissä</summary>
|
|
||||||
<summary xml:lang="fr">Discuter sur Matrix</summary>
|
<summary xml:lang="fr">Discuter sur Matrix</summary>
|
||||||
<summary xml:lang="gl">Charlar en Matrix</summary>
|
|
||||||
<summary xml:lang="he">התכתבות דרך Matrix</summary>
|
|
||||||
<summary xml:lang="hu">Csevegés Matrixon</summary>
|
|
||||||
<summary xml:lang="ia">Conversation en ditecto sur Matrix</summary>
|
<summary xml:lang="ia">Conversation en ditecto sur Matrix</summary>
|
||||||
<summary xml:lang="it">Chat su Matrix</summary>
|
<summary xml:lang="it">Chat su Matrix</summary>
|
||||||
<summary xml:lang="ka">ისაუბრეთ Matrix-ზე</summary>
|
<summary xml:lang="ka">ისაუბრეთ Matrix-ზე</summary>
|
||||||
@@ -71,7 +64,6 @@
|
|||||||
<summary xml:lang="nn">Prat med via Matrix</summary>
|
<summary xml:lang="nn">Prat med via Matrix</summary>
|
||||||
<summary xml:lang="pl">Rozmawiaj na Matriksie</summary>
|
<summary xml:lang="pl">Rozmawiaj na Matriksie</summary>
|
||||||
<summary xml:lang="sl">Klepet na Matrixu</summary>
|
<summary xml:lang="sl">Klepet na Matrixu</summary>
|
||||||
<summary xml:lang="sv">Chatta på Matrix</summary>
|
|
||||||
<summary xml:lang="ta">மேட்ரிக்ஸுக்கான உரையாடல் செயலி</summary>
|
<summary xml:lang="ta">மேட்ரிக்ஸுக்கான உரையாடல் செயலி</summary>
|
||||||
<summary xml:lang="tr">Matrix Üzerinde Sohbet</summary>
|
<summary xml:lang="tr">Matrix Üzerinde Sohbet</summary>
|
||||||
<summary xml:lang="uk">Спілкування у Matrix</summary>
|
<summary xml:lang="uk">Спілкування у Matrix</summary>
|
||||||
@@ -119,7 +111,7 @@
|
|||||||
<p xml:lang="eu">«NeoChat»ek «Matrix» zehaztapenaren ezaugarri guztiak eskaintzen dituen aplikazio bat izan nahi du. Beraz, egungo zehaztapen egonkorrean dagoen guztiaren euskarria du, VoIP, hariak eta muturren artean zifratzeko salbuespen nabarmenekin. Badira beste ez-betetze txikiago batzuk, «Matrix»en zehaztapena etengabe eboluzioan dagoelako, baina azken helburua zehaztapen osoaren euskarria ematea izaten jarraitzen du.</p>
|
<p xml:lang="eu">«NeoChat»ek «Matrix» zehaztapenaren ezaugarri guztiak eskaintzen dituen aplikazio bat izan nahi du. Beraz, egungo zehaztapen egonkorrean dagoen guztiaren euskarria du, VoIP, hariak eta muturren artean zifratzeko salbuespen nabarmenekin. Badira beste ez-betetze txikiago batzuk, «Matrix»en zehaztapena etengabe eboluzioan dagoelako, baina azken helburua zehaztapen osoaren euskarria ematea izaten jarraitzen du.</p>
|
||||||
<p xml:lang="fi">NeoChat pyrkii olemaan Matrix-määritelmän täysominaisuuksinen sovellus, joten se tukee kaikkea nykyisessä vakaassa määritelmässä muutamaa huomattavaa poikkeusta lukuun ottamatta (VoIP, säikeet ja jotkin piirteet päästä päähän -salauksessa). Joitakin pienempiäkin puutteita on Matrix-määritelmän jatkuvan kehityksen vuoksi, mutta lopputavoitteena on tarjota määritelmän täysi tuki.</p>
|
<p xml:lang="fi">NeoChat pyrkii olemaan Matrix-määritelmän täysominaisuuksinen sovellus, joten se tukee kaikkea nykyisessä vakaassa määritelmässä muutamaa huomattavaa poikkeusta lukuun ottamatta (VoIP, säikeet ja jotkin piirteet päästä päähän -salauksessa). Joitakin pienempiäkin puutteita on Matrix-määritelmän jatkuvan kehityksen vuoksi, mutta lopputavoitteena on tarjota määritelmän täysi tuki.</p>
|
||||||
<p xml:lang="fr">L'objectif de NeoChat est d'être une application complète pour le protocole Matrix. En tant que tel, tout dans la spécification stable actuelle avec les exceptions notables de VoIP, les processus et certains aspects du chiffrement de bout en bout sont pris en charge. Il y a quelques autres petites omissions en raison du fait que la spécification du protocole Matrix est en constante évolution. Cependant, l'objectif reste de fournir un soutien éventuel pour l'ensemble de la spécification.</p>
|
<p xml:lang="fr">L'objectif de NeoChat est d'être une application complète pour le protocole Matrix. En tant que tel, tout dans la spécification stable actuelle avec les exceptions notables de VoIP, les processus et certains aspects du chiffrement de bout en bout sont pris en charge. Il y a quelques autres petites omissions en raison du fait que la spécification du protocole Matrix est en constante évolution. Cependant, l'objectif reste de fournir un soutien éventuel pour l'ensemble de la spécification.</p>
|
||||||
<p xml:lang="gl">NeoChat pretende ser unha aplicación completa para a especificación de Matrix. Coas excepcións de VoIP, conversas fiadas e algúns aspectos da cifraxe de extremo a extremo, a versión estábel segue as especificacións. Existen algunhas outras pequenas omisións debido ao feito de que Matrix está en continua evolución pero a intención é fornecer compatibilidade coa especificación completa.</p>
|
<p xml:lang="gl">NeoChat pretende ser unha aplicación completa para a especificación de Matrix. Coas excepcións de VoIP, conversas fiadas e algúns aspectos da cifraxe de extremo a extremo, a versión estábel segue as especificacións. Existen algunhas outras pequenas omisións debido ao feito de que Matrix está en continua evolución pero a intención é implementar a especificación completa.</p>
|
||||||
<p xml:lang="he">NeoChat מתיימר להיות יישום עתיר יכולות לפי מפרט Matrix. כיוון שזה ייעודו, כל מה שבמפרט היציב עם חריגות משמעותיות כגון VoIP, שרשורים ועוד מגוון היבטים של הצפנה מקצה לקצה נתמכים גם הם. יש מספר השמטות קטן עקב העובדה שהמפרט של Matrix ממשיך להתפתח אך המטרה היא להמשיך לספק תמיכה בסופו של דבר לכל המפרט.</p>
|
<p xml:lang="he">NeoChat מתיימר להיות יישום עתיר יכולות לפי מפרט Matrix. כיוון שזה ייעודו, כל מה שבמפרט היציב עם חריגות משמעותיות כגון VoIP, שרשורים ועוד מגוון היבטים של הצפנה מקצה לקצה נתמכים גם הם. יש מספר השמטות קטן עקב העובדה שהמפרט של Matrix ממשיך להתפתח אך המטרה היא להמשיך לספק תמיכה בסופו של דבר לכל המפרט.</p>
|
||||||
<p xml:lang="hu">A NeoChat célja, hogy a Matrix specifikációnak megfelelő teljes funkcionalitású alkalmazás legyen. Mint ilyen, a jelenlegi stabil specifikáció támogatott a VoIP, a szálak és a végpontok közötti titkosítás egyes elemeinek kivételével. Van még néhány kisebb hiányosság annak köszönhetően, hogy a Matrix specifikáció folyamatosan fejlődik, de végső cél a teljes specifikáció megvalósítása.</p>
|
<p xml:lang="hu">A NeoChat célja, hogy a Matrix specifikációnak megfelelő teljes funkcionalitású alkalmazás legyen. Mint ilyen, a jelenlegi stabil specifikáció támogatott a VoIP, a szálak és a végpontok közötti titkosítás egyes elemeinek kivételével. Van még néhány kisebb hiányosság annak köszönhetően, hogy a Matrix specifikáció folyamatosan fejlődik, de végső cél a teljes specifikáció megvalósítása.</p>
|
||||||
<p xml:lang="ia">NeoChat aspira a esser un application plenmente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p>
|
<p xml:lang="ia">NeoChat aspira a esser un application plenmente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p>
|
||||||
@@ -447,10 +439,6 @@
|
|||||||
<content_attribute id="social-chat">intense</content_attribute>
|
<content_attribute id="social-chat">intense</content_attribute>
|
||||||
</content_rating>
|
</content_rating>
|
||||||
<releases>
|
<releases>
|
||||||
<release version="24.12.3" date="2025-03-06"/>
|
|
||||||
<release version="24.12.2" date="2025-02-06"/>
|
|
||||||
<release version="24.12.1" date="2025-01-09"/>
|
|
||||||
<release version="24.12.0" date="2024-12-12"/>
|
|
||||||
<release version="24.08.3" date="2024-11-07"/>
|
<release version="24.08.3" date="2024-11-07"/>
|
||||||
<release version="24.08.2" date="2024-10-10"/>
|
<release version="24.08.2" date="2024-10-10"/>
|
||||||
<release version="24.08.1" date="2024-09-12"/>
|
<release version="24.08.1" date="2024-09-12"/>
|
||||||
|
|||||||
@@ -87,33 +87,47 @@ GenericName[uk]=Клієнт Matrix
|
|||||||
GenericName[x-test]=xxMatrix Clientxx
|
GenericName[x-test]=xxMatrix Clientxx
|
||||||
GenericName[zh_CN]=Matrix 客户端
|
GenericName[zh_CN]=Matrix 客户端
|
||||||
GenericName[zh_TW]=Matrix 用戶端
|
GenericName[zh_TW]=Matrix 用戶端
|
||||||
Comment=Chat on Matrix
|
Comment=Client for the Matrix protocol
|
||||||
Comment[ar]=دردش على ماتركس
|
Comment[ar]=عميل لميفاق ماتركس
|
||||||
Comment[ca]=Xat a Matrix
|
Comment[az]=Matrix protokolu üçün müştəri
|
||||||
Comment[ca@valencia]=Xat a Matrix
|
Comment[ca]=Client per al protocol Matrix
|
||||||
Comment[de]=Über Matrix unterhalten
|
Comment[ca@valencia]=Client per al protocol Matrix
|
||||||
Comment[en_GB]=Chat on Matrix
|
Comment[de]=Programm für das Matrix-Protokoll
|
||||||
Comment[eo]=Babilo en Matrix
|
Comment[el]=Πελάτης για το πρωτόκολλο Matrix
|
||||||
Comment[es]=Chat en Matrix
|
Comment[en_GB]=Client for the Matrix protocol
|
||||||
Comment[eu]=Berriketa Matrix-en
|
Comment[eo]=Kliento por la Matrix-protokolo
|
||||||
Comment[fi]=Keskustele Matrixissä
|
Comment[es]=Cliente para el protocolo Matrix
|
||||||
Comment[fr]=Clavarder sur Matrix
|
Comment[eu]=Matrix protokolorako bezeroa
|
||||||
Comment[gl]=Charle en Matrix
|
Comment[fi]=Asiakas Matrix-yhteyskäytännölle
|
||||||
Comment[he]=התכתבות דרך Matrix
|
Comment[fr]=Client pour le protocole « Matrix »
|
||||||
Comment[hu]=Csevegés Matrixon
|
Comment[gl]=Cliente para o protocolo Matrix.
|
||||||
Comment[ia]=Conversation en ditecto sur Matrix
|
Comment[he]=לקוח לפרוטוקול Matrix
|
||||||
Comment[it]= su Matrix
|
Comment[hu]=Kliens a Matrix protokollhoz
|
||||||
Comment[ka]=საუბარი Matrix-ზე
|
Comment[ia]=Cliente per le protocollo de Matrix
|
||||||
Comment[nl]=Chat op Matrix
|
Comment[id]=Klien untuk protokol Matrix
|
||||||
Comment[pl]=Rozmawiaj na Matriksie
|
Comment[ie]=Un cliente del protocol Matrix
|
||||||
Comment[pt_BR]=Bate papo na Matrix
|
Comment[it]=Client per il protocollo Matrix
|
||||||
Comment[sl]=Klepet na Matrixu
|
Comment[ka]=კლიენტი Matrix-ის პროტოკოლისთვის
|
||||||
Comment[sv]=Chatta på Matrix
|
Comment[ko]=Matrix 프로토콜용 클라이언트
|
||||||
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும்
|
Comment[lt]=Matrix protokolo kliento programa
|
||||||
Comment[tr]=Matrix üzerinde sohbet edin
|
Comment[lv]=Klients „Matrix“ protokolam
|
||||||
Comment[uk]=Спілкування у Matrix
|
Comment[nl]=Client voor het Matrix-protocol
|
||||||
Comment[zh_CN]=在 Matrix 上聊天
|
Comment[nn]=Klient for Matrix-protokollen
|
||||||
Comment[zh_TW]=在 Matrix 上聊天
|
Comment[pa]=ਮੈਟਰਿਕਸ ਪਰੋਟੋਕਾਲ ਲਈ ਕਲਾਈਂਟ ਹੈ
|
||||||
|
Comment[pl]=Program obsługi protokołu Matriksa
|
||||||
|
Comment[pt]=Cliente para o protocolo Matrix
|
||||||
|
Comment[pt_BR]=Cliente para o protocolo Matrix
|
||||||
|
Comment[ro]=Client pentru protocolul Matrix
|
||||||
|
Comment[ru]=Клиент для протокола Matrix
|
||||||
|
Comment[sk]=Klient protokolu Matrix
|
||||||
|
Comment[sl]=Odjemalec za protokol Matrix
|
||||||
|
Comment[sv]=Klient för protokollet Matrix
|
||||||
|
Comment[ta]=Matrix நெறிமுறைக்கான வாங்கி
|
||||||
|
Comment[tr]=Matrix protokolü için istemci
|
||||||
|
Comment[uk]=Клієнт протоколу Matrix
|
||||||
|
Comment[x-test]=xxClient for the Matrix protocolxx
|
||||||
|
Comment[zh_CN]=为 Matrix 协议打造的客户端
|
||||||
|
Comment[zh_TW]=Matrix 通訊協定的用戶端
|
||||||
MimeType=x-scheme-handler/matrix;
|
MimeType=x-scheme-handler/matrix;
|
||||||
Exec=neochat %u
|
Exec=neochat %u
|
||||||
Terminal=false
|
Terminal=false
|
||||||
|
|||||||
866
po/ar/neochat.po
866
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
867
po/az/neochat.po
867
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1150
po/ca/neochat.po
1150
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
856
po/cs/neochat.po
856
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
864
po/da/neochat.po
864
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1226
po/de/neochat.po
1226
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
867
po/el/neochat.po
867
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
948
po/eo/neochat.po
948
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
864
po/es/neochat.po
864
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
926
po/eu/neochat.po
926
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
2169
po/fi/neochat.po
2169
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
876
po/fr/neochat.po
876
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
965
po/gl/neochat.po
965
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
914
po/hu/neochat.po
914
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
862
po/ia/neochat.po
862
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
867
po/id/neochat.po
867
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
867
po/ie/neochat.po
867
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
868
po/it/neochat.po
868
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
847
po/ja/neochat.po
847
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
862
po/ka/neochat.po
862
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
865
po/ko/neochat.po
865
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
847
po/lt/neochat.po
847
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
865
po/lv/neochat.po
865
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
870
po/nl/neochat.po
870
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
887
po/nn/neochat.po
887
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
867
po/pa/neochat.po
867
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
872
po/pl/neochat.po
872
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
867
po/pt/neochat.po
867
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
972
po/ru/neochat.po
972
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
867
po/sk/neochat.po
867
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
862
po/sl/neochat.po
862
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
865
po/sv/neochat.po
865
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
864
po/ta/neochat.po
864
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1086
po/tr/neochat.po
1086
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
864
po/uk/neochat.po
864
po/uk/neochat.po
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
@@ -3,7 +3,7 @@
|
|||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
---
|
---
|
||||||
name: neochat
|
name: neochat
|
||||||
base: core24
|
base: core22
|
||||||
adopt-info: neochat
|
adopt-info: neochat
|
||||||
grade: stable
|
grade: stable
|
||||||
confinement: strict
|
confinement: strict
|
||||||
@@ -27,10 +27,6 @@ apps:
|
|||||||
|
|
||||||
compression: lzo
|
compression: lzo
|
||||||
|
|
||||||
package-repositories:
|
|
||||||
- type: apt
|
|
||||||
ppa: ubuntu-toolchain-r/test
|
|
||||||
|
|
||||||
slots:
|
slots:
|
||||||
session-dbus-interface:
|
session-dbus-interface:
|
||||||
interface: dbus
|
interface: dbus
|
||||||
@@ -80,7 +76,6 @@ parts:
|
|||||||
source-depth: 1
|
source-depth: 1
|
||||||
plugin: cmake
|
plugin: cmake
|
||||||
build-environment:
|
build-environment:
|
||||||
- PATH: /snap/bin:${PATH}
|
|
||||||
- PKG_CONFIG_PATH: $CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET/pkgconfig:$PKG_CONFIG_PATH
|
- PKG_CONFIG_PATH: $CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET/pkgconfig:$PKG_CONFIG_PATH
|
||||||
cmake-parameters:
|
cmake-parameters:
|
||||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
@@ -97,13 +92,9 @@ parts:
|
|||||||
- olm
|
- olm
|
||||||
- qtkeychain
|
- qtkeychain
|
||||||
source: https://github.com/quotient-im/libQuotient.git
|
source: https://github.com/quotient-im/libQuotient.git
|
||||||
source-tag: 0.9.1
|
source-tag: 0.8.2
|
||||||
source-depth: 1
|
source-depth: 1
|
||||||
plugin: cmake
|
plugin: cmake
|
||||||
build-environment:
|
|
||||||
- PATH: /snap/bin:${PATH}
|
|
||||||
build-snaps:
|
|
||||||
- cmake
|
|
||||||
build-packages:
|
build-packages:
|
||||||
- libssl-dev
|
- libssl-dev
|
||||||
cmake-parameters:
|
cmake-parameters:
|
||||||
@@ -122,10 +113,6 @@ parts:
|
|||||||
source-tag: 'v0.3.0'
|
source-tag: 'v0.3.0'
|
||||||
source-depth: 1
|
source-depth: 1
|
||||||
plugin: cmake
|
plugin: cmake
|
||||||
build-environment:
|
|
||||||
- PATH: /snap/bin:${PATH}
|
|
||||||
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
|
|
||||||
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
|
|
||||||
cmake-parameters:
|
cmake-parameters:
|
||||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
- -DCMAKE_BUILD_TYPE=Release
|
- -DCMAKE_BUILD_TYPE=Release
|
||||||
@@ -143,12 +130,9 @@ parts:
|
|||||||
- kquickimageeditor
|
- kquickimageeditor
|
||||||
parse-info:
|
parse-info:
|
||||||
- usr/share/metainfo/org.kde.neochat.appdata.xml
|
- usr/share/metainfo/org.kde.neochat.appdata.xml
|
||||||
source: .
|
source: https://invent.kde.org/network/neochat.git
|
||||||
|
source-tag: 'v24.08.1'
|
||||||
plugin: cmake
|
plugin: cmake
|
||||||
build-environment:
|
|
||||||
- PATH: /snap/bin:${PATH}
|
|
||||||
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
|
|
||||||
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
|
|
||||||
build-packages:
|
build-packages:
|
||||||
- cmark
|
- cmark
|
||||||
- libcmark-dev
|
- libcmark-dev
|
||||||
@@ -172,12 +156,3 @@ parts:
|
|||||||
prime:
|
prime:
|
||||||
- usr/lib/*/libcmark.so*
|
- usr/lib/*/libcmark.so*
|
||||||
|
|
||||||
gpu-2404:
|
|
||||||
after: [neochat]
|
|
||||||
source: https://github.com/canonical/gpu-snap.git
|
|
||||||
plugin: dump
|
|
||||||
override-prime: |
|
|
||||||
craftctl default
|
|
||||||
${CRAFT_PART_SRC}/bin/gpu-2404-cleanup mesa-2404
|
|
||||||
prime:
|
|
||||||
- bin/gpu-2404-wrapper
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ endif()
|
|||||||
add_library(neochat STATIC
|
add_library(neochat STATIC
|
||||||
controller.cpp
|
controller.cpp
|
||||||
controller.h
|
controller.h
|
||||||
|
actionshandler.cpp
|
||||||
|
actionshandler.h
|
||||||
models/emojimodel.cpp
|
models/emojimodel.cpp
|
||||||
models/emojimodel.h
|
models/emojimodel.h
|
||||||
emojitones.cpp
|
emojitones.cpp
|
||||||
@@ -200,12 +202,6 @@ set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
|||||||
QT_QML_SINGLETON_TYPE TRUE
|
QT_QML_SINGLETON_TYPE TRUE
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ANDROID OR WIN32)
|
|
||||||
set_source_files_properties(qml/ShareActionStub.qml PROPERTIES
|
|
||||||
QT_QML_SOURCE_TYPENAME ShareAction
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
||||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
|
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
|
||||||
QML_FILES
|
QML_FILES
|
||||||
@@ -317,9 +313,13 @@ if(NOT ANDROID AND NOT WIN32)
|
|||||||
qml/EditMenu.qml
|
qml/EditMenu.qml
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
|
set_source_files_properties(qml/ShareActionStub.qml PROPERTIES
|
||||||
|
QT_RESOURCE_ALIAS qml/ShareAction.qml
|
||||||
|
)
|
||||||
qt_target_qml_sources(neochat QML_FILES qml/ShareActionStub.qml)
|
qt_target_qml_sources(neochat QML_FILES qml/ShareActionStub.qml)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
configure_file(config-neochat.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-neochat.h)
|
configure_file(config-neochat.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-neochat.h)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
@@ -418,7 +418,6 @@ target_link_libraries(neochat PUBLIC
|
|||||||
KF6::ConfigGui
|
KF6::ConfigGui
|
||||||
KF6::CoreAddons
|
KF6::CoreAddons
|
||||||
KF6::SonnetCore
|
KF6::SonnetCore
|
||||||
KF6::IconThemes
|
|
||||||
KF6::ColorScheme
|
KF6::ColorScheme
|
||||||
KF6::ItemModels
|
KF6::ItemModels
|
||||||
QuotientQt6
|
QuotientQt6
|
||||||
@@ -492,7 +491,6 @@ if(ANDROID)
|
|||||||
"network-connect"
|
"network-connect"
|
||||||
"list-remove-user"
|
"list-remove-user"
|
||||||
"org.kde.neochat"
|
"org.kde.neochat"
|
||||||
"org.kde.neochat.tray"
|
|
||||||
"preferences-system-users"
|
"preferences-system-users"
|
||||||
"preferences-desktop-theme-global"
|
"preferences-desktop-theme-global"
|
||||||
"notifications"
|
"notifications"
|
||||||
@@ -530,13 +528,11 @@ if(ANDROID)
|
|||||||
"object-rotate-left"
|
"object-rotate-left"
|
||||||
"object-rotate-right"
|
"object-rotate-right"
|
||||||
"add-subtitle"
|
"add-subtitle"
|
||||||
"security-high"
|
|
||||||
"security-low"
|
"security-low"
|
||||||
"security-low-symbolic"
|
"security-low-symbolic"
|
||||||
"kde"
|
"kde"
|
||||||
"list-remove-symbolic"
|
"list-remove-symbolic"
|
||||||
"edit-delete"
|
"edit-delete"
|
||||||
"user-home-symbolic"
|
|
||||||
)
|
)
|
||||||
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
|
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
|
||||||
else()
|
else()
|
||||||
|
|||||||
144
src/actionshandler.cpp
Normal file
144
src/actionshandler.cpp
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
|
||||||
|
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "actionshandler.h"
|
||||||
|
|
||||||
|
#include "chatbarcache.h"
|
||||||
|
#include "models/actionsmodel.h"
|
||||||
|
#include "neochatconfig.h"
|
||||||
|
#include "texthandler.h"
|
||||||
|
|
||||||
|
using namespace Quotient;
|
||||||
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
|
void ActionsHandler::handleMessageEvent(NeoChatRoom *room, ChatBarCache *chatBarCache)
|
||||||
|
{
|
||||||
|
if (room == nullptr || chatBarCache == nullptr) {
|
||||||
|
qWarning() << "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chatBarCache->attachmentPath().isEmpty()) {
|
||||||
|
QUrl url(chatBarCache->attachmentPath());
|
||||||
|
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
||||||
|
room->uploadFile(QUrl(path), chatBarCache->text().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : chatBarCache->text());
|
||||||
|
chatBarCache->setAttachmentPath({});
|
||||||
|
chatBarCache->setText({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto handledText = handleMentions(chatBarCache);
|
||||||
|
const auto result = handleQuickEdit(room, handledText);
|
||||||
|
if (!result) {
|
||||||
|
handleMessage(room, handledText, chatBarCache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ActionsHandler::handleMentions(ChatBarCache *chatBarCache)
|
||||||
|
{
|
||||||
|
const auto mentions = chatBarCache->mentions();
|
||||||
|
std::sort(mentions->begin(), mentions->end(), [](const auto &a, const auto &b) -> bool {
|
||||||
|
return a.cursor.anchor() > b.cursor.anchor();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto handledText = chatBarCache->text();
|
||||||
|
for (const auto &mention : *mentions) {
|
||||||
|
if (mention.text.isEmpty() || mention.id.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
handledText = handledText.replace(mention.cursor.anchor(),
|
||||||
|
mention.cursor.position() - mention.cursor.anchor(),
|
||||||
|
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text.toHtmlEscaped(), mention.id));
|
||||||
|
}
|
||||||
|
mentions->clear();
|
||||||
|
|
||||||
|
return handledText;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionsHandler::handleQuickEdit(NeoChatRoom *room, const QString &handledText)
|
||||||
|
{
|
||||||
|
if (room == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NeoChatConfig::allowQuickEdit()) {
|
||||||
|
QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$"));
|
||||||
|
auto match = sed.match(handledText);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
const QString regex = match.captured(1);
|
||||||
|
const QString replacement = match.captured(2).toHtmlEscaped();
|
||||||
|
const QString flags = match.captured(3);
|
||||||
|
|
||||||
|
for (auto it = room->messageEvents().crbegin(); it != room->messageEvents().crend(); it++) {
|
||||||
|
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
|
if (event->senderId() == room->localMember().id() && event->has<EventContent::TextContent>()) {
|
||||||
|
#else
|
||||||
|
if (event->senderId() == room->localMember().id() && event->hasTextContent()) {
|
||||||
|
#endif
|
||||||
|
QString originalString;
|
||||||
|
if (event->content()) {
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
|
originalString = event->get<EventContent::TextContent>()->body;
|
||||||
|
#else
|
||||||
|
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
originalString = event->plainBody();
|
||||||
|
}
|
||||||
|
if (flags == "/g"_L1) {
|
||||||
|
room->postHtmlMessage(handledText, originalString.replace(regex, replacement), event->msgtype(), {}, event->id());
|
||||||
|
} else {
|
||||||
|
room->postHtmlMessage(handledText,
|
||||||
|
originalString.replace(originalString.indexOf(regex), regex.size(), replacement),
|
||||||
|
event->msgtype(),
|
||||||
|
{},
|
||||||
|
event->id());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionsHandler::handleMessage(NeoChatRoom *room, QString handledText, ChatBarCache *chatBarCache)
|
||||||
|
{
|
||||||
|
if (room == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto messageType = RoomMessageEvent::MsgType::Text;
|
||||||
|
|
||||||
|
if (handledText.startsWith(QLatin1Char('/'))) {
|
||||||
|
for (const auto &action : ActionsModel::instance().allActions()) {
|
||||||
|
if (handledText.indexOf(action.prefix) == 1
|
||||||
|
&& (handledText.indexOf(" "_ls) == action.prefix.length() + 1 || handledText.length() == action.prefix.length() + 1)) {
|
||||||
|
handledText = action.handle(handledText.mid(action.prefix.length() + 1).trimmed(), room, chatBarCache);
|
||||||
|
if (action.messageType.has_value()) {
|
||||||
|
messageType = *action.messageType;
|
||||||
|
}
|
||||||
|
if (action.messageAction) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextHandler textHandler;
|
||||||
|
textHandler.setData(handledText);
|
||||||
|
handledText = textHandler.handleSendText();
|
||||||
|
|
||||||
|
if (handledText.length() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
room->postMessage(chatBarCache->text(), handledText, messageType, chatBarCache->replyId(), chatBarCache->editId(), chatBarCache->threadId());
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_actionshandler.cpp"
|
||||||
43
src/actionshandler.h
Normal file
43
src/actionshandler.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
|
||||||
|
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class ChatBarCache;
|
||||||
|
class NeoChatRoom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class ActionsHandler
|
||||||
|
*
|
||||||
|
* This class contains functions to handle chat messages ready for posting to a room.
|
||||||
|
*
|
||||||
|
* Everything that needs to be done to prepare the message for posting in a room
|
||||||
|
* including:
|
||||||
|
* - File handling
|
||||||
|
* - User mentions
|
||||||
|
* - Quick edits
|
||||||
|
* - Chat actions
|
||||||
|
* - Custom emojis
|
||||||
|
*
|
||||||
|
* @note A chat action is a message starting with /, resulting in something other
|
||||||
|
* than a normal message being sent (e.g. /me, /join).
|
||||||
|
*
|
||||||
|
* @sa ActionsModel, NeoChatRoom
|
||||||
|
*/
|
||||||
|
class ActionsHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Pre-process text and send message event.
|
||||||
|
*/
|
||||||
|
static void handleMessageEvent(NeoChatRoom *room, ChatBarCache *chatBarCache);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QString handleMentions(ChatBarCache *chatBarCache);
|
||||||
|
static bool handleQuickEdit(NeoChatRoom *room, const QString &handledText);
|
||||||
|
|
||||||
|
static void handleMessage(NeoChatRoom *room, QString handledText, ChatBarCache *chatBarCache);
|
||||||
|
};
|
||||||
@@ -176,14 +176,13 @@ QQC2.Control {
|
|||||||
RowLayout {
|
RowLayout {
|
||||||
QQC2.ScrollView {
|
QQC2.ScrollView {
|
||||||
id: chatBarScrollView
|
id: chatBarScrollView
|
||||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
|
||||||
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
|
||||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
|
||||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.maximumHeight: Kirigami.Units.gridUnit * 8
|
Layout.maximumHeight: Kirigami.Units.gridUnit * 8
|
||||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 3
|
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||||
|
Layout.minimumHeight: Kirigami.Units.gridUnit * 2
|
||||||
|
|
||||||
// HACK: This is to stop the ScrollBar flickering on and off as the height is increased
|
// HACK: This is to stop the ScrollBar flickering on and off as the height is increased
|
||||||
QQC2.ScrollBar.vertical.policy: chatBarHeightAnimation.running && implicitHeight <= height ? QQC2.ScrollBar.AlwaysOff : QQC2.ScrollBar.AsNeeded
|
QQC2.ScrollBar.vertical.policy: chatBarHeightAnimation.running && implicitHeight <= height ? QQC2.ScrollBar.AlwaysOff : QQC2.ScrollBar.AsNeeded
|
||||||
@@ -252,22 +251,20 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Keys.onEnterPressed: event => {
|
Keys.onEnterPressed: event => {
|
||||||
const controlIsPressed = event.modifiers & Qt.ControlModifier;
|
|
||||||
if (completionMenu.visible) {
|
if (completionMenu.visible) {
|
||||||
completionMenu.complete();
|
completionMenu.complete();
|
||||||
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile || NeoChatConfig.sendMessageWith === 1 && !controlIsPressed || NeoChatConfig.sendMessageWith === 0 && controlIsPressed) {
|
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile) {
|
||||||
textField.insert(cursorPosition, "\n");
|
textField.insert(cursorPosition, "\n");
|
||||||
} else if (NeoChatConfig.sendMessageWith === 0 && !controlIsPressed || NeoChatConfig.sendMessageWith === 1 && controlIsPressed) {
|
} else {
|
||||||
_private.postMessage();
|
_private.postMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Keys.onReturnPressed: event => {
|
Keys.onReturnPressed: event => {
|
||||||
const controlIsPressed = event.modifiers & Qt.ControlModifier;
|
|
||||||
if (completionMenu.visible) {
|
if (completionMenu.visible) {
|
||||||
completionMenu.complete();
|
completionMenu.complete();
|
||||||
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile || NeoChatConfig.sendMessageWith === 1 && !controlIsPressed || NeoChatConfig.sendMessageWith === 0 && controlIsPressed) {
|
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile) {
|
||||||
textField.insert(cursorPosition, "\n");
|
textField.insert(cursorPosition, "\n");
|
||||||
} else if (NeoChatConfig.sendMessageWith === 0 && !controlIsPressed || NeoChatConfig.sendMessageWith === 1 && controlIsPressed) {
|
} else {
|
||||||
_private.postMessage();
|
_private.postMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,11 +318,12 @@ QQC2.Control {
|
|||||||
id: actionsRow
|
id: actionsRow
|
||||||
spacing: 0
|
spacing: 0
|
||||||
Layout.alignment: Qt.AlignBottom
|
Layout.alignment: Qt.AlignBottom
|
||||||
Layout.bottomMargin: Kirigami.Units.smallSpacing * 4
|
Layout.bottomMargin: Kirigami.Units.smallSpacing * 1.5
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.actions
|
model: root.actions
|
||||||
delegate: QQC2.ToolButton {
|
delegate: QQC2.ToolButton {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
icon.name: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
|
icon.name: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
|
||||||
onClicked: modelData.trigger()
|
onClicked: modelData.trigger()
|
||||||
|
|
||||||
@@ -342,6 +340,7 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DelegateSizeHelper {
|
DelegateSizeHelper {
|
||||||
id: chatBarSizeHelper
|
id: chatBarSizeHelper
|
||||||
startBreakpoint: Kirigami.Units.gridUnit * 46
|
startBreakpoint: Kirigami.Units.gridUnit * 46
|
||||||
@@ -406,6 +405,7 @@ QQC2.Control {
|
|||||||
repeatTimer.stop();
|
repeatTimer.stop();
|
||||||
root.currentRoom.markAllMessagesAsRead();
|
root.currentRoom.markAllMessagesAsRead();
|
||||||
textField.clear();
|
textField.clear();
|
||||||
|
_private.chatBarCache.clearRelations();
|
||||||
messageSent();
|
messageSent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,9 +43,6 @@ QQC2.ItemDelegate {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: root.emoji.startsWith("mxc") || root.isImage
|
visible: root.emoji.startsWith("mxc") || root.isImage
|
||||||
source: visible ? root.emoji : ""
|
source: visible ? root.emoji : ""
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
sourceSize.width: width
|
|
||||||
sourceSize.height: height
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ QQC2.ScrollView {
|
|||||||
|
|
||||||
Kirigami.PlaceholderMessage {
|
Kirigami.PlaceholderMessage {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
icon.name: root.stickers ? "stickers" : "preferences-desktop-emoticons"
|
|
||||||
text: root.stickers ? i18n("No stickers") : i18n("No emojis")
|
text: root.stickers ? i18n("No stickers") : i18n("No emojis")
|
||||||
visible: emojis.count === 0
|
visible: emojis.count === 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ ColumnLayout {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: root.categoryIconSize + QQC2.ScrollBar.horizontal.height
|
Layout.preferredHeight: root.categoryIconSize + QQC2.ScrollBar.horizontal.height
|
||||||
QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
|
QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
|
||||||
visible: categories.count !== 0
|
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: categories
|
id: categories
|
||||||
@@ -202,13 +201,8 @@ ColumnLayout {
|
|||||||
width: root.categoryIconSize
|
width: root.categoryIconSize
|
||||||
height: width
|
height: width
|
||||||
checked: stickerModel.packIndex === model.index
|
checked: stickerModel.packIndex === model.index
|
||||||
padding: Kirigami.Units.largeSpacing
|
|
||||||
|
|
||||||
contentItem: Image {
|
contentItem: Image {
|
||||||
source: model.avatarUrl
|
source: model.avatarUrl
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
sourceSize.width: width
|
|
||||||
sourceSize.height: height
|
|
||||||
}
|
}
|
||||||
QQC2.ToolTip.text: model.name
|
QQC2.ToolTip.text: model.name
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
|||||||
@@ -5,11 +5,10 @@
|
|||||||
|
|
||||||
#include <Quotient/roommember.h>
|
#include <Quotient/roommember.h>
|
||||||
|
|
||||||
|
#include "actionshandler.h"
|
||||||
#include "chatdocumenthandler.h"
|
#include "chatdocumenthandler.h"
|
||||||
#include "eventhandler.h"
|
#include "eventhandler.h"
|
||||||
#include "models/actionsmodel.h"
|
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "texthandler.h"
|
|
||||||
|
|
||||||
ChatBarCache::ChatBarCache(QObject *parent)
|
ChatBarCache::ChatBarCache(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
@@ -30,37 +29,6 @@ void ChatBarCache::setText(const QString &text)
|
|||||||
Q_EMIT textChanged();
|
Q_EMIT textChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ChatBarCache::sendText() const
|
|
||||||
{
|
|
||||||
if (!attachmentPath().isEmpty()) {
|
|
||||||
QUrl url(attachmentPath());
|
|
||||||
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
|
||||||
return text().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : text();
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatMentions();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ChatBarCache::formatMentions() const
|
|
||||||
{
|
|
||||||
auto mentions = m_mentions;
|
|
||||||
std::sort(mentions.begin(), mentions.end(), [](const auto &a, const auto &b) {
|
|
||||||
return a.cursor.anchor() > b.cursor.anchor();
|
|
||||||
});
|
|
||||||
|
|
||||||
auto formattedText = text();
|
|
||||||
for (const auto &mention : mentions) {
|
|
||||||
if (mention.text.isEmpty() || mention.id.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
formattedText = formattedText.replace(mention.cursor.anchor(),
|
|
||||||
mention.cursor.position() - mention.cursor.anchor(),
|
|
||||||
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text.toHtmlEscaped(), mention.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return formattedText;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ChatBarCache::isReplying() const
|
bool ChatBarCache::isReplying() const
|
||||||
{
|
{
|
||||||
return m_relationType == Reply && !m_relationId.isEmpty();
|
return m_relationType == Reply && !m_relationId.isEmpty();
|
||||||
@@ -300,36 +268,7 @@ void ChatBarCache::postMessage()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!attachmentPath().isEmpty()) {
|
ActionsHandler::handleMessageEvent(room, this);
|
||||||
room->uploadFile(QUrl(attachmentPath()), sendText());
|
|
||||||
clearCache();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto result = ActionsModel::handleAction(room, this);
|
|
||||||
if (!result.first.has_value()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextHandler textHandler;
|
|
||||||
textHandler.setData(*std::get<std::optional<QString>>(result));
|
|
||||||
const auto sendText = textHandler.handleSendText();
|
|
||||||
|
|
||||||
if (sendText.length() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto type = std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result);
|
|
||||||
room->postMessage(text(), sendText, type ? *type : Quotient::RoomMessageEvent::MsgType::Text, replyId(), editId(), threadId());
|
|
||||||
clearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatBarCache::clearCache()
|
|
||||||
{
|
|
||||||
setText({});
|
|
||||||
m_mentions.clear();
|
|
||||||
m_savedText = QString();
|
|
||||||
clearRelations();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_chatbarcache.cpp"
|
#include "moc_chatbarcache.cpp"
|
||||||
|
|||||||
@@ -153,7 +153,6 @@ public:
|
|||||||
explicit ChatBarCache(QObject *parent = nullptr);
|
explicit ChatBarCache(QObject *parent = nullptr);
|
||||||
|
|
||||||
QString text() const;
|
QString text() const;
|
||||||
QString sendText() const;
|
|
||||||
void setText(const QString &text);
|
void setText(const QString &text);
|
||||||
|
|
||||||
bool isReplying() const;
|
bool isReplying() const;
|
||||||
@@ -216,8 +215,6 @@ Q_SIGNALS:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_text = QString();
|
QString m_text = QString();
|
||||||
QString formatMentions() const;
|
|
||||||
|
|
||||||
QString m_relationId = QString();
|
QString m_relationId = QString();
|
||||||
RelationType m_relationType = RelationType::None;
|
RelationType m_relationType = RelationType::None;
|
||||||
QString m_threadId = QString();
|
QString m_threadId = QString();
|
||||||
@@ -226,6 +223,4 @@ private:
|
|||||||
QString m_savedText;
|
QString m_savedText;
|
||||||
|
|
||||||
QPointer<MessageContentModel> m_relationContentModel;
|
QPointer<MessageContentModel> m_relationContentModel;
|
||||||
|
|
||||||
void clearCache();
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -63,7 +63,11 @@ Controller::Controller(QObject *parent)
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
auto c = new NeoChatConnection(this);
|
auto c = new NeoChatConnection(this);
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("device_1234"), QStringLiteral("token_1234"));
|
c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("device_1234"), QStringLiteral("token_1234"));
|
||||||
|
#else
|
||||||
|
c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("token_1234"));
|
||||||
|
#endif
|
||||||
connect(c, &Connection::connected, this, [c, this]() {
|
connect(c, &Connection::connected, this, [c, this]() {
|
||||||
m_accountRegistry.add(c);
|
m_accountRegistry.add(c);
|
||||||
c->syncLoop();
|
c->syncLoop();
|
||||||
@@ -168,6 +172,7 @@ void Controller::addConnection(NeoChatConnection *c)
|
|||||||
connect(c, &NeoChatConnection::syncDone, this, [this, c]() {
|
connect(c, &NeoChatConnection::syncDone, this, [this, c]() {
|
||||||
m_notificationsManager.handleNotifications(c);
|
m_notificationsManager.handleNotifications(c);
|
||||||
});
|
});
|
||||||
|
connect(c, &NeoChatConnection::showInviteNotification, &m_notificationsManager, &NotificationsManager::postInviteNotification);
|
||||||
|
|
||||||
c->sync();
|
c->sync();
|
||||||
|
|
||||||
@@ -225,7 +230,11 @@ void Controller::invokeLogin()
|
|||||||
Qt::SingleShotConnection);
|
Qt::SingleShotConnection);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
connection->assumeIdentity(account.userId(), account.deviceId(), accessToken);
|
connection->assumeIdentity(account.userId(), account.deviceId(), accessToken);
|
||||||
|
#else
|
||||||
|
connection->assumeIdentity(account.userId(), accessToken);
|
||||||
|
#endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +303,7 @@ bool Controller::supportSystemTray() const
|
|||||||
void Controller::setQuitOnLastWindowClosed()
|
void Controller::setQuitOnLastWindowClosed()
|
||||||
{
|
{
|
||||||
#ifndef Q_OS_ANDROID
|
#ifndef Q_OS_ANDROID
|
||||||
if (supportSystemTray() && NeoChatConfig::self()->systemTray()) {
|
if (NeoChatConfig::self()->systemTray()) {
|
||||||
m_trayIcon = new TrayIcon(this);
|
m_trayIcon = new TrayIcon(this);
|
||||||
m_trayIcon->show();
|
m_trayIcon->show();
|
||||||
} else {
|
} else {
|
||||||
@@ -422,21 +431,21 @@ void Controller::setTestMode(bool test)
|
|||||||
|
|
||||||
void Controller::removeConnection(const QString &userId)
|
void Controller::removeConnection(const QString &userId)
|
||||||
{
|
{
|
||||||
// When loadAccessTokenFromKeyChain() fails m_connectionsLoading won't have an
|
|
||||||
// entry for it so we need to check both separately.
|
|
||||||
if (m_accountsLoading.contains(userId)) {
|
|
||||||
m_accountsLoading.removeAll(userId);
|
|
||||||
Q_EMIT accountsLoadingChanged();
|
|
||||||
}
|
|
||||||
if (m_connectionsLoading.contains(userId) && m_connectionsLoading[userId]) {
|
if (m_connectionsLoading.contains(userId) && m_connectionsLoading[userId]) {
|
||||||
auto connection = m_connectionsLoading[userId];
|
auto connection = m_connectionsLoading[userId];
|
||||||
|
m_accountsLoading.removeAll(userId);
|
||||||
|
Q_EMIT accountsLoadingChanged();
|
||||||
SettingsGroup("Accounts"_ls).remove(userId);
|
SettingsGroup("Accounts"_ls).remove(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Controller::csSupported() const
|
bool Controller::csSupported() const
|
||||||
{
|
{
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
return true;
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::revertToDefaultConfig()
|
void Controller::revertToDefaultConfig()
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Window
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
@@ -24,7 +23,7 @@ ColumnLayout {
|
|||||||
model: root.connection.accountDataEventTypes
|
model: root.connection.accountDataEventTypes
|
||||||
delegate: FormCard.FormButtonDelegate {
|
delegate: FormCard.FormButtonDelegate {
|
||||||
text: modelData
|
text: modelData
|
||||||
onClicked: root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||||
sourceText: root.connection.accountDataJsonString(modelData)
|
sourceText: root.connection.accountDataJsonString(modelData)
|
||||||
}, {
|
}, {
|
||||||
title: i18nc("@title:window", "Event Source"),
|
title: i18nc("@title:window", "Event Source"),
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Window
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
@@ -48,7 +47,7 @@ ColumnLayout {
|
|||||||
model: root.room.accountDataEventTypes
|
model: root.room.accountDataEventTypes
|
||||||
delegate: FormCard.FormButtonDelegate {
|
delegate: FormCard.FormButtonDelegate {
|
||||||
text: modelData
|
text: modelData
|
||||||
onClicked: root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||||
sourceText: root.room.roomAcountDataJson(text)
|
sourceText: root.room.roomAcountDataJson(text)
|
||||||
}, {
|
}, {
|
||||||
title: i18n("Event Source"),
|
title: i18n("Event Source"),
|
||||||
@@ -78,7 +77,7 @@ ColumnLayout {
|
|||||||
if (model.eventCount === 1) {
|
if (model.eventCount === 1) {
|
||||||
openEventSource(model.type, model.stateKey);
|
openEventSource(model.type, model.stateKey);
|
||||||
} else {
|
} else {
|
||||||
root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'StateKeys'), {
|
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'StateKeys'), {
|
||||||
room: root.room,
|
room: root.room,
|
||||||
eventType: model.type
|
eventType: model.type
|
||||||
}, {
|
}, {
|
||||||
@@ -90,7 +89,7 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function openEventSource(type: string, stateKey: string): void {
|
function openEventSource(type: string, stateKey: string): void {
|
||||||
onClicked: root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||||
model: stateModel,
|
model: stateModel,
|
||||||
allowEdit: true,
|
allowEdit: true,
|
||||||
room: root.room,
|
room: root.room,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Window
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
@@ -38,7 +37,7 @@ FormCard.FormCardPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openEventSource(stateKey: string): void {
|
function openEventSource(stateKey: string): void {
|
||||||
root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||||
model: stateKeysModel,
|
model: stateKeysModel,
|
||||||
allowEdit: true,
|
allowEdit: true,
|
||||||
room: root.room,
|
room: root.room,
|
||||||
|
|||||||
@@ -225,10 +225,18 @@ QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
|
|||||||
{
|
{
|
||||||
QString body;
|
QString body;
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
if (event.has<EventContent::FileContent>()) {
|
if (event.has<EventContent::FileContent>()) {
|
||||||
|
#else
|
||||||
|
if (event.hasFileContent()) {
|
||||||
|
#endif
|
||||||
// if filename is given or body is equal to filename,
|
// if filename is given or body is equal to filename,
|
||||||
// then body is a caption
|
// then body is a caption
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
QString filename = event.get<EventContent::FileContent>()->originalName;
|
QString filename = event.get<EventContent::FileContent>()->originalName;
|
||||||
|
#else
|
||||||
|
QString filename = event.content()->fileInfo()->originalName;
|
||||||
|
#endif
|
||||||
QString body = event.plainBody();
|
QString body = event.plainBody();
|
||||||
if (filename.isEmpty() || filename == body) {
|
if (filename.isEmpty() || filename == body) {
|
||||||
return QString();
|
return QString();
|
||||||
@@ -236,8 +244,13 @@ QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
if (event.has<EventContent::TextContent>() && event.content()) {
|
if (event.has<EventContent::TextContent>() && event.content()) {
|
||||||
body = event.get<EventContent::TextContent>()->body;
|
body = event.get<EventContent::TextContent>()->body;
|
||||||
|
#else
|
||||||
|
if (event.hasTextContent() && event.content()) {
|
||||||
|
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
body = event.plainBody();
|
body = event.plainBody();
|
||||||
}
|
}
|
||||||
@@ -464,8 +477,13 @@ QString EventHandler::getMessageBody(const NeoChatRoom *room, const RoomMessageE
|
|||||||
{
|
{
|
||||||
TextHandler textHandler;
|
TextHandler textHandler;
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
if (event.has<EventContent::FileContent>()) {
|
if (event.has<EventContent::FileContent>()) {
|
||||||
QString fileCaption = event.get<EventContent::FileContent>()->originalName;
|
QString fileCaption = event.get<EventContent::FileContent>()->originalName;
|
||||||
|
#else
|
||||||
|
if (event.hasFileContent()) {
|
||||||
|
QString fileCaption = event.content()->fileInfo()->originalName;
|
||||||
|
#endif
|
||||||
if (fileCaption.isEmpty()) {
|
if (fileCaption.isEmpty()) {
|
||||||
fileCaption = event.plainBody();
|
fileCaption = event.plainBody();
|
||||||
} else if (fileCaption != event.plainBody()) {
|
} else if (fileCaption != event.plainBody()) {
|
||||||
@@ -476,8 +494,13 @@ QString EventHandler::getMessageBody(const NeoChatRoom *room, const RoomMessageE
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString body;
|
QString body;
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
if (event.has<EventContent::TextContent>() && event.content()) {
|
if (event.has<EventContent::TextContent>() && event.content()) {
|
||||||
body = event.get<EventContent::TextContent>()->body;
|
body = event.get<EventContent::TextContent>()->body;
|
||||||
|
#else
|
||||||
|
if (event.hasTextContent() && event.content()) {
|
||||||
|
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
body = event.plainBody();
|
body = event.plainBody();
|
||||||
}
|
}
|
||||||
@@ -692,15 +715,28 @@ QVariantMap EventHandler::getMediaInfoForEvent(const NeoChatRoom *room, const Qu
|
|||||||
// Get the file info for the event.
|
// Get the file info for the event.
|
||||||
if (event->is<RoomMessageEvent>()) {
|
if (event->is<RoomMessageEvent>()) {
|
||||||
auto roomMessageEvent = eventCast<const RoomMessageEvent>(event);
|
auto roomMessageEvent = eventCast<const RoomMessageEvent>(event);
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
if (!roomMessageEvent->has<EventContent::FileContentBase>()) {
|
if (!roomMessageEvent->has<EventContent::FileContentBase>()) {
|
||||||
|
#else
|
||||||
|
if (!roomMessageEvent->hasFileContent()) {
|
||||||
|
#endif
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
const auto content = roomMessageEvent->get<EventContent::FileContentBase>();
|
const auto content = roomMessageEvent->get<EventContent::FileContentBase>();
|
||||||
QVariantMap mediaInfo = getMediaInfoFromFileInfo(room, content.get(), eventId, false, false);
|
QVariantMap mediaInfo = getMediaInfoFromFileInfo(room, content.get(), eventId, false, false);
|
||||||
|
#else
|
||||||
|
const auto content = static_cast<const EventContent::FileContent *>(roomMessageEvent->content());
|
||||||
|
QVariantMap mediaInfo = getMediaInfoFromFileInfo(room, content, eventId, false, false);
|
||||||
|
#endif
|
||||||
// if filename isn't specifically given, it is in body
|
// if filename isn't specifically given, it is in body
|
||||||
// https://spec.matrix.org/latest/client-server-api/#mfile
|
// https://spec.matrix.org/latest/client-server-api/#mfile
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
mediaInfo["filename"_ls] = content->commonInfo().originalName.isEmpty() ? roomMessageEvent->plainBody() : content->commonInfo().originalName;
|
mediaInfo["filename"_ls] = content->commonInfo().originalName.isEmpty() ? roomMessageEvent->plainBody() : content->commonInfo().originalName;
|
||||||
|
#else
|
||||||
|
mediaInfo["filename"_ls] = (content->fileInfo()->originalName.isEmpty()) ? roomMessageEvent->plainBody() : content->fileInfo()->originalName;
|
||||||
|
#endif
|
||||||
|
|
||||||
return mediaInfo;
|
return mediaInfo;
|
||||||
} else if (event->is<StickerEvent>()) {
|
} else if (event->is<StickerEvent>()) {
|
||||||
@@ -714,7 +750,11 @@ QVariantMap EventHandler::getMediaInfoForEvent(const NeoChatRoom *room, const Qu
|
|||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
const Quotient::EventContent::FileContentBase *fileContent,
|
const Quotient::EventContent::FileContentBase *fileContent,
|
||||||
|
#else
|
||||||
|
const Quotient::EventContent::TypedBase *fileContent,
|
||||||
|
#endif
|
||||||
const QString &eventId,
|
const QString &eventId,
|
||||||
bool isThumbnail,
|
bool isThumbnail,
|
||||||
bool isSticker)
|
bool isSticker)
|
||||||
@@ -722,10 +762,18 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
|||||||
QVariantMap mediaInfo;
|
QVariantMap mediaInfo;
|
||||||
|
|
||||||
// Get the mxc URL for the media.
|
// Get the mxc URL for the media.
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
if (!fileContent->url().isValid() || fileContent->url().scheme() != QStringLiteral("mxc") || eventId.isEmpty()) {
|
if (!fileContent->url().isValid() || fileContent->url().scheme() != QStringLiteral("mxc") || eventId.isEmpty()) {
|
||||||
|
#else
|
||||||
|
if (!fileContent->fileInfo()->url().isValid() || fileContent->fileInfo()->url().scheme() != QStringLiteral("mxc") || eventId.isEmpty()) {
|
||||||
|
#endif
|
||||||
mediaInfo["source"_ls] = QUrl();
|
mediaInfo["source"_ls] = QUrl();
|
||||||
} else {
|
} else {
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
QUrl source = room->makeMediaUrl(eventId, fileContent->url());
|
QUrl source = room->makeMediaUrl(eventId, fileContent->url());
|
||||||
|
#else
|
||||||
|
QUrl source = room->makeMediaUrl(eventId, fileContent->fileInfo()->url());
|
||||||
|
#endif
|
||||||
|
|
||||||
if (source.isValid()) {
|
if (source.isValid()) {
|
||||||
mediaInfo["source"_ls] = source;
|
mediaInfo["source"_ls] = source;
|
||||||
@@ -742,15 +790,25 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
|||||||
mediaInfo["mimeIcon"_ls] = mimeType.iconName();
|
mediaInfo["mimeIcon"_ls] = mimeType.iconName();
|
||||||
|
|
||||||
// Add media size if available.
|
// Add media size if available.
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
mediaInfo["size"_ls] = fileContent->commonInfo().payloadSize;
|
mediaInfo["size"_ls] = fileContent->commonInfo().payloadSize;
|
||||||
|
#else
|
||||||
|
mediaInfo["size"_ls] = static_cast<const EventContent::FileContent *>(fileContent)->fileInfo()->payloadSize;
|
||||||
|
#endif
|
||||||
|
|
||||||
mediaInfo["isSticker"_ls] = isSticker;
|
mediaInfo["isSticker"_ls] = isSticker;
|
||||||
|
|
||||||
// Add parameter depending on media type.
|
// Add parameter depending on media type.
|
||||||
if (mimeType.name().contains(QStringLiteral("image"))) {
|
if (mimeType.name().contains(QStringLiteral("image"))) {
|
||||||
if (auto castInfo = static_cast<const EventContent::ImageContent *>(fileContent)) {
|
if (auto castInfo = static_cast<const EventContent::ImageContent *>(fileContent)) {
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
mediaInfo["width"_ls] = castInfo->imageSize.width();
|
mediaInfo["width"_ls] = castInfo->imageSize.width();
|
||||||
mediaInfo["height"_ls] = castInfo->imageSize.height();
|
mediaInfo["height"_ls] = castInfo->imageSize.height();
|
||||||
|
#else
|
||||||
|
const auto imageInfo = static_cast<const EventContent::ImageInfo *>(castInfo->fileInfo());
|
||||||
|
mediaInfo["width"_ls] = imageInfo->imageSize.width();
|
||||||
|
mediaInfo["height"_ls] = imageInfo->imageSize.height();
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO: Images in certain formats (e.g. WebP) will be erroneously marked as animated, even if they are static.
|
// TODO: Images in certain formats (e.g. WebP) will be erroneously marked as animated, even if they are static.
|
||||||
mediaInfo["animated"_ls] = QMovie::supportedFormats().contains(mimeType.preferredSuffix().toUtf8());
|
mediaInfo["animated"_ls] = QMovie::supportedFormats().contains(mimeType.preferredSuffix().toUtf8());
|
||||||
|
|||||||
@@ -290,7 +290,11 @@ private:
|
|||||||
|
|
||||||
static QVariantMap getMediaInfoForEvent(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
static QVariantMap getMediaInfoForEvent(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
||||||
QVariantMap static getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
QVariantMap static getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
const Quotient::EventContent::FileContentBase *fileContent,
|
const Quotient::EventContent::FileContentBase *fileContent,
|
||||||
|
#else
|
||||||
|
const Quotient::EventContent::TypedBase *fileContent,
|
||||||
|
#endif
|
||||||
const QString &eventId,
|
const QString &eventId,
|
||||||
bool isThumbnail = false,
|
bool isThumbnail = false,
|
||||||
bool isSticker = false);
|
bool isSticker = false);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "imagepackevent.h"
|
#include "imagepackevent.h"
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
@@ -10,10 +11,10 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
|
|||||||
{
|
{
|
||||||
if (json.contains(QStringLiteral("pack"))) {
|
if (json.contains(QStringLiteral("pack"))) {
|
||||||
pack = ImagePackEventContent::Pack{
|
pack = ImagePackEventContent::Pack{
|
||||||
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
|
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
|
||||||
fromJson<std::optional<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
|
fromJson<Omittable<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
|
||||||
fromJson<std::optional<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
|
fromJson<Omittable<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
|
||||||
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
pack = std::nullopt;
|
pack = std::nullopt;
|
||||||
@@ -30,9 +31,9 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
|
|||||||
images += ImagePackImage{
|
images += ImagePackImage{
|
||||||
k,
|
k,
|
||||||
fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()),
|
fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()),
|
||||||
fromJson<std::optional<QString>>(json["images"_ls][k]["body"_ls]),
|
fromJson<Omittable<QString>>(json["images"_ls][k]["body"_ls]),
|
||||||
info,
|
info,
|
||||||
fromJson<std::optional<QStringList>>(json["images"_ls][k]["usage"_ls]),
|
fromJson<Omittable<QStringList>>(json["images"_ls][k]["usage"_ls]),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,13 @@
|
|||||||
|
|
||||||
#include <Quotient/accountregistry.h>
|
#include <Quotient/accountregistry.h>
|
||||||
#include <Quotient/e2ee/sssshandler.h>
|
#include <Quotient/e2ee/sssshandler.h>
|
||||||
#include <Quotient/keyimport.h>
|
|
||||||
#include <Quotient/keyverificationsession.h>
|
#include <Quotient/keyverificationsession.h>
|
||||||
#include <Quotient/roommember.h>
|
#include <Quotient/roommember.h>
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
|
#include <Quotient/keyimport.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
|
|
||||||
@@ -40,9 +43,11 @@ struct ForeignSSSSHandler {
|
|||||||
QML_NAMED_ELEMENT(SSSSHandler)
|
QML_NAMED_ELEMENT(SSSSHandler)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
struct ForeignKeyImport {
|
struct ForeignKeyImport {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
QML_SINGLETON
|
QML_SINGLETON
|
||||||
QML_FOREIGN(Quotient::KeyImport)
|
QML_FOREIGN(Quotient::KeyImport)
|
||||||
QML_NAMED_ELEMENT(KeyImport)
|
QML_NAMED_ELEMENT(KeyImport)
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
NeochatAdd3PIdJob::NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const std::optional<QJsonObject> &auth)
|
NeochatAdd3PIdJob::NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Omittable<QJsonObject> &auth)
|
||||||
: BaseJob(HttpVerb::Post, QStringLiteral("Add3PIDJob"), makePath("/_matrix/client/v3", "/account/3pid/add"))
|
: BaseJob(HttpVerb::Post, QStringLiteral("Add3PIDJob"), makePath("/_matrix/client/v3", "/account/3pid/add"))
|
||||||
{
|
{
|
||||||
QJsonObject _dataJson;
|
QJsonObject _dataJson;
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
class NeochatAdd3PIdJob : public Quotient::BaseJob
|
class NeochatAdd3PIdJob : public Quotient::BaseJob
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const std::optional<QJsonObject> &auth = {});
|
explicit NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Quotient::Omittable<QJsonObject> &auth = {});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth)
|
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Omittable<QJsonObject> &auth)
|
||||||
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), "/_matrix/client/r0/account/password")
|
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), "/_matrix/client/r0/account/password")
|
||||||
{
|
{
|
||||||
QJsonObject _data;
|
QJsonObject _data;
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
|
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
class NeochatChangePasswordJob : public Quotient::BaseJob
|
class NeochatChangePasswordJob : public Quotient::BaseJob
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth = {});
|
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Quotient::Omittable<QJsonObject> &auth = {});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth)
|
NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const Omittable<QJsonObject> &auth)
|
||||||
: BaseJob(HttpVerb::Post, QStringLiteral("DisableDeviceJob"), "_matrix/client/v3/account/deactivate")
|
: BaseJob(HttpVerb::Post, QStringLiteral("DisableDeviceJob"), "_matrix/client/v3/account/deactivate")
|
||||||
{
|
{
|
||||||
QJsonObject data;
|
QJsonObject data;
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
class NeoChatDeactivateAccountJob : public Quotient::BaseJob
|
class NeoChatDeactivateAccountJob : public Quotient::BaseJob
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth = {});
|
explicit NeoChatDeactivateAccountJob(const Quotient::Omittable<QJsonObject> &auth = {});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth)
|
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Omittable<QJsonObject> &auth)
|
||||||
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId).toLatin1())
|
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId).toLatin1())
|
||||||
{
|
{
|
||||||
QJsonObject _data;
|
QJsonObject _data;
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
class NeochatDeleteDeviceJob : public Quotient::BaseJob
|
class NeochatDeleteDeviceJob : public Quotient::BaseJob
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth = {});
|
explicit NeochatDeleteDeviceJob(const QString &deviceId, const Quotient::Omittable<QJsonObject> &auth = {});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
|
|
||||||
// TODO: Upstream to libQuotient
|
// TODO: Upstream to libQuotient
|
||||||
class NeochatGetCommonRoomsJob : public Quotient::BaseJob
|
class NeochatGetCommonRoomsJob : public Quotient::BaseJob
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ void LoginHelper::init()
|
|||||||
m_connection = new NeoChatConnection();
|
m_connection = new NeoChatConnection();
|
||||||
m_matrixId = QString();
|
m_matrixId = QString();
|
||||||
m_password = QString();
|
m_password = QString();
|
||||||
m_deviceName = QStringLiteral("NeoChat");
|
m_deviceName = QStringLiteral("NeoChat %1 %2 %3 %4")
|
||||||
|
.arg(QSysInfo::machineHostName(), QSysInfo::productType(), QSysInfo::productVersion(), QSysInfo::currentCpuArchitecture());
|
||||||
m_supportsSso = false;
|
m_supportsSso = false;
|
||||||
m_supportsPassword = false;
|
m_supportsPassword = false;
|
||||||
m_ssoUrl = QUrl();
|
m_ssoUrl = QUrl();
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ LoginStep {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
FormCard.FormTextDelegate {
|
FormCard.FormTextDelegate {
|
||||||
textItem.wrapMode: Text.Wrap
|
|
||||||
text: i18n("Please wait while your messages are loaded from the server. This might take a little while.")
|
text: i18n("Please wait while your messages are loaded from the server. This might take a little while.")
|
||||||
}
|
}
|
||||||
FormCard.AbstractFormDelegate {
|
FormCard.AbstractFormDelegate {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import QtQuick.Layouts
|
|||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
import org.kde.neochat.settings
|
import org.kde.neochat.settings
|
||||||
@@ -17,7 +16,6 @@ Kirigami.Page {
|
|||||||
|
|
||||||
property bool showExisting: false
|
property bool showExisting: false
|
||||||
property bool _showExisting: showExisting && root.currentStepString === root.initialStep
|
property bool _showExisting: showExisting && root.currentStepString === root.initialStep
|
||||||
property bool showSettings: true
|
|
||||||
property alias currentStep: module.item
|
property alias currentStep: module.item
|
||||||
property string currentStepString: initialStep
|
property string currentStepString: initialStep
|
||||||
property string initialStep: "LoginRegister"
|
property string initialStep: "LoginRegister"
|
||||||
@@ -92,27 +90,11 @@ Kirigami.Page {
|
|||||||
id: loadedAccounts
|
id: loadedAccounts
|
||||||
model: AccountRegistry
|
model: AccountRegistry
|
||||||
delegate: FormCard.FormButtonDelegate {
|
delegate: FormCard.FormButtonDelegate {
|
||||||
id: delegate
|
text: model.userId
|
||||||
|
|
||||||
required property string userId
|
|
||||||
required property NeoChatConnection connection
|
|
||||||
|
|
||||||
text: QmlUtils.escapeString(connection.localUser.displayName)
|
|
||||||
description: connection.localUser.id
|
|
||||||
leadingPadding: Kirigami.Units.largeSpacing
|
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Controller.activeConnection = delegate.connection;
|
Controller.activeConnection = model.connection;
|
||||||
root.connectionChosen();
|
root.connectionChosen();
|
||||||
}
|
}
|
||||||
leading: KirigamiComponents.Avatar {
|
|
||||||
id: avatar
|
|
||||||
name: delegate.text
|
|
||||||
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl.
|
|
||||||
source: delegate.connection.localUser.avatarUrl.toString().length > 0 ? delegate.connection.makeMediaUrl(delegate.connection.localUser.avatarUrl) : ""
|
|
||||||
implicitWidth: Kirigami.Units.iconSizes.medium
|
|
||||||
implicitHeight: Kirigami.Units.iconSizes.medium
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Repeater {
|
Repeater {
|
||||||
@@ -266,7 +248,6 @@ Kirigami.Page {
|
|||||||
FormCard.FormCard {
|
FormCard.FormCard {
|
||||||
Layout.topMargin: Kirigami.Units.largeSpacing * 2
|
Layout.topMargin: Kirigami.Units.largeSpacing * 2
|
||||||
maximumWidth: Kirigami.Units.gridUnit * 20
|
maximumWidth: Kirigami.Units.gridUnit * 20
|
||||||
visible: root.showSettings
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
text: i18nc("@action:button", "Settings")
|
text: i18nc("@action:button", "Settings")
|
||||||
icon.name: "settings-configure"
|
icon.name: "settings-configure"
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
#include <KCrash>
|
#include <KCrash>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <KIconTheme>
|
|
||||||
#include <KLocalizedContext>
|
#include <KLocalizedContext>
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
@@ -102,7 +101,6 @@ Q_DECL_EXPORT
|
|||||||
#endif
|
#endif
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
KIconTheme::initTheme();
|
|
||||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||||
|
|
||||||
#ifdef HAVE_WEBVIEW
|
#ifdef HAVE_WEBVIEW
|
||||||
@@ -142,7 +140,7 @@ int main(int argc, char *argv[])
|
|||||||
KAboutData about(QStringLiteral("neochat"),
|
KAboutData about(QStringLiteral("neochat"),
|
||||||
i18n("NeoChat"),
|
i18n("NeoChat"),
|
||||||
QStringLiteral(NEOCHAT_VERSION_STRING),
|
QStringLiteral(NEOCHAT_VERSION_STRING),
|
||||||
i18n("Chat on Matrix"),
|
i18n("Matrix client"),
|
||||||
KAboutLicense::GPL_V3,
|
KAboutLicense::GPL_V3,
|
||||||
i18n("© 2018-2020 Black Hat, 2020-2024 KDE Community"));
|
i18n("© 2018-2020 Black Hat, 2020-2024 KDE Community"));
|
||||||
about.addAuthor(i18n("Carl Schwan"),
|
about.addAuthor(i18n("Carl Schwan"),
|
||||||
|
|||||||
@@ -163,7 +163,11 @@ void AccountEmoticonModel::setEmoticonImage(int index, const QUrl &source)
|
|||||||
QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl source)
|
QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl source)
|
||||||
{
|
{
|
||||||
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
co_await qCoro(job.get(), &BaseJob::finished);
|
co_await qCoro(job.get(), &BaseJob::finished);
|
||||||
|
#else
|
||||||
|
co_await qCoro(job, &BaseJob::finished);
|
||||||
|
#endif
|
||||||
if (job->error() != BaseJob::NoError) {
|
if (job->error() != BaseJob::NoError) {
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
@@ -185,7 +189,11 @@ QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl sourc
|
|||||||
QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString shortcode, QString description, QString type)
|
QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString shortcode, QString description, QString type)
|
||||||
{
|
{
|
||||||
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
co_await qCoro(job.get(), &BaseJob::finished);
|
co_await qCoro(job.get(), &BaseJob::finished);
|
||||||
|
#else
|
||||||
|
co_await qCoro(job, &BaseJob::finished);
|
||||||
|
#endif
|
||||||
if (job->error() != BaseJob::NoError) {
|
if (job->error() != BaseJob::NoError) {
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include "chatbarcache.h"
|
#include "chatbarcache.h"
|
||||||
#include "enums/messagetype.h"
|
#include "enums/messagetype.h"
|
||||||
#include "neochatconfig.h"
|
|
||||||
#include "neochatconnection.h"
|
#include "neochatconnection.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "roommanager.h"
|
#include "roommanager.h"
|
||||||
@@ -18,7 +17,6 @@
|
|||||||
|
|
||||||
using Action = ActionsModel::Action;
|
using Action = ActionsModel::Action;
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
using namespace Qt::StringLiterals;
|
|
||||||
|
|
||||||
QStringList rainbowColors{"#ff2b00"_ls, "#ff5500"_ls, "#ff8000"_ls, "#ffaa00"_ls, "#ffd500"_ls, "#ffff00"_ls, "#d4ff00"_ls, "#aaff00"_ls, "#80ff00"_ls,
|
QStringList rainbowColors{"#ff2b00"_ls, "#ff5500"_ls, "#ff8000"_ls, "#ffaa00"_ls, "#ffd500"_ls, "#ffff00"_ls, "#d4ff00"_ls, "#aaff00"_ls, "#80ff00"_ls,
|
||||||
"#55ff00"_ls, "#2bff00"_ls, "#00ff00"_ls, "#00ff2b"_ls, "#00ff55"_ls, "#00ff80"_ls, "#00ffaa"_ls, "#00ffd5"_ls, "#00ffff"_ls,
|
"#55ff00"_ls, "#2bff00"_ls, "#00ff00"_ls, "#00ff2b"_ls, "#00ff55"_ls, "#00ff80"_ls, "#00ffaa"_ls, "#00ffd5"_ls, "#00ffff"_ls,
|
||||||
@@ -576,78 +574,3 @@ QList<Action> &ActionsModel::allActions() const
|
|||||||
{
|
{
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActionsModel::handleQuickEditAction(NeoChatRoom *room, const QString &messageText)
|
|
||||||
{
|
|
||||||
if (room == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NeoChatConfig::allowQuickEdit()) {
|
|
||||||
QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$"));
|
|
||||||
auto match = sed.match(messageText);
|
|
||||||
if (match.hasMatch()) {
|
|
||||||
const QString regex = match.captured(1);
|
|
||||||
const QString replacement = match.captured(2).toHtmlEscaped();
|
|
||||||
const QString flags = match.captured(3);
|
|
||||||
|
|
||||||
for (auto it = room->messageEvents().crbegin(); it != room->messageEvents().crend(); it++) {
|
|
||||||
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
|
|
||||||
if (event->senderId() == room->localMember().id() && event->has<EventContent::TextContent>()) {
|
|
||||||
QString originalString;
|
|
||||||
if (event->content()) {
|
|
||||||
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content().get())->body;
|
|
||||||
} else {
|
|
||||||
originalString = event->plainBody();
|
|
||||||
}
|
|
||||||
QString replaceId = event->id();
|
|
||||||
const auto eventRelation = event->relatesTo();
|
|
||||||
if (eventRelation && eventRelation->type == "m.replace"_L1) {
|
|
||||||
replaceId = eventRelation->eventId;
|
|
||||||
}
|
|
||||||
if (flags == "/g"_L1) {
|
|
||||||
room->postHtmlMessage(messageText, originalString.replace(regex, replacement), event->msgtype(), {}, replaceId);
|
|
||||||
} else {
|
|
||||||
room->postHtmlMessage(messageText,
|
|
||||||
originalString.replace(originalString.indexOf(regex), regex.size(), replacement),
|
|
||||||
event->msgtype(),
|
|
||||||
{},
|
|
||||||
replaceId);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<std::optional<QString>, std::optional<Quotient::RoomMessageEvent::MsgType>> ActionsModel::handleAction(NeoChatRoom *room, ChatBarCache *chatBarCache)
|
|
||||||
{
|
|
||||||
auto sendText = chatBarCache->sendText();
|
|
||||||
const auto edited = handleQuickEditAction(room, sendText);
|
|
||||||
if (edited) {
|
|
||||||
return std::make_pair(std::nullopt, std::nullopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Quotient::RoomMessageEvent::MsgType> messageType = std::nullopt;
|
|
||||||
if (sendText.startsWith(QLatin1Char('/'))) {
|
|
||||||
for (const auto &action : ActionsModel::instance().allActions()) {
|
|
||||||
if (sendText.indexOf(action.prefix) == 1
|
|
||||||
&& (sendText.indexOf(" "_ls) == action.prefix.length() + 1 || sendText.length() == action.prefix.length() + 1)) {
|
|
||||||
sendText = action.handle(sendText.mid(action.prefix.length() + 1).trimmed(), room, chatBarCache);
|
|
||||||
if (action.messageType.has_value()) {
|
|
||||||
messageType = action.messageType;
|
|
||||||
}
|
|
||||||
if (action.messageAction) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
return std::make_pair(std::nullopt, std::nullopt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(sendText, messageType);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -90,21 +90,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
QList<Action> &allActions() const;
|
QList<Action> &allActions() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle special sed style edit action.
|
|
||||||
*
|
|
||||||
* @return True if the message has a sed edit which was actioned. False otherwise.
|
|
||||||
*/
|
|
||||||
static bool handleQuickEditAction(NeoChatRoom *room, const QString &messageText);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle any action within the message contained in the given ChatBarCache.
|
|
||||||
*
|
|
||||||
* @return A modified or unmodified string that needs to be sent or an empty string if
|
|
||||||
* the handled action replaces sending a normal message.
|
|
||||||
*/
|
|
||||||
static std::pair<std::optional<QString>, std::optional<Quotient::RoomMessageEvent::MsgType>> handleAction(NeoChatRoom *room, ChatBarCache *chatBarCache);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ActionsModel() = default;
|
ActionsModel() = default;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -85,7 +85,13 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
|
|||||||
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
|
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
|
||||||
}
|
}
|
||||||
if (role == IconNameRole) {
|
if (role == IconNameRole) {
|
||||||
return m_filterModel->data(filterIndex, RoomListModel::AvatarRole).toString();
|
auto mediaId = m_filterModel->data(filterIndex, RoomListModel::AvatarRole).toString();
|
||||||
|
if (mediaId.isEmpty()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
if (m_room) {
|
||||||
|
return m_room->connection()->makeMediaUrl(QUrl(QStringLiteral("mxc://%1").arg(mediaId)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_autoCompletionType == Emoji) {
|
if (m_autoCompletionType == Emoji) {
|
||||||
|
|||||||
@@ -129,7 +129,11 @@ void DevicesModel::logout(const QString &deviceId, const QString &password)
|
|||||||
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, m_connection->user()->id()}};
|
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, m_connection->user()->id()}};
|
||||||
authData["identifier"_ls] = identifier;
|
authData["identifier"_ls] = identifier;
|
||||||
auto innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
auto innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
connect(innerJob.get(), &BaseJob::success, this, onSuccess);
|
connect(innerJob.get(), &BaseJob::success, this, onSuccess);
|
||||||
|
#else
|
||||||
|
connect(innerJob, &BaseJob::success, this, onSuccess);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
onSuccess();
|
onSuccess();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -522,10 +522,19 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
|
|||||||
auto fileTransferInfo = m_room->cachedFileTransferInfo(event);
|
auto fileTransferInfo = m_room->cachedFileTransferInfo(event);
|
||||||
|
|
||||||
#ifndef Q_OS_ANDROID
|
#ifndef Q_OS_ANDROID
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
Q_ASSERT(roomMessageEvent->content() != nullptr && roomMessageEvent->has<EventContent::FileContent>());
|
Q_ASSERT(roomMessageEvent->content() != nullptr && roomMessageEvent->has<EventContent::FileContent>());
|
||||||
const QMimeType mimeType = roomMessageEvent->get<EventContent::FileContent>()->mimeType;
|
const QMimeType mimeType = roomMessageEvent->get<EventContent::FileContent>()->mimeType;
|
||||||
|
#else
|
||||||
|
Q_ASSERT(roomMessageEvent->content() != nullptr && roomMessageEvent->hasFileContent());
|
||||||
|
const QMimeType mimeType = roomMessageEvent->content()->fileInfo()->mimeType;
|
||||||
|
#endif
|
||||||
if (mimeType.name() == QStringLiteral("text/plain") || mimeType.parentMimeTypes().contains(QStringLiteral("text/plain"))) {
|
if (mimeType.name() == QStringLiteral("text/plain") || mimeType.parentMimeTypes().contains(QStringLiteral("text/plain"))) {
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
QString originalName = roomMessageEvent->get<EventContent::FileContent>()->originalName;
|
QString originalName = roomMessageEvent->get<EventContent::FileContent>()->originalName;
|
||||||
|
#else
|
||||||
|
QString originalName = roomMessageEvent->content()->fileInfo()->originalName;
|
||||||
|
#endif
|
||||||
if (originalName.isEmpty()) {
|
if (originalName.isEmpty()) {
|
||||||
originalName = roomMessageEvent->plainBody();
|
originalName = roomMessageEvent->plainBody();
|
||||||
}
|
}
|
||||||
@@ -569,22 +578,15 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
|
|||||||
case MessageComponentType::Video: {
|
case MessageComponentType::Video: {
|
||||||
if (!event->is<StickerEvent>()) {
|
if (!event->is<StickerEvent>()) {
|
||||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
||||||
const auto fileContent = roomMessageEvent->get<EventContent::FileContentBase>();
|
QList<MessageComponent> components;
|
||||||
if (fileContent != nullptr) {
|
components += MessageComponent{type, QString(), {}};
|
||||||
const auto fileInfo = fileContent->commonInfo();
|
auto body = EventHandler::rawMessageBody(*roomMessageEvent);
|
||||||
const auto body = EventHandler::rawMessageBody(*roomMessageEvent);
|
components += TextHandler().textComponents(body,
|
||||||
// Do not attach the description to the image, if it's the same as the original filename.
|
EventHandler::messageBodyInputFormat(*roomMessageEvent),
|
||||||
if (fileInfo.originalName != body) {
|
m_room,
|
||||||
QList<MessageComponent> components;
|
roomMessageEvent,
|
||||||
components += MessageComponent{type, QString(), {}};
|
roomMessageEvent->isReplaced());
|
||||||
components += TextHandler().textComponents(body,
|
return components;
|
||||||
EventHandler::messageBodyInputFormat(*roomMessageEvent),
|
|
||||||
m_room,
|
|
||||||
roomMessageEvent,
|
|
||||||
roomMessageEvent->isReplaced());
|
|
||||||
return components;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -642,7 +644,7 @@ QList<MessageComponent> MessageContentModel::addLinkPreviews(QList<MessageCompon
|
|||||||
|
|
||||||
void MessageContentModel::closeLinkPreview(int row)
|
void MessageContentModel::closeLinkPreview(int row)
|
||||||
{
|
{
|
||||||
if (row < 0 || row >= m_components.size()) {
|
if (row < 0 || row > m_components.size()) {
|
||||||
qWarning() << "closeLinkPreview() called with row" << row << "which does not exist. m_components.size() =" << m_components.size();
|
qWarning() << "closeLinkPreview() called with row" << row << "which does not exist. m_components.size() =" << m_components.size();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -652,7 +654,6 @@ void MessageContentModel::closeLinkPreview(int row)
|
|||||||
m_removedLinkPreviews += m_components[row].attributes["link"_ls].toUrl();
|
m_removedLinkPreviews += m_components[row].attributes["link"_ls].toUrl();
|
||||||
m_components.remove(row);
|
m_components.remove(row);
|
||||||
m_components.squeeze();
|
m_components.squeeze();
|
||||||
endResetModel();
|
|
||||||
resetContent();
|
resetContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,7 +666,11 @@ void MessageContentModel::updateItineraryModel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event)) {
|
if (auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event)) {
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
if (roomMessageEvent->has<EventContent::FileContent>()) {
|
if (roomMessageEvent->has<EventContent::FileContent>()) {
|
||||||
|
#else
|
||||||
|
if (roomMessageEvent->hasFileContent()) {
|
||||||
|
#endif
|
||||||
auto filePath = m_room->cachedFileTransferInfo(event).localPath;
|
auto filePath = m_room->cachedFileTransferInfo(event).localPath;
|
||||||
if (filePath.isEmpty() && m_itineraryModel != nullptr) {
|
if (filePath.isEmpty() && m_itineraryModel != nullptr) {
|
||||||
delete m_itineraryModel;
|
delete m_itineraryModel;
|
||||||
|
|||||||
@@ -505,8 +505,11 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
|||||||
|
|
||||||
if (role == ProgressInfoRole) {
|
if (role == ProgressInfoRole) {
|
||||||
if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
|
if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
|
||||||
if (e->has<EventContent::FileContent>() || e->has<EventContent::ImageContent>() || e->has<EventContent::VideoContent>()
|
#if Quotient_VERSION_MINOR > 8
|
||||||
|| e->has<EventContent::AudioContent>()) {
|
if (e->has<EventContent::FileContent>()) {
|
||||||
|
#else
|
||||||
|
if (e->hasFileContent()) {
|
||||||
|
#endif
|
||||||
return QVariant::fromValue(m_currentRoom->cachedFileTransferInfo(&evt));
|
return QVariant::fromValue(m_currentRoom->cachedFileTransferInfo(&evt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,7 +311,12 @@ void PushRuleModel::addKeyword(const QString &keyword, const QString &roomId)
|
|||||||
pushConditions.append(keywordCondition);
|
pushConditions.append(keywordCondition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
auto job = m_connection->callApi<Quotient::SetPushRuleJob>(PushRuleKind::kindString(kind),
|
auto job = m_connection->callApi<Quotient::SetPushRuleJob>(PushRuleKind::kindString(kind),
|
||||||
|
#else
|
||||||
|
auto job = m_connection->callApi<Quotient::SetPushRuleJob>(QLatin1String("global"),
|
||||||
|
PushRuleKind::kindString(kind),
|
||||||
|
#endif
|
||||||
keyword,
|
keyword,
|
||||||
actions,
|
actions,
|
||||||
QString(),
|
QString(),
|
||||||
@@ -336,7 +341,11 @@ void PushRuleModel::removeKeyword(const QString &keyword)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto kind = PushRuleKind::kindString(m_rules[index].kind);
|
auto kind = PushRuleKind::kindString(m_rules[index].kind);
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
auto job = m_connection->callApi<Quotient::DeletePushRuleJob>(kind, m_rules[index].id);
|
auto job = m_connection->callApi<Quotient::DeletePushRuleJob>(kind, m_rules[index].id);
|
||||||
|
#else
|
||||||
|
auto job = m_connection->callApi<Quotient::DeletePushRuleJob>(QStringLiteral("global"), kind, m_rules[index].id);
|
||||||
|
#endif
|
||||||
connect(job, &Quotient::BaseJob::failure, this, [this, job, index]() {
|
connect(job, &Quotient::BaseJob::failure, this, [this, job, index]() {
|
||||||
qWarning() << QLatin1String("Unable to remove push rule for keyword %1: ").arg(m_rules[index].id) << job->errorString();
|
qWarning() << QLatin1String("Unable to remove push rule for keyword %1: ").arg(m_rules[index].id) << job->errorString();
|
||||||
});
|
});
|
||||||
@@ -344,10 +353,18 @@ void PushRuleModel::removeKeyword(const QString &keyword)
|
|||||||
|
|
||||||
void PushRuleModel::setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled)
|
void PushRuleModel::setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled)
|
||||||
{
|
{
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
auto job = m_connection->callApi<Quotient::IsPushRuleEnabledJob>(kind, ruleId);
|
auto job = m_connection->callApi<Quotient::IsPushRuleEnabledJob>(kind, ruleId);
|
||||||
|
#else
|
||||||
|
auto job = m_connection->callApi<Quotient::IsPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId);
|
||||||
|
#endif
|
||||||
connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled, this]() {
|
connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled, this]() {
|
||||||
if (job->enabled() != enabled) {
|
if (job->enabled() != enabled) {
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
m_connection->callApi<Quotient::SetPushRuleEnabledJob>(kind, ruleId, enabled);
|
m_connection->callApi<Quotient::SetPushRuleEnabledJob>(kind, ruleId, enabled);
|
||||||
|
#else
|
||||||
|
m_connection->callApi<Quotient::SetPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId, enabled);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -361,7 +378,11 @@ void PushRuleModel::setNotificationRuleActions(const QString &kind, const QStrin
|
|||||||
actions = actionToVariant(action);
|
actions = actionToVariant(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
m_connection->callApi<Quotient::SetPushRuleActionsJob>(kind, ruleId, actions);
|
m_connection->callApi<Quotient::SetPushRuleActionsJob>(kind, ruleId, actions);
|
||||||
|
#else
|
||||||
|
m_connection->callApi<Quotient::SetPushRuleActionsJob>(QStringLiteral("global"), kind, ruleId, actions);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
PushRuleAction::Action PushRuleModel::variantToAction(const QList<QVariant> &actions, bool enabled)
|
PushRuleAction::Action PushRuleModel::variantToAction(const QList<QVariant> &actions, bool enabled)
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
|
|||||||
return room->displayName().toHtmlEscaped();
|
return room->displayName().toHtmlEscaped();
|
||||||
}
|
}
|
||||||
if (role == AvatarRole) {
|
if (role == AvatarRole) {
|
||||||
return room->avatarMediaUrl();
|
return room->avatarMediaId();
|
||||||
}
|
}
|
||||||
if (role == CanonicalAliasRole) {
|
if (role == CanonicalAliasRole) {
|
||||||
return room->canonicalAlias();
|
return room->canonicalAlias();
|
||||||
|
|||||||
@@ -286,7 +286,6 @@ QHash<int, QByteArray> RoomTreeModel::roleNames() const
|
|||||||
roles[IconRole] = "icon";
|
roles[IconRole] = "icon";
|
||||||
roles[AttentionRole] = "attention";
|
roles[AttentionRole] = "attention";
|
||||||
roles[FavouriteRole] = "favourite";
|
roles[FavouriteRole] = "favourite";
|
||||||
roles[RoomTypeRole] = "roomType";
|
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,7 +323,7 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
|
|||||||
return room->displayName();
|
return room->displayName();
|
||||||
}
|
}
|
||||||
if (role == AvatarRole) {
|
if (role == AvatarRole) {
|
||||||
return room->avatarMediaUrl();
|
return room->avatarMediaId();
|
||||||
}
|
}
|
||||||
if (role == CanonicalAliasRole) {
|
if (role == CanonicalAliasRole) {
|
||||||
return room->canonicalAlias();
|
return room->canonicalAlias();
|
||||||
@@ -386,11 +385,6 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
|
|||||||
if (role == FavouriteRole) {
|
if (role == FavouriteRole) {
|
||||||
return room->isFavourite();
|
return room->isFavourite();
|
||||||
}
|
}
|
||||||
if (role == RoomTypeRole) {
|
|
||||||
if (room->creation()) {
|
|
||||||
return room->creation()->contentPart<QString>("type"_L1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ public:
|
|||||||
IconRole,
|
IconRole,
|
||||||
AttentionRole, /**< Whether there are any notifications. */
|
AttentionRole, /**< Whether there are any notifications. */
|
||||||
FavouriteRole, /**< Whether the room is favourited. */
|
FavouriteRole, /**< Whether the room is favourited. */
|
||||||
RoomTypeRole, /**< The room's type. */
|
|
||||||
};
|
};
|
||||||
Q_ENUM(EventRoles)
|
Q_ENUM(EventRoles)
|
||||||
explicit RoomTreeModel(QObject *parent = nullptr);
|
explicit RoomTreeModel(QObject *parent = nullptr);
|
||||||
|
|||||||
@@ -157,11 +157,6 @@ bool SortFilterRoomTreeModel::filterAcceptsRow(int source_row, const QModelIndex
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide rooms with defined types, assuming that data-holding rooms have a defined type
|
|
||||||
if (!sourceModel()->data(index, RoomTreeModel::RoomTypeRole).toString().isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static auto config = NeoChatConfig::self();
|
static auto config = NeoChatConfig::self();
|
||||||
if (config->allRoomsInHome() && RoomManager::instance().currentSpace().isEmpty()) {
|
if (config->allRoomsInHome() && RoomManager::instance().currentSpace().isEmpty()) {
|
||||||
return acceptRoom;
|
return acceptRoom;
|
||||||
|
|||||||
@@ -93,7 +93,11 @@ void SpaceChildrenModel::refreshModel()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR >= 9
|
||||||
void SpaceChildrenModel::insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::SpaceHierarchyRoomsChunk> children, const QModelIndex &parent)
|
void SpaceChildrenModel::insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::SpaceHierarchyRoomsChunk> children, const QModelIndex &parent)
|
||||||
|
#else
|
||||||
|
void SpaceChildrenModel::insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::ChildRoomsChunk> children, const QModelIndex &parent)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
SpaceTreeItem *parentItem = getItem(parent);
|
SpaceTreeItem *parentItem = getItem(parent);
|
||||||
|
|
||||||
|
|||||||
@@ -144,5 +144,9 @@ private:
|
|||||||
|
|
||||||
void refreshModel();
|
void refreshModel();
|
||||||
|
|
||||||
|
#if Quotient_VERSION_MINOR >= 9
|
||||||
void insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::SpaceHierarchyRoomsChunk> children, const QModelIndex &parent = QModelIndex());
|
void insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::SpaceHierarchyRoomsChunk> children, const QModelIndex &parent = QModelIndex());
|
||||||
|
#else
|
||||||
|
void insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::ChildRoomsChunk> children, const QModelIndex &parent = QModelIndex());
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <Quotient/events/event.h>
|
#include <Quotient/events/event.h>
|
||||||
#include <Quotient/events/stickerevent.h>
|
#include <Quotient/events/stickerevent.h>
|
||||||
#include <Quotient/jobs/basejob.h>
|
#include <Quotient/jobs/basejob.h>
|
||||||
|
#include <Quotient/omittable.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "chatbarcache.h"
|
#include "chatbarcache.h"
|
||||||
|
|||||||
@@ -87,7 +87,11 @@ QVariant UserListModel::data(const QModelIndex &index, int role) const
|
|||||||
return memberId;
|
return memberId;
|
||||||
}
|
}
|
||||||
if (role == AvatarRole) {
|
if (role == AvatarRole) {
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
return m_currentRoom->member(memberId).avatarUrl();
|
return m_currentRoom->member(memberId).avatarUrl();
|
||||||
|
#else
|
||||||
|
return m_currentRoom->memberAvatar(memberId).url();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (role == ObjectRole) {
|
if (role == ObjectRole) {
|
||||||
return QVariant::fromValue(memberId);
|
return QVariant::fromValue(memberId);
|
||||||
@@ -172,7 +176,11 @@ void UserListModel::refreshAllMembers()
|
|||||||
|
|
||||||
if (m_currentRoom != nullptr) {
|
if (m_currentRoom != nullptr) {
|
||||||
m_members = m_currentRoom->joinedMemberIds();
|
m_members = m_currentRoom->joinedMemberIds();
|
||||||
|
#if Quotient_VERSION_MINOR > 8
|
||||||
MemberSorter sorter;
|
MemberSorter sorter;
|
||||||
|
#else
|
||||||
|
MemberSorter sorter(m_currentRoom);
|
||||||
|
#endif
|
||||||
std::sort(m_members.begin(), m_members.end(), [&sorter, this](const auto &left, const auto &right) {
|
std::sort(m_members.begin(), m_members.end(), [&sorter, this](const auto &left, const auto &right) {
|
||||||
const auto leftPl = m_currentRoom->getUserPowerLevel(left);
|
const auto leftPl = m_currentRoom->getUserPowerLevel(left);
|
||||||
const auto rightPl = m_currentRoom->getUserPowerLevel(right);
|
const auto rightPl = m_currentRoom->getUserPowerLevel(right);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user