Compare commits
213 Commits
work/nvrwh
...
v24.12.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d7a964889 | ||
|
|
2ab2570d94 | ||
|
|
bf81e743f4 | ||
|
|
a85af258fe | ||
|
|
063e7393ac | ||
|
|
dafd02790f | ||
|
|
29dd6b12ec | ||
|
|
9c7a49bf62 | ||
|
|
e3cb592cd1 | ||
|
|
2dc54441ac | ||
|
|
9259e7bb52 | ||
|
|
9212cf3f45 | ||
|
|
49a99058b7 | ||
|
|
b7c9ec9bd2 | ||
|
|
683d1f3487 | ||
|
|
e7563870bf | ||
|
|
59a865e1d3 | ||
|
|
75b6444c1e | ||
|
|
180e927f82 | ||
|
|
fcb32b1974 | ||
|
|
bf9d1e5261 | ||
|
|
d6eb91c476 | ||
|
|
96b03082e3 | ||
|
|
962063e58a | ||
|
|
06a09700a0 | ||
|
|
12657abd03 | ||
|
|
3752c3b872 | ||
|
|
acf3f7030d | ||
|
|
63ed48f283 | ||
|
|
25f2693710 | ||
|
|
2efcc1041b | ||
|
|
1f5823cec0 | ||
|
|
efd18fa2d6 | ||
|
|
98dc2cf41a | ||
|
|
97f27a1ae0 | ||
|
|
46b9566242 | ||
|
|
70ab0374ec | ||
|
|
2b2e991bb8 | ||
|
|
fbf4dfbe35 | ||
|
|
1344e46201 | ||
|
|
728d133b7c | ||
|
|
a41be9e19b | ||
|
|
aa5ece8bfb | ||
|
|
21f5ee74ba | ||
|
|
2e6cf03c15 | ||
|
|
9332910bcb | ||
|
|
157c098af3 | ||
|
|
9fe134e7f0 | ||
|
|
46aaab3fb0 | ||
|
|
a5b37a78a0 | ||
|
|
59699abb94 | ||
|
|
3cc0d89ee5 | ||
|
|
96e83fc71b | ||
|
|
d89019d752 | ||
|
|
51565dfdd2 | ||
|
|
e1d09171d5 | ||
|
|
f86572f880 | ||
|
|
d7451834f3 | ||
|
|
a4767cea7d | ||
|
|
4c43869fd4 | ||
|
|
e603664521 | ||
|
|
369242ab31 | ||
|
|
013773d465 | ||
|
|
20b17a58d3 | ||
|
|
1c4bb79347 | ||
|
|
6d2b49f3eb | ||
|
|
e3d5867da6 | ||
|
|
a046e3ed27 | ||
|
|
5b935c1d33 | ||
|
|
fe6bc5a36e | ||
|
|
c085be4f6e | ||
|
|
1f73a9dc90 | ||
|
|
63206ef1dd | ||
|
|
0d286db0c2 | ||
|
|
7d3f478a74 | ||
|
|
6df2ebd1eb | ||
|
|
252fb6eb21 | ||
|
|
5873092356 | ||
|
|
30822003d1 | ||
|
|
52ae237eb7 | ||
|
|
ee02abfe37 | ||
|
|
f0de235f37 | ||
|
|
9e9fe6d275 | ||
|
|
f4ca5f0f34 | ||
|
|
5f240fa05c | ||
|
|
1e29eca59a | ||
|
|
1f71ec3bf8 | ||
|
|
64c5ad88f6 | ||
|
|
fb5a3c1c5c | ||
|
|
4a5a83f94a | ||
|
|
133edc249f | ||
|
|
da30e66127 | ||
|
|
4516e1e0f4 | ||
|
|
bd80f65163 | ||
|
|
f828ecf282 | ||
|
|
a0483167c5 | ||
|
|
87288f508c | ||
|
|
dc184ed2fd | ||
|
|
49e1bf9ab1 | ||
|
|
74acf3f9dc | ||
|
|
38205d2791 | ||
|
|
81da926d4f | ||
|
|
1018fe5d3f | ||
|
|
58b32dd50f | ||
|
|
82184b895a | ||
|
|
da0f6f78a4 | ||
|
|
cfd06d064c | ||
|
|
a90e9ae92a | ||
|
|
8ab0002057 | ||
|
|
e1840be234 | ||
|
|
d6ecaaa344 | ||
|
|
0c08c2ab89 | ||
|
|
39ff11e059 | ||
|
|
93254431c5 | ||
|
|
fc14a8eac8 | ||
|
|
50759bb3ca | ||
|
|
23134d8e72 | ||
|
|
7cd095f76a | ||
|
|
d5c3054da4 | ||
|
|
ae12c838bd | ||
|
|
51727dd345 | ||
|
|
5611b000fb | ||
|
|
461896e228 | ||
|
|
e388536a03 | ||
|
|
61f22edd86 | ||
|
|
9e368691d6 | ||
|
|
dad2b3ec8f | ||
|
|
8821c37ff8 | ||
|
|
c105170eca | ||
|
|
b07c04eddc | ||
|
|
7aa0f68b10 | ||
|
|
cbdae4c312 | ||
|
|
9210940556 | ||
|
|
d8489527b4 | ||
|
|
64c9cd97de | ||
|
|
119a9890b1 | ||
|
|
69be6b5939 | ||
|
|
112152f2df | ||
|
|
2ef634a6cb | ||
|
|
fd31b4fb74 | ||
|
|
3b12520fa2 | ||
|
|
24718a5f72 | ||
|
|
db62bacc7e | ||
|
|
6500669b67 | ||
|
|
557d151ed4 | ||
|
|
95ffd485b4 | ||
|
|
ebd38fb435 | ||
|
|
a5b999e682 | ||
|
|
41d34fc0e4 | ||
|
|
b51194f90f | ||
|
|
80ac9e1ba7 | ||
|
|
e3874c824a | ||
|
|
6599c6b609 | ||
|
|
13d522221c | ||
|
|
dd8f926f32 | ||
|
|
258312e798 | ||
|
|
43d40c7e75 | ||
|
|
cbcc9a6514 | ||
|
|
625048610b | ||
|
|
fa47b67e3d | ||
|
|
9347a66acf | ||
|
|
317df56ffa | ||
|
|
fed9197716 | ||
|
|
1e892599e9 | ||
|
|
b7229ca0cf | ||
|
|
953b711823 | ||
|
|
01d903efd3 | ||
|
|
241dd81932 | ||
|
|
f6dfe0cbcf | ||
|
|
f10b97139c | ||
|
|
385c5b3405 | ||
|
|
7bc6f906f8 | ||
|
|
b8b1434a95 | ||
|
|
85c7a4bcb3 | ||
|
|
84b698a7e8 | ||
|
|
7b249e9fa6 | ||
|
|
46593ef68f | ||
|
|
b70f73c7d6 | ||
|
|
ece5e34fa2 | ||
|
|
74b400288d | ||
|
|
83f19b0631 | ||
|
|
c905d2d6fb | ||
|
|
d0c1eb2f04 | ||
|
|
d7d9d29c1d | ||
|
|
2a3f019ec6 | ||
|
|
d384d50b0d | ||
|
|
be8cb12bba | ||
|
|
a1aa2918be | ||
|
|
d7536bccb3 | ||
|
|
6b677355e1 | ||
|
|
85d625f6ac | ||
|
|
f5d6f87afe | ||
|
|
31d755f407 | ||
|
|
ebfc20d4b4 | ||
|
|
b83d42103f | ||
|
|
c9856347fe | ||
|
|
7224c92caf | ||
|
|
a84f98c96f | ||
|
|
a40bccc29d | ||
|
|
171897161c | ||
|
|
013ad49e2b | ||
|
|
b357586164 | ||
|
|
5642f3416a | ||
|
|
9bbb1710df | ||
|
|
e2b7679252 | ||
|
|
5c353cd4b5 | ||
|
|
cba6dc994f | ||
|
|
b0c4b7fc2a | ||
|
|
ed7aff1f24 | ||
|
|
33f4be0d88 | ||
|
|
1178cafef0 | ||
|
|
1be97e65b4 | ||
|
|
634cefc694 |
@@ -110,7 +110,7 @@
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/quotient-im/libQuotient.git",
|
||||
"branch": "0.8.x",
|
||||
"tag": "0.9.2",
|
||||
"disable-submodules": true
|
||||
}
|
||||
],
|
||||
|
||||
@@ -14,6 +14,7 @@ Dependencies:
|
||||
'frameworks/kquickcharts': '@latest-kf6'
|
||||
'frameworks/knotifications': '@latest-kf6'
|
||||
'frameworks/kcolorscheme': '@latest-kf6'
|
||||
'frameworks/kiconthemes': '@latest-kf6'
|
||||
'libraries/kquickimageeditor': '@latest-kf6'
|
||||
'frameworks/sonnet': '@latest-kf6'
|
||||
'frameworks/prison': '@latest-kf6'
|
||||
|
||||
@@ -8,8 +8,8 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "12")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "3")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
@@ -66,7 +66,7 @@ if (QT_KNOWN_POLICY_QTP0004)
|
||||
qt_policy(SET QTP0004 NEW)
|
||||
endif ()
|
||||
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme)
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels IconThemes ColorScheme)
|
||||
set_package_properties(KF6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
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)
|
||||
endif()
|
||||
|
||||
find_package(QuotientQt6 0.8.2)
|
||||
find_package(QuotientQt6 0.9)
|
||||
set_package_properties(QuotientQt6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
DESCRIPTION "Qt wrapper around Matrix API"
|
||||
@@ -115,11 +115,6 @@ set_package_properties(QuotientQt6 PROPERTIES
|
||||
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)
|
||||
set_package_properties(cmark PROPERTIES
|
||||
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://flathub.org/apps/details/org.kde.neochat'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a>
|
||||
<a href='https://snapcraft.io/neochat'><img width='190px' alt='Download on the Snap Store' src='https://snapcraft.io/static/images/badges/en/snap-store-black.svg'/></a>
|
||||
<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>
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||
classpath 'com.android.tools.build:gradle:8.6.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,26 @@
|
||||
"!room_id_1234:localhost:1234": {
|
||||
"state": {
|
||||
"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",
|
||||
"state_key": "@user:localhost:1234",
|
||||
@@ -26,6 +46,26 @@
|
||||
},
|
||||
"timeline": {
|
||||
"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",
|
||||
"sender": "@user:localhost:1234",
|
||||
|
||||
@@ -11,11 +11,11 @@ ecm_add_test(
|
||||
TEST_NAME neochatroomtest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
texthandlertest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME texthandlertest
|
||||
)
|
||||
# ecm_add_test(
|
||||
# texthandlertest.cpp
|
||||
# LINK_LIBRARIES neochat Qt::Test
|
||||
# TEST_NAME texthandlertest
|
||||
# )
|
||||
|
||||
ecm_add_test(
|
||||
delegatesizehelpertest.cpp
|
||||
@@ -53,12 +53,6 @@ ecm_add_test(
|
||||
TEST_NAME messageeventmodeltest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
actionshandlertest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME actionshandlertest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
windowcontrollertest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <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,6 +63,7 @@ private Q_SLOTS:
|
||||
void receiveRichEdited();
|
||||
void receiveLineSeparator();
|
||||
void receiveRichCodeUrl();
|
||||
void receiveRichColor();
|
||||
|
||||
void componentOutput_data();
|
||||
void componentOutput();
|
||||
@@ -520,6 +521,25 @@ void TextHandlerTest::receiveRichCodeUrl()
|
||||
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()
|
||||
{
|
||||
QTest::addColumn<QString>("testInputString");
|
||||
@@ -535,7 +555,7 @@ void TextHandlerTest::componentOutput_data()
|
||||
QVariantMap{{QStringLiteral("class"), QStringLiteral("html")}}}};
|
||||
QTest::newRow("quote") << QStringLiteral("<p>Text</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>")
|
||||
<< 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>")
|
||||
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}},
|
||||
MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}}};
|
||||
|
||||
@@ -50,38 +50,33 @@
|
||||
<name xml:lang="x-test">xxNeoChatxx</name>
|
||||
<name xml:lang="zh-CN">NeoChat</name>
|
||||
<name xml:lang="zh-TW">NeoChat</name>
|
||||
<summary>Chat with your friends on matrix</summary>
|
||||
<summary xml:lang="ar">دردش مع أصدقائك على ماتركس</summary>
|
||||
<summary xml:lang="ca">Xategeu amb els vostres amics a Matrix</summary>
|
||||
<summary xml:lang="ca-valencia">Xategeu amb els vostres amics a Matrix</summary>
|
||||
<summary xml:lang="cs">Mluvte se svými přáteli na Matrixu</summary>
|
||||
<summary xml:lang="de">Mit den Freunden auf Matrix unterhalten</summary>
|
||||
<summary xml:lang="el">Συνομιλήστε με τους φίλους σας στο matrix</summary>
|
||||
<summary xml:lang="en-GB">Chat with your friends on matrix</summary>
|
||||
<summary xml:lang="eo">Babilu kun viaj amikoj sur matrix</summary>
|
||||
<summary xml:lang="es">Charle con sus amigos en matrix</summary>
|
||||
<summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary>
|
||||
<summary xml:lang="fi">Keskustelu ystäviesi kanssa Matrixissa</summary>
|
||||
<summary xml:lang="fr">Discuter avec vos ami(e)s sur le réseau Matrix</summary>
|
||||
<summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary>
|
||||
<summary xml:lang="he">התכתבות עם החברים שלך ב־matrix</summary>
|
||||
<summary xml:lang="hu">Csevegjen barátaival a matrixon</summary>
|
||||
<summary xml:lang="ia">Starta Conversation con tu amicos sur matrix</summary>
|
||||
<summary xml:lang="it">Conversa con i tuoi contatti su matrix</summary>
|
||||
<summary xml:lang="ka">ესაუბრეთ მეგობრებს Matrix-ზე</summary>
|
||||
<summary xml:lang="ko">Matrix를 사용하여 친구들과 대화하기</summary>
|
||||
<summary xml:lang="lv">Tērzējiet ar saviem draugiem „Matrix“ tīklā</summary>
|
||||
<summary xml:lang="nl">Met uw vrienden chatten op matrix</summary>
|
||||
<summary xml:lang="nn">Prat med vennar på Matrix</summary>
|
||||
<summary xml:lang="pl">Rozmawiaj ze swoimi znajomymi w Matriksie</summary>
|
||||
<summary xml:lang="sl">Klepet z vašimi prijatelji na matrixu</summary>
|
||||
<summary xml:lang="sv">Chatta med dina vänner på Matrix</summary>
|
||||
<summary xml:lang="ta">மேட்ரிக்ஸு மூலம் உங்கள் நண்பர்களிடம் பேசலாம்</summary>
|
||||
<summary xml:lang="tr">Matrix’te arkadaşlarınızla sohbet edin</summary>
|
||||
<summary xml:lang="uk">Спілкуйтеся з вашими друзями у matrix</summary>
|
||||
<summary xml:lang="x-test">xxChat with your friends on matrixxx</summary>
|
||||
<summary xml:lang="zh-CN">在 Matrix 上与朋友聊天</summary>
|
||||
<summary xml:lang="zh-TW">在 Matrix 上與您的朋友聊天</summary>
|
||||
<summary>Chat on Matrix</summary>
|
||||
<summary xml:lang="ar">دردش على ماتركس</summary>
|
||||
<summary xml:lang="ca">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="eu">Berriketa Matrix-en</summary>
|
||||
<summary xml:lang="fi">Keskustelu Matrixissä</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="it">Chat su Matrix</summary>
|
||||
<summary xml:lang="ka">ისაუბრეთ Matrix-ზე</summary>
|
||||
<summary xml:lang="nl">Chat op Matrix</summary>
|
||||
<summary xml:lang="nn">Prat med via Matrix</summary>
|
||||
<summary xml:lang="pl">Rozmawiaj na Matriksie</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="tr">Matrix Üzerinde Sohbet</summary>
|
||||
<summary xml:lang="uk">Спілкування у Matrix</summary>
|
||||
<summary xml:lang="x-test">xxChat on Matrixxx</summary>
|
||||
<summary xml:lang="zh-TW">在 Matrix 上聊天</summary>
|
||||
<description>
|
||||
<p>NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p>
|
||||
<p xml:lang="ar">نيوتشات هو تطبيق دردشة يتيح لك الاستفادة الكاملة من شبكة Matrix. فهو يوفر لك طريقة آمنة لإرسال الرسائل النصية ومقاطع الفيديو والملفات الصوتية إلى عائلتك وزملائك وأصدقائك.</p>
|
||||
@@ -105,6 +100,7 @@
|
||||
<p xml:lang="nl">NeoChat is een chat-toepassing die u het volledige voordeel van het Matrix-netwerk laat genieten. Het levert u op een veilige manier tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden te verzenden.</p>
|
||||
<p xml:lang="nn">NeoChat er ein prateapp som lèt deg bruka all funksjonalitet i Matrix-nettverket. Du kan utveksla tekst, lyd og videoar med vennar, familie og kollegaar på ein trygg måte.</p>
|
||||
<p xml:lang="pl">NoeChat to aplikacja do rozmów, która umożliwia wykorzystanie wszystkich możliwości Matriksa. Umożliwia wysyłanie wiadomości tekstowych, filmów i dźwięków w bezpieczny sposób do twojej rodziny, kolegów i przyjaciół.</p>
|
||||
<p xml:lang="ru">NeoChat — приложение для общения, предоставляющее все преимущества сети Matrix. С его помощью можно безопасно отправлять текстовые сообщения, видеозаписи и звуковые файлы родственникам, коллегам и друзьям.</p>
|
||||
<p xml:lang="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p>
|
||||
<p xml:lang="sv">NeoChat är ett chattprogram som låter dig dra full nytta av Matrix-nätverket. Det ger dig ett säkert sätt att skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner.</p>
|
||||
<p xml:lang="tr">NeoChat, Matrix ağının tüm özelliklerini kullanan bir sohbet uygulamasıdır. Ailenize, arkadaşlarınıza ve iş arkadaşlarınıza metin iletileri, ses ve video dosyaları göndermenin kolay bir yolunu sunar.</p>
|
||||
@@ -123,7 +119,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="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="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="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="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="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>
|
||||
@@ -198,6 +194,7 @@
|
||||
<li xml:lang="nn">Avstemmingar – MSC3381</li>
|
||||
<li xml:lang="pl">Ankiety - MSC3381</li>
|
||||
<li xml:lang="pt">Inquéritos - MSC3381</li>
|
||||
<li xml:lang="ru">Голосования — MSC3381</li>
|
||||
<li xml:lang="sl">Polls - MSC3381</li>
|
||||
<li xml:lang="sv">Polls - MSC3381</li>
|
||||
<li xml:lang="ta">வாக்கெடுப்புகள் - MSC3381</li>
|
||||
@@ -358,8 +355,10 @@
|
||||
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption>
|
||||
<caption xml:lang="nn">Oppdag nye fellesskap med Matrix Spaces</caption>
|
||||
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
|
||||
<caption xml:lang="ru">Поиск новых сообществ с помощью Matrix Spaces</caption>
|
||||
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
|
||||
<caption xml:lang="sv">Upptäck nya gemenskaper med Matrix Spaces</caption>
|
||||
<caption xml:lang="ta">மேட்ரிக்ஸு இடங்களின் மூலம் புதிய சமூகங்களைக் கண்டுபிடிக்கலாம்</caption>
|
||||
<caption xml:lang="tr">Matrix Alanlar ile yeni topluluklar keşfedin</caption>
|
||||
<caption xml:lang="uk">Пошук нових спільнот за допомогою Matrix Spaces</caption>
|
||||
<caption xml:lang="x-test">xxDiscover new communities with Matrix Spacesxx</caption>
|
||||
@@ -448,6 +447,11 @@
|
||||
<content_attribute id="social-chat">intense</content_attribute>
|
||||
</content_rating>
|
||||
<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.2" date="2024-10-10"/>
|
||||
<release version="24.08.1" date="2024-09-12"/>
|
||||
<release version="24.08.0" date="2024-08-22"/>
|
||||
|
||||
@@ -87,47 +87,33 @@ GenericName[uk]=Клієнт Matrix
|
||||
GenericName[x-test]=xxMatrix Clientxx
|
||||
GenericName[zh_CN]=Matrix 客户端
|
||||
GenericName[zh_TW]=Matrix 用戶端
|
||||
Comment=Client for the Matrix protocol
|
||||
Comment[ar]=عميل لميفاق ماتركس
|
||||
Comment[az]=Matrix protokolu üçün müştəri
|
||||
Comment[ca]=Client per al protocol Matrix
|
||||
Comment[ca@valencia]=Client per al protocol Matrix
|
||||
Comment[de]=Programm für das Matrix-Protokoll
|
||||
Comment[el]=Πελάτης για το πρωτόκολλο Matrix
|
||||
Comment[en_GB]=Client for the Matrix protocol
|
||||
Comment[eo]=Kliento por la Matrix-protokolo
|
||||
Comment[es]=Cliente para el protocolo Matrix
|
||||
Comment[eu]=Matrix protokolorako bezeroa
|
||||
Comment[fi]=Asiakas Matrix-yhteyskäytännölle
|
||||
Comment[fr]=Client pour le protocole « Matrix »
|
||||
Comment[gl]=Cliente para o protocolo Matrix.
|
||||
Comment[he]=לקוח לפרוטוקול Matrix
|
||||
Comment[hu]=Kliens a Matrix protokollhoz
|
||||
Comment[ia]=Cliente per le protocollo de Matrix
|
||||
Comment[id]=Klien untuk protokol Matrix
|
||||
Comment[ie]=Un cliente del protocol Matrix
|
||||
Comment[it]=Client per il protocollo Matrix
|
||||
Comment[ka]=კლიენტი Matrix-ის პროტოკოლისთვის
|
||||
Comment[ko]=Matrix 프로토콜용 클라이언트
|
||||
Comment[lt]=Matrix protokolo kliento programa
|
||||
Comment[lv]=Klients „Matrix“ protokolam
|
||||
Comment[nl]=Client voor het Matrix-protocol
|
||||
Comment[nn]=Klient for Matrix-protokollen
|
||||
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 通訊協定的用戶端
|
||||
Comment=Chat on Matrix
|
||||
Comment[ar]=دردش على ماتركس
|
||||
Comment[ca]=Xat a Matrix
|
||||
Comment[ca@valencia]=Xat a Matrix
|
||||
Comment[de]=Über Matrix unterhalten
|
||||
Comment[en_GB]=Chat on Matrix
|
||||
Comment[eo]=Babilo en Matrix
|
||||
Comment[es]=Chat en Matrix
|
||||
Comment[eu]=Berriketa Matrix-en
|
||||
Comment[fi]=Keskustele Matrixissä
|
||||
Comment[fr]=Clavarder sur Matrix
|
||||
Comment[gl]=Charle en Matrix
|
||||
Comment[he]=התכתבות דרך Matrix
|
||||
Comment[hu]=Csevegés Matrixon
|
||||
Comment[ia]=Conversation en ditecto sur Matrix
|
||||
Comment[it]= su Matrix
|
||||
Comment[ka]=საუბარი Matrix-ზე
|
||||
Comment[nl]=Chat op Matrix
|
||||
Comment[pl]=Rozmawiaj na Matriksie
|
||||
Comment[pt_BR]=Bate papo na Matrix
|
||||
Comment[sl]=Klepet na Matrixu
|
||||
Comment[sv]=Chatta på Matrix
|
||||
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும்
|
||||
Comment[tr]=Matrix üzerinde sohbet edin
|
||||
Comment[uk]=Спілкування у Matrix
|
||||
Comment[zh_CN]=在 Matrix 上聊天
|
||||
Comment[zh_TW]=在 Matrix 上聊天
|
||||
MimeType=x-scheme-handler/matrix;
|
||||
Exec=neochat %u
|
||||
Terminal=false
|
||||
|
||||
888
po/ar/neochat.po
888
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
887
po/az/neochat.po
887
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1172
po/ca/neochat.po
1172
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
876
po/cs/neochat.po
876
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
886
po/da/neochat.po
886
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1234
po/de/neochat.po
1234
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
887
po/el/neochat.po
887
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
968
po/eo/neochat.po
968
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
886
po/es/neochat.po
886
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
948
po/eu/neochat.po
948
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
2163
po/fi/neochat.po
2163
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
898
po/fr/neochat.po
898
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
985
po/gl/neochat.po
985
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
934
po/hu/neochat.po
934
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
884
po/ia/neochat.po
884
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
887
po/id/neochat.po
887
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
887
po/ie/neochat.po
887
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
890
po/it/neochat.po
890
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
867
po/ja/neochat.po
867
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
884
po/ka/neochat.po
884
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
885
po/ko/neochat.po
885
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
867
po/lt/neochat.po
867
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
885
po/lv/neochat.po
885
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
892
po/nl/neochat.po
892
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
1001
po/nn/neochat.po
1001
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
887
po/pa/neochat.po
887
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
894
po/pl/neochat.po
894
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
887
po/pt/neochat.po
887
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2034
po/ru/neochat.po
2034
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
887
po/sk/neochat.po
887
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
884
po/sl/neochat.po
884
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
887
po/sv/neochat.po
887
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1233
po/ta/neochat.po
1233
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1112
po/tr/neochat.po
1112
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
886
po/uk/neochat.po
886
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
|
||||
---
|
||||
name: neochat
|
||||
base: core22
|
||||
base: core24
|
||||
adopt-info: neochat
|
||||
grade: stable
|
||||
confinement: strict
|
||||
@@ -27,6 +27,10 @@ apps:
|
||||
|
||||
compression: lzo
|
||||
|
||||
package-repositories:
|
||||
- type: apt
|
||||
ppa: ubuntu-toolchain-r/test
|
||||
|
||||
slots:
|
||||
session-dbus-interface:
|
||||
interface: dbus
|
||||
@@ -76,6 +80,7 @@ parts:
|
||||
source-depth: 1
|
||||
plugin: cmake
|
||||
build-environment:
|
||||
- PATH: /snap/bin:${PATH}
|
||||
- PKG_CONFIG_PATH: $CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET/pkgconfig:$PKG_CONFIG_PATH
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
@@ -92,9 +97,13 @@ parts:
|
||||
- olm
|
||||
- qtkeychain
|
||||
source: https://github.com/quotient-im/libQuotient.git
|
||||
source-tag: 0.8.2
|
||||
source-tag: 0.9.1
|
||||
source-depth: 1
|
||||
plugin: cmake
|
||||
build-environment:
|
||||
- PATH: /snap/bin:${PATH}
|
||||
build-snaps:
|
||||
- cmake
|
||||
build-packages:
|
||||
- libssl-dev
|
||||
cmake-parameters:
|
||||
@@ -113,6 +122,10 @@ parts:
|
||||
source-tag: 'v0.3.0'
|
||||
source-depth: 1
|
||||
plugin: cmake
|
||||
build-environment:
|
||||
- PATH: /snap/bin:${PATH}
|
||||
- PYTHONPATH: ${CRAFT_STAGE}/lib/python3.12/site-packages:${CRAFT_STAGE}/usr/lib/python3/dist-packages
|
||||
- LD_LIBRARY_PATH: "/snap/mesa-2404/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/kde-qt6-core24-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/libproxy:$LD_LIBRARY_PATH"
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
@@ -130,9 +143,12 @@ parts:
|
||||
- kquickimageeditor
|
||||
parse-info:
|
||||
- usr/share/metainfo/org.kde.neochat.appdata.xml
|
||||
source: https://invent.kde.org/network/neochat.git
|
||||
source-tag: 'v24.08.1'
|
||||
source: .
|
||||
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:
|
||||
- cmark
|
||||
- libcmark-dev
|
||||
@@ -156,3 +172,12 @@ parts:
|
||||
prime:
|
||||
- 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,8 +10,6 @@ endif()
|
||||
add_library(neochat STATIC
|
||||
controller.cpp
|
||||
controller.h
|
||||
actionshandler.cpp
|
||||
actionshandler.h
|
||||
models/emojimodel.cpp
|
||||
models/emojimodel.h
|
||||
emojitones.cpp
|
||||
@@ -202,6 +200,12 @@ set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||
QT_QML_SINGLETON_TYPE TRUE
|
||||
)
|
||||
|
||||
if(ANDROID OR WIN32)
|
||||
set_source_files_properties(qml/ShareActionStub.qml PROPERTIES
|
||||
QT_QML_SOURCE_TYPENAME ShareAction
|
||||
)
|
||||
endif()
|
||||
|
||||
ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
|
||||
QML_FILES
|
||||
@@ -313,13 +317,9 @@ if(NOT ANDROID AND NOT WIN32)
|
||||
qml/EditMenu.qml
|
||||
)
|
||||
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)
|
||||
endif()
|
||||
|
||||
|
||||
configure_file(config-neochat.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-neochat.h)
|
||||
|
||||
if(WIN32)
|
||||
@@ -418,6 +418,7 @@ target_link_libraries(neochat PUBLIC
|
||||
KF6::ConfigGui
|
||||
KF6::CoreAddons
|
||||
KF6::SonnetCore
|
||||
KF6::IconThemes
|
||||
KF6::ColorScheme
|
||||
KF6::ItemModels
|
||||
QuotientQt6
|
||||
@@ -491,6 +492,7 @@ if(ANDROID)
|
||||
"network-connect"
|
||||
"list-remove-user"
|
||||
"org.kde.neochat"
|
||||
"org.kde.neochat.tray"
|
||||
"preferences-system-users"
|
||||
"preferences-desktop-theme-global"
|
||||
"notifications"
|
||||
@@ -528,11 +530,13 @@ if(ANDROID)
|
||||
"object-rotate-left"
|
||||
"object-rotate-right"
|
||||
"add-subtitle"
|
||||
"security-high"
|
||||
"security-low"
|
||||
"security-low-symbolic"
|
||||
"kde"
|
||||
"list-remove-symbolic"
|
||||
"edit-delete"
|
||||
"user-home-symbolic"
|
||||
)
|
||||
ecm_add_android_apk(neochat-app ANDROID_DIR ${CMAKE_SOURCE_DIR}/android)
|
||||
else()
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
// 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 (event->senderId() == room->localMember().id() && event->hasTextContent()) {
|
||||
QString originalString;
|
||||
if (event->content()) {
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content().get())->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"
|
||||
@@ -1,43 +0,0 @@
|
||||
// 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,13 +176,14 @@ QQC2.Control {
|
||||
RowLayout {
|
||||
QQC2.ScrollView {
|
||||
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.maximumHeight: Kirigami.Units.gridUnit * 8
|
||||
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 2
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 3
|
||||
|
||||
// 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
|
||||
@@ -251,20 +252,22 @@ QQC2.Control {
|
||||
}
|
||||
}
|
||||
Keys.onEnterPressed: event => {
|
||||
const controlIsPressed = event.modifiers & Qt.ControlModifier;
|
||||
if (completionMenu.visible) {
|
||||
completionMenu.complete();
|
||||
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile) {
|
||||
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile || NeoChatConfig.sendMessageWith === 1 && !controlIsPressed || NeoChatConfig.sendMessageWith === 0 && controlIsPressed) {
|
||||
textField.insert(cursorPosition, "\n");
|
||||
} else {
|
||||
} else if (NeoChatConfig.sendMessageWith === 0 && !controlIsPressed || NeoChatConfig.sendMessageWith === 1 && controlIsPressed) {
|
||||
_private.postMessage();
|
||||
}
|
||||
}
|
||||
Keys.onReturnPressed: event => {
|
||||
const controlIsPressed = event.modifiers & Qt.ControlModifier;
|
||||
if (completionMenu.visible) {
|
||||
completionMenu.complete();
|
||||
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile) {
|
||||
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile || NeoChatConfig.sendMessageWith === 1 && !controlIsPressed || NeoChatConfig.sendMessageWith === 0 && controlIsPressed) {
|
||||
textField.insert(cursorPosition, "\n");
|
||||
} else {
|
||||
} else if (NeoChatConfig.sendMessageWith === 0 && !controlIsPressed || NeoChatConfig.sendMessageWith === 1 && controlIsPressed) {
|
||||
_private.postMessage();
|
||||
}
|
||||
}
|
||||
@@ -318,12 +321,11 @@ QQC2.Control {
|
||||
id: actionsRow
|
||||
spacing: 0
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
Layout.bottomMargin: Kirigami.Units.smallSpacing * 1.5
|
||||
Layout.bottomMargin: Kirigami.Units.smallSpacing * 4
|
||||
|
||||
Repeater {
|
||||
model: root.actions
|
||||
delegate: QQC2.ToolButton {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
icon.name: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
|
||||
onClicked: modelData.trigger()
|
||||
|
||||
@@ -340,7 +342,6 @@ QQC2.Control {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelegateSizeHelper {
|
||||
id: chatBarSizeHelper
|
||||
startBreakpoint: Kirigami.Units.gridUnit * 46
|
||||
@@ -405,7 +406,6 @@ QQC2.Control {
|
||||
repeatTimer.stop();
|
||||
root.currentRoom.markAllMessagesAsRead();
|
||||
textField.clear();
|
||||
_private.chatBarCache.clearRelations();
|
||||
messageSent();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ QQC2.ItemDelegate {
|
||||
anchors.fill: parent
|
||||
visible: root.emoji.startsWith("mxc") || root.isImage
|
||||
source: visible ? root.emoji : ""
|
||||
fillMode: Image.PreserveAspectFit
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ QQC2.ScrollView {
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
anchors.centerIn: parent
|
||||
icon.name: root.stickers ? "stickers" : "preferences-desktop-emoticons"
|
||||
text: root.stickers ? i18n("No stickers") : i18n("No emojis")
|
||||
visible: emojis.count === 0
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: root.categoryIconSize + QQC2.ScrollBar.horizontal.height
|
||||
QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
|
||||
visible: categories.count !== 0
|
||||
|
||||
ListView {
|
||||
id: categories
|
||||
@@ -201,8 +202,13 @@ ColumnLayout {
|
||||
width: root.categoryIconSize
|
||||
height: width
|
||||
checked: stickerModel.packIndex === model.index
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
|
||||
contentItem: Image {
|
||||
source: model.avatarUrl
|
||||
fillMode: Image.PreserveAspectFit
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
}
|
||||
QQC2.ToolTip.text: model.name
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
|
||||
#include <Quotient/roommember.h>
|
||||
|
||||
#include "actionshandler.h"
|
||||
#include "chatdocumenthandler.h"
|
||||
#include "eventhandler.h"
|
||||
#include "models/actionsmodel.h"
|
||||
#include "neochatroom.h"
|
||||
#include "texthandler.h"
|
||||
|
||||
ChatBarCache::ChatBarCache(QObject *parent)
|
||||
: QObject(parent)
|
||||
@@ -29,6 +30,37 @@ void ChatBarCache::setText(const QString &text)
|
||||
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
|
||||
{
|
||||
return m_relationType == Reply && !m_relationId.isEmpty();
|
||||
@@ -268,7 +300,36 @@ void ChatBarCache::postMessage()
|
||||
return;
|
||||
}
|
||||
|
||||
ActionsHandler::handleMessageEvent(room, this);
|
||||
if (!attachmentPath().isEmpty()) {
|
||||
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"
|
||||
|
||||
@@ -153,6 +153,7 @@ public:
|
||||
explicit ChatBarCache(QObject *parent = nullptr);
|
||||
|
||||
QString text() const;
|
||||
QString sendText() const;
|
||||
void setText(const QString &text);
|
||||
|
||||
bool isReplying() const;
|
||||
@@ -215,6 +216,8 @@ Q_SIGNALS:
|
||||
|
||||
private:
|
||||
QString m_text = QString();
|
||||
QString formatMentions() const;
|
||||
|
||||
QString m_relationId = QString();
|
||||
RelationType m_relationType = RelationType::None;
|
||||
QString m_threadId = QString();
|
||||
@@ -223,4 +226,6 @@ private:
|
||||
QString m_savedText;
|
||||
|
||||
QPointer<MessageContentModel> m_relationContentModel;
|
||||
|
||||
void clearCache();
|
||||
};
|
||||
|
||||
@@ -63,11 +63,7 @@ Controller::Controller(QObject *parent)
|
||||
});
|
||||
} else {
|
||||
auto c = new NeoChatConnection(this);
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
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]() {
|
||||
m_accountRegistry.add(c);
|
||||
c->syncLoop();
|
||||
@@ -172,7 +168,6 @@ void Controller::addConnection(NeoChatConnection *c)
|
||||
connect(c, &NeoChatConnection::syncDone, this, [this, c]() {
|
||||
m_notificationsManager.handleNotifications(c);
|
||||
});
|
||||
connect(c, &NeoChatConnection::showInviteNotification, &m_notificationsManager, &NotificationsManager::postInviteNotification);
|
||||
|
||||
c->sync();
|
||||
|
||||
@@ -230,14 +225,7 @@ void Controller::invokeLogin()
|
||||
Qt::SingleShotConnection);
|
||||
}
|
||||
});
|
||||
connect(connection, &NeoChatConnection::networkError, this, [this](const QString &error, const QString &, int, int) {
|
||||
Q_EMIT errorOccured(i18n("Network Error: %1", error));
|
||||
});
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
connection->assumeIdentity(account.userId(), account.deviceId(), accessToken);
|
||||
#else
|
||||
connection->assumeIdentity(account.userId(), accessToken);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -434,21 +422,21 @@ void Controller::setTestMode(bool test)
|
||||
|
||||
void Controller::removeConnection(const QString &userId)
|
||||
{
|
||||
if (m_connectionsLoading.contains(userId) && m_connectionsLoading[userId]) {
|
||||
auto connection = m_connectionsLoading[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]) {
|
||||
auto connection = m_connectionsLoading[userId];
|
||||
SettingsGroup("Accounts"_ls).remove(userId);
|
||||
}
|
||||
}
|
||||
|
||||
bool Controller::csSupported() const
|
||||
{
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Controller::revertToDefaultConfig()
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
@@ -23,7 +24,7 @@ ColumnLayout {
|
||||
model: root.connection.accountDataEventTypes
|
||||
delegate: FormCard.FormButtonDelegate {
|
||||
text: modelData
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
onClicked: root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
sourceText: root.connection.accountDataJsonString(modelData)
|
||||
}, {
|
||||
title: i18nc("@title:window", "Event Source"),
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
@@ -47,7 +48,7 @@ ColumnLayout {
|
||||
model: root.room.accountDataEventTypes
|
||||
delegate: FormCard.FormButtonDelegate {
|
||||
text: modelData
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
onClicked: root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
sourceText: root.room.roomAcountDataJson(text)
|
||||
}, {
|
||||
title: i18n("Event Source"),
|
||||
@@ -77,7 +78,7 @@ ColumnLayout {
|
||||
if (model.eventCount === 1) {
|
||||
openEventSource(model.type, model.stateKey);
|
||||
} else {
|
||||
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'StateKeys'), {
|
||||
root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'StateKeys'), {
|
||||
room: root.room,
|
||||
eventType: model.type
|
||||
}, {
|
||||
@@ -89,7 +90,7 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
function openEventSource(type: string, stateKey: string): void {
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
onClicked: root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
model: stateModel,
|
||||
allowEdit: true,
|
||||
room: root.room,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
@@ -37,7 +38,7 @@ FormCard.FormCardPage {
|
||||
}
|
||||
|
||||
function openEventSource(stateKey: string): void {
|
||||
applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
model: stateKeysModel,
|
||||
allowEdit: true,
|
||||
room: root.room,
|
||||
|
||||
@@ -225,14 +225,10 @@ QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
|
||||
{
|
||||
QString body;
|
||||
|
||||
if (event.hasFileContent()) {
|
||||
if (event.has<EventContent::FileContent>()) {
|
||||
// if filename is given or body is equal to filename,
|
||||
// then body is a caption
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
QString filename = event.fileContent()->originalName;
|
||||
#else
|
||||
QString filename = event.content()->fileInfo()->originalName;
|
||||
#endif
|
||||
QString filename = event.get<EventContent::FileContent>()->originalName;
|
||||
QString body = event.plainBody();
|
||||
if (filename.isEmpty() || filename == body) {
|
||||
return QString();
|
||||
@@ -240,12 +236,8 @@ QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
|
||||
return body;
|
||||
}
|
||||
|
||||
if (event.hasTextContent() && event.content()) {
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
body = event.richTextContent()->body;
|
||||
#else
|
||||
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
||||
#endif
|
||||
if (event.has<EventContent::TextContent>() && event.content()) {
|
||||
body = event.get<EventContent::TextContent>()->body;
|
||||
} else {
|
||||
body = event.plainBody();
|
||||
}
|
||||
@@ -472,12 +464,8 @@ QString EventHandler::getMessageBody(const NeoChatRoom *room, const RoomMessageE
|
||||
{
|
||||
TextHandler textHandler;
|
||||
|
||||
if (event.hasFileContent()) {
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
QString fileCaption = event.fileContent()->originalName;
|
||||
#else
|
||||
QString fileCaption = event.content()->fileInfo()->originalName;
|
||||
#endif
|
||||
if (event.has<EventContent::FileContent>()) {
|
||||
QString fileCaption = event.get<EventContent::FileContent>()->originalName;
|
||||
if (fileCaption.isEmpty()) {
|
||||
fileCaption = event.plainBody();
|
||||
} else if (fileCaption != event.plainBody()) {
|
||||
@@ -488,12 +476,8 @@ QString EventHandler::getMessageBody(const NeoChatRoom *room, const RoomMessageE
|
||||
}
|
||||
|
||||
QString body;
|
||||
if (event.hasTextContent() && event.content()) {
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
body = event.richTextContent()->body;
|
||||
#else
|
||||
body = static_cast<const EventContent::TextContent *>(event.content())->body;
|
||||
#endif
|
||||
if (event.has<EventContent::TextContent>() && event.content()) {
|
||||
body = event.get<EventContent::TextContent>()->body;
|
||||
} else {
|
||||
body = event.plainBody();
|
||||
}
|
||||
@@ -708,25 +692,15 @@ QVariantMap EventHandler::getMediaInfoForEvent(const NeoChatRoom *room, const Qu
|
||||
// Get the file info for the event.
|
||||
if (event->is<RoomMessageEvent>()) {
|
||||
auto roomMessageEvent = eventCast<const RoomMessageEvent>(event);
|
||||
if (!roomMessageEvent->hasFileContent()) {
|
||||
if (!roomMessageEvent->has<EventContent::FileContentBase>()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
const auto content = roomMessageEvent->content();
|
||||
QVariantMap mediaInfo = getMediaInfoFromFileInfo(room, static_cast<EventContent::FileContent *>(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
|
||||
const auto content = roomMessageEvent->get<EventContent::FileContentBase>();
|
||||
QVariantMap mediaInfo = getMediaInfoFromFileInfo(room, content.get(), eventId, false, false);
|
||||
// if filename isn't specifically given, it is in body
|
||||
// https://spec.matrix.org/latest/client-server-api/#mfile
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
mediaInfo["filename"_ls] =
|
||||
(roomMessageEvent->fileContent()->originalName.isEmpty()) ? roomMessageEvent->plainBody() : roomMessageEvent->fileContent()->originalName;
|
||||
#else
|
||||
mediaInfo["filename"_ls] = (content->fileInfo()->originalName.isEmpty()) ? roomMessageEvent->plainBody() : content->fileInfo()->originalName;
|
||||
#endif
|
||||
mediaInfo["filename"_ls] = content->commonInfo().originalName.isEmpty() ? roomMessageEvent->plainBody() : content->commonInfo().originalName;
|
||||
|
||||
return mediaInfo;
|
||||
} else if (event->is<StickerEvent>()) {
|
||||
@@ -740,11 +714,7 @@ QVariantMap EventHandler::getMediaInfoForEvent(const NeoChatRoom *room, const Qu
|
||||
}
|
||||
|
||||
QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
const Quotient::EventContent::FileContentBase *fileContent,
|
||||
#else
|
||||
const Quotient::EventContent::TypedBase *fileContent,
|
||||
#endif
|
||||
const QString &eventId,
|
||||
bool isThumbnail,
|
||||
bool isSticker)
|
||||
@@ -752,18 +722,10 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
||||
QVariantMap mediaInfo;
|
||||
|
||||
// Get the mxc URL for the media.
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
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();
|
||||
} else {
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
QUrl source = room->makeMediaUrl(eventId, fileContent->url());
|
||||
#else
|
||||
QUrl source = room->makeMediaUrl(eventId, fileContent->fileInfo()->url());
|
||||
#endif
|
||||
|
||||
if (source.isValid()) {
|
||||
mediaInfo["source"_ls] = source;
|
||||
@@ -780,25 +742,15 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
||||
mediaInfo["mimeIcon"_ls] = mimeType.iconName();
|
||||
|
||||
// Add media size if available.
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
mediaInfo["size"_ls] = static_cast<const EventContent::FileContent *>(fileContent)->payloadSize;
|
||||
#else
|
||||
mediaInfo["size"_ls] = static_cast<const EventContent::FileContent *>(fileContent)->fileInfo()->payloadSize;
|
||||
#endif
|
||||
mediaInfo["size"_ls] = fileContent->commonInfo().payloadSize;
|
||||
|
||||
mediaInfo["isSticker"_ls] = isSticker;
|
||||
|
||||
// Add parameter depending on media type.
|
||||
if (mimeType.name().contains(QStringLiteral("image"))) {
|
||||
if (auto castInfo = static_cast<const EventContent::ImageContent *>(fileContent)) {
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
mediaInfo["width"_ls] = castInfo->imageSize.width();
|
||||
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.
|
||||
mediaInfo["animated"_ls] = QMovie::supportedFormats().contains(mimeType.preferredSuffix().toUtf8());
|
||||
|
||||
@@ -290,11 +290,7 @@ private:
|
||||
|
||||
static QVariantMap getMediaInfoForEvent(const NeoChatRoom *room, const Quotient::RoomEvent *event);
|
||||
QVariantMap static getMediaInfoFromFileInfo(const NeoChatRoom *room,
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
const Quotient::EventContent::FileContentBase *fileContent,
|
||||
#else
|
||||
const Quotient::EventContent::TypedBase *fileContent,
|
||||
#endif
|
||||
const QString &eventId,
|
||||
bool isThumbnail = false,
|
||||
bool isSticker = false);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "imagepackevent.h"
|
||||
#include <QJsonObject>
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
@@ -11,10 +10,10 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
|
||||
{
|
||||
if (json.contains(QStringLiteral("pack"))) {
|
||||
pack = ImagePackEventContent::Pack{
|
||||
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
|
||||
fromJson<Omittable<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
|
||||
fromJson<Omittable<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
|
||||
fromJson<Omittable<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
||||
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
|
||||
fromJson<std::optional<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
|
||||
fromJson<std::optional<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
|
||||
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
|
||||
};
|
||||
} else {
|
||||
pack = std::nullopt;
|
||||
@@ -31,9 +30,9 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
|
||||
images += ImagePackImage{
|
||||
k,
|
||||
fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()),
|
||||
fromJson<Omittable<QString>>(json["images"_ls][k]["body"_ls]),
|
||||
fromJson<std::optional<QString>>(json["images"_ls][k]["body"_ls]),
|
||||
info,
|
||||
fromJson<Omittable<QStringList>>(json["images"_ls][k]["usage"_ls]),
|
||||
fromJson<std::optional<QStringList>>(json["images"_ls][k]["usage"_ls]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,10 @@
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/e2ee/sssshandler.h>
|
||||
#include <Quotient/keyimport.h>
|
||||
#include <Quotient/keyverificationsession.h>
|
||||
#include <Quotient/roommember.h>
|
||||
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
#include <Quotient/keyimport.h>
|
||||
#endif
|
||||
|
||||
#include "controller.h"
|
||||
#include "neochatconfig.h"
|
||||
|
||||
@@ -43,11 +40,9 @@ struct ForeignSSSSHandler {
|
||||
QML_NAMED_ELEMENT(SSSSHandler)
|
||||
};
|
||||
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
struct ForeignKeyImport {
|
||||
Q_GADGET
|
||||
QML_SINGLETON
|
||||
QML_FOREIGN(Quotient::KeyImport)
|
||||
QML_NAMED_ELEMENT(KeyImport)
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeochatAdd3PIdJob::NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Omittable<QJsonObject> &auth)
|
||||
NeochatAdd3PIdJob::NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const std::optional<QJsonObject> &auth)
|
||||
: BaseJob(HttpVerb::Post, QStringLiteral("Add3PIDJob"), makePath("/_matrix/client/v3", "/account/3pid/add"))
|
||||
{
|
||||
QJsonObject _dataJson;
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
class NeochatAdd3PIdJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Quotient::Omittable<QJsonObject> &auth = {});
|
||||
explicit NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const std::optional<QJsonObject> &auth = {});
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Omittable<QJsonObject> &auth)
|
||||
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth)
|
||||
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), "/_matrix/client/r0/account/password")
|
||||
{
|
||||
QJsonObject _data;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
class NeochatChangePasswordJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Quotient::Omittable<QJsonObject> &auth = {});
|
||||
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth = {});
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const Omittable<QJsonObject> &auth)
|
||||
NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth)
|
||||
: BaseJob(HttpVerb::Post, QStringLiteral("DisableDeviceJob"), "_matrix/client/v3/account/deactivate")
|
||||
{
|
||||
QJsonObject data;
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
class NeoChatDeactivateAccountJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeoChatDeactivateAccountJob(const Quotient::Omittable<QJsonObject> &auth = {});
|
||||
explicit NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth = {});
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Omittable<QJsonObject> &auth)
|
||||
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth)
|
||||
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId).toLatin1())
|
||||
{
|
||||
QJsonObject _data;
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
class NeochatDeleteDeviceJob : public Quotient::BaseJob
|
||||
{
|
||||
public:
|
||||
explicit NeochatDeleteDeviceJob(const QString &deviceId, const Quotient::Omittable<QJsonObject> &auth = {});
|
||||
explicit NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth = {});
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/omittable.h>
|
||||
|
||||
// TODO: Upstream to libQuotient
|
||||
class NeochatGetCommonRoomsJob : public Quotient::BaseJob
|
||||
|
||||
@@ -25,8 +25,7 @@ void LoginHelper::init()
|
||||
m_connection = new NeoChatConnection();
|
||||
m_matrixId = QString();
|
||||
m_password = QString();
|
||||
m_deviceName = QStringLiteral("NeoChat %1 %2 %3 %4")
|
||||
.arg(QSysInfo::machineHostName(), QSysInfo::productType(), QSysInfo::productVersion(), QSysInfo::currentCpuArchitecture());
|
||||
m_deviceName = QStringLiteral("NeoChat");
|
||||
m_supportsSso = false;
|
||||
m_supportsPassword = false;
|
||||
m_ssoUrl = QUrl();
|
||||
|
||||
@@ -13,6 +13,7 @@ LoginStep {
|
||||
id: root
|
||||
|
||||
FormCard.FormTextDelegate {
|
||||
textItem.wrapMode: Text.Wrap
|
||||
text: i18n("Please wait while your messages are loaded from the server. This might take a little while.")
|
||||
}
|
||||
FormCard.AbstractFormDelegate {
|
||||
|
||||
@@ -7,6 +7,7 @@ import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
||||
|
||||
import org.kde.neochat
|
||||
import org.kde.neochat.settings
|
||||
@@ -16,6 +17,7 @@ Kirigami.Page {
|
||||
|
||||
property bool showExisting: false
|
||||
property bool _showExisting: showExisting && root.currentStepString === root.initialStep
|
||||
property bool showSettings: true
|
||||
property alias currentStep: module.item
|
||||
property string currentStepString: initialStep
|
||||
property string initialStep: "LoginRegister"
|
||||
@@ -90,11 +92,27 @@ Kirigami.Page {
|
||||
id: loadedAccounts
|
||||
model: AccountRegistry
|
||||
delegate: FormCard.FormButtonDelegate {
|
||||
text: model.userId
|
||||
id: delegate
|
||||
|
||||
required property string userId
|
||||
required property NeoChatConnection connection
|
||||
|
||||
text: QmlUtils.escapeString(connection.localUser.displayName)
|
||||
description: connection.localUser.id
|
||||
leadingPadding: Kirigami.Units.largeSpacing
|
||||
|
||||
onClicked: {
|
||||
Controller.activeConnection = model.connection;
|
||||
Controller.activeConnection = delegate.connection;
|
||||
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 {
|
||||
@@ -248,6 +266,7 @@ Kirigami.Page {
|
||||
FormCard.FormCard {
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing * 2
|
||||
maximumWidth: Kirigami.Units.gridUnit * 20
|
||||
visible: root.showSettings
|
||||
FormCard.FormButtonDelegate {
|
||||
text: i18nc("@action:button", "Settings")
|
||||
icon.name: "settings-configure"
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <KCrash>
|
||||
#endif
|
||||
|
||||
#include <KIconTheme>
|
||||
#include <KLocalizedContext>
|
||||
#include <KLocalizedString>
|
||||
|
||||
@@ -101,6 +102,7 @@ Q_DECL_EXPORT
|
||||
#endif
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
KIconTheme::initTheme();
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
|
||||
#ifdef HAVE_WEBVIEW
|
||||
@@ -140,7 +142,7 @@ int main(int argc, char *argv[])
|
||||
KAboutData about(QStringLiteral("neochat"),
|
||||
i18n("NeoChat"),
|
||||
QStringLiteral(NEOCHAT_VERSION_STRING),
|
||||
i18n("Matrix client"),
|
||||
i18n("Chat on Matrix"),
|
||||
KAboutLicense::GPL_V3,
|
||||
i18n("© 2018-2020 Black Hat, 2020-2024 KDE Community"));
|
||||
about.addAuthor(i18n("Carl Schwan"),
|
||||
|
||||
@@ -163,11 +163,7 @@ void AccountEmoticonModel::setEmoticonImage(int index, const QUrl &source)
|
||||
QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl source)
|
||||
{
|
||||
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
co_await qCoro(job.get(), &BaseJob::finished);
|
||||
#else
|
||||
co_await qCoro(job, &BaseJob::finished);
|
||||
#endif
|
||||
if (job->error() != BaseJob::NoError) {
|
||||
co_return;
|
||||
}
|
||||
@@ -189,11 +185,7 @@ QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl sourc
|
||||
QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString shortcode, QString description, QString type)
|
||||
{
|
||||
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
co_await qCoro(job.get(), &BaseJob::finished);
|
||||
#else
|
||||
co_await qCoro(job, &BaseJob::finished);
|
||||
#endif
|
||||
if (job->error() != BaseJob::NoError) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "enums/messagetype.h"
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatconnection.h"
|
||||
#include "neochatroom.h"
|
||||
#include "roommanager.h"
|
||||
#include <Quotient/events/eventcontent.h>
|
||||
#include <Quotient/events/roommemberevent.h>
|
||||
#include <Quotient/events/roompowerlevelsevent.h>
|
||||
#include <Quotient/user.h>
|
||||
@@ -16,6 +18,7 @@
|
||||
|
||||
using Action = ActionsModel::Action;
|
||||
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,
|
||||
"#55ff00"_ls, "#2bff00"_ls, "#00ff00"_ls, "#00ff2b"_ls, "#00ff55"_ls, "#00ff80"_ls, "#00ffaa"_ls, "#00ffd5"_ls, "#00ffff"_ls,
|
||||
@@ -573,3 +576,78 @@ QList<Action> &ActionsModel::allActions() const
|
||||
{
|
||||
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,6 +90,21 @@ public:
|
||||
*/
|
||||
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:
|
||||
ActionsModel() = default;
|
||||
};
|
||||
|
||||
@@ -85,13 +85,7 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
|
||||
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
|
||||
}
|
||||
if (role == IconNameRole) {
|
||||
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)));
|
||||
}
|
||||
return m_filterModel->data(filterIndex, RoomListModel::AvatarRole).toString();
|
||||
}
|
||||
}
|
||||
if (m_autoCompletionType == Emoji) {
|
||||
|
||||
@@ -129,11 +129,7 @@ void DevicesModel::logout(const QString &deviceId, const QString &password)
|
||||
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, m_connection->user()->id()}};
|
||||
authData["identifier"_ls] = identifier;
|
||||
auto innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
connect(innerJob.get(), &BaseJob::success, this, onSuccess);
|
||||
#else
|
||||
connect(innerJob, &BaseJob::success, this, onSuccess);
|
||||
#endif
|
||||
} else {
|
||||
onSuccess();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <QImageReader>
|
||||
|
||||
#include <Quotient/events/eventcontent.h>
|
||||
#include <Quotient/events/redactionevent.h>
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <Quotient/events/stickerevent.h>
|
||||
@@ -521,18 +522,10 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
|
||||
auto fileTransferInfo = m_room->cachedFileTransferInfo(event);
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
Q_ASSERT(roomMessageEvent->content() != nullptr && roomMessageEvent->hasFileContent());
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
const QMimeType mimeType = roomMessageEvent->fileContent()->mimeType;
|
||||
#else
|
||||
const QMimeType mimeType = roomMessageEvent->content()->fileInfo()->mimeType;
|
||||
#endif
|
||||
Q_ASSERT(roomMessageEvent->content() != nullptr && roomMessageEvent->has<EventContent::FileContent>());
|
||||
const QMimeType mimeType = roomMessageEvent->get<EventContent::FileContent>()->mimeType;
|
||||
if (mimeType.name() == QStringLiteral("text/plain") || mimeType.parentMimeTypes().contains(QStringLiteral("text/plain"))) {
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
QString originalName = roomMessageEvent->fileContent()->originalName;
|
||||
#else
|
||||
QString originalName = roomMessageEvent->content()->fileInfo()->originalName;
|
||||
#endif
|
||||
QString originalName = roomMessageEvent->get<EventContent::FileContent>()->originalName;
|
||||
if (originalName.isEmpty()) {
|
||||
originalName = roomMessageEvent->plainBody();
|
||||
}
|
||||
@@ -576,15 +569,22 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
|
||||
case MessageComponentType::Video: {
|
||||
if (!event->is<StickerEvent>()) {
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
||||
QList<MessageComponent> components;
|
||||
components += MessageComponent{type, QString(), {}};
|
||||
auto body = EventHandler::rawMessageBody(*roomMessageEvent);
|
||||
components += TextHandler().textComponents(body,
|
||||
EventHandler::messageBodyInputFormat(*roomMessageEvent),
|
||||
m_room,
|
||||
roomMessageEvent,
|
||||
roomMessageEvent->isReplaced());
|
||||
return components;
|
||||
const auto fileContent = roomMessageEvent->get<EventContent::FileContentBase>();
|
||||
if (fileContent != nullptr) {
|
||||
const auto fileInfo = fileContent->commonInfo();
|
||||
const auto body = EventHandler::rawMessageBody(*roomMessageEvent);
|
||||
// Do not attach the description to the image, if it's the same as the original filename.
|
||||
if (fileInfo.originalName != body) {
|
||||
QList<MessageComponent> components;
|
||||
components += MessageComponent{type, QString(), {}};
|
||||
components += TextHandler().textComponents(body,
|
||||
EventHandler::messageBodyInputFormat(*roomMessageEvent),
|
||||
m_room,
|
||||
roomMessageEvent,
|
||||
roomMessageEvent->isReplaced());
|
||||
return components;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
@@ -642,7 +642,7 @@ QList<MessageComponent> MessageContentModel::addLinkPreviews(QList<MessageCompon
|
||||
|
||||
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();
|
||||
return;
|
||||
}
|
||||
@@ -652,6 +652,7 @@ void MessageContentModel::closeLinkPreview(int row)
|
||||
m_removedLinkPreviews += m_components[row].attributes["link"_ls].toUrl();
|
||||
m_components.remove(row);
|
||||
m_components.squeeze();
|
||||
endResetModel();
|
||||
resetContent();
|
||||
}
|
||||
}
|
||||
@@ -664,7 +665,7 @@ void MessageContentModel::updateItineraryModel()
|
||||
}
|
||||
|
||||
if (auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event)) {
|
||||
if (roomMessageEvent->hasFileContent()) {
|
||||
if (roomMessageEvent->has<EventContent::FileContent>()) {
|
||||
auto filePath = m_room->cachedFileTransferInfo(event).localPath;
|
||||
if (filePath.isEmpty() && m_itineraryModel != nullptr) {
|
||||
delete m_itineraryModel;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "neochatconfig.h"
|
||||
|
||||
#include <Quotient/csapi/rooms.h>
|
||||
#include <Quotient/events/eventcontent.h>
|
||||
#include <Quotient/events/redactionevent.h>
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <Quotient/events/stickerevent.h>
|
||||
@@ -504,7 +505,8 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
|
||||
if (role == ProgressInfoRole) {
|
||||
if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
|
||||
if (e->hasFileContent()) {
|
||||
if (e->has<EventContent::FileContent>() || e->has<EventContent::ImageContent>() || e->has<EventContent::VideoContent>()
|
||||
|| e->has<EventContent::AudioContent>()) {
|
||||
return QVariant::fromValue(m_currentRoom->cachedFileTransferInfo(&evt));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,12 +311,7 @@ void PushRuleModel::addKeyword(const QString &keyword, const QString &roomId)
|
||||
pushConditions.append(keywordCondition);
|
||||
}
|
||||
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
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,
|
||||
actions,
|
||||
QString(),
|
||||
@@ -341,11 +336,7 @@ void PushRuleModel::removeKeyword(const QString &keyword)
|
||||
}
|
||||
|
||||
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);
|
||||
#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]() {
|
||||
qWarning() << QLatin1String("Unable to remove push rule for keyword %1: ").arg(m_rules[index].id) << job->errorString();
|
||||
});
|
||||
@@ -353,18 +344,10 @@ void PushRuleModel::removeKeyword(const QString &keyword)
|
||||
|
||||
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);
|
||||
#else
|
||||
auto job = m_connection->callApi<Quotient::IsPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId);
|
||||
#endif
|
||||
connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled, this]() {
|
||||
if (job->enabled() != enabled) {
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
m_connection->callApi<Quotient::SetPushRuleEnabledJob>(kind, ruleId, enabled);
|
||||
#else
|
||||
m_connection->callApi<Quotient::SetPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId, enabled);
|
||||
#endif
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -378,11 +361,7 @@ void PushRuleModel::setNotificationRuleActions(const QString &kind, const QStrin
|
||||
actions = actionToVariant(action);
|
||||
}
|
||||
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
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)
|
||||
|
||||
@@ -212,7 +212,7 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
|
||||
return room->displayName().toHtmlEscaped();
|
||||
}
|
||||
if (role == AvatarRole) {
|
||||
return room->avatarMediaId();
|
||||
return room->avatarMediaUrl();
|
||||
}
|
||||
if (role == CanonicalAliasRole) {
|
||||
return room->canonicalAlias();
|
||||
|
||||
@@ -286,6 +286,7 @@ QHash<int, QByteArray> RoomTreeModel::roleNames() const
|
||||
roles[IconRole] = "icon";
|
||||
roles[AttentionRole] = "attention";
|
||||
roles[FavouriteRole] = "favourite";
|
||||
roles[RoomTypeRole] = "roomType";
|
||||
return roles;
|
||||
}
|
||||
|
||||
@@ -323,7 +324,7 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
|
||||
return room->displayName();
|
||||
}
|
||||
if (role == AvatarRole) {
|
||||
return room->avatarMediaId();
|
||||
return room->avatarMediaUrl();
|
||||
}
|
||||
if (role == CanonicalAliasRole) {
|
||||
return room->canonicalAlias();
|
||||
@@ -385,6 +386,11 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
|
||||
if (role == FavouriteRole) {
|
||||
return room->isFavourite();
|
||||
}
|
||||
if (role == RoomTypeRole) {
|
||||
if (room->creation()) {
|
||||
return room->creation()->contentPart<QString>("type"_L1);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
IconRole,
|
||||
AttentionRole, /**< Whether there are any notifications. */
|
||||
FavouriteRole, /**< Whether the room is favourited. */
|
||||
RoomTypeRole, /**< The room's type. */
|
||||
};
|
||||
Q_ENUM(EventRoles)
|
||||
explicit RoomTreeModel(QObject *parent = nullptr);
|
||||
|
||||
@@ -157,6 +157,11 @@ bool SortFilterRoomTreeModel::filterAcceptsRow(int source_row, const QModelIndex
|
||||
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();
|
||||
if (config->allRoomsInHome() && RoomManager::instance().currentSpace().isEmpty()) {
|
||||
return acceptRoom;
|
||||
|
||||
@@ -93,11 +93,7 @@ void SpaceChildrenModel::refreshModel()
|
||||
});
|
||||
}
|
||||
|
||||
#if Quotient_VERSION_MINOR >= 9
|
||||
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);
|
||||
|
||||
|
||||
@@ -144,9 +144,5 @@ private:
|
||||
|
||||
void refreshModel();
|
||||
|
||||
#if Quotient_VERSION_MINOR >= 9
|
||||
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,7 +6,6 @@
|
||||
#include <Quotient/events/event.h>
|
||||
#include <Quotient/events/stickerevent.h>
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/omittable.h>
|
||||
#include <memory>
|
||||
|
||||
#include "chatbarcache.h"
|
||||
|
||||
@@ -87,11 +87,7 @@ QVariant UserListModel::data(const QModelIndex &index, int role) const
|
||||
return memberId;
|
||||
}
|
||||
if (role == AvatarRole) {
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
return m_currentRoom->member(memberId).avatarUrl();
|
||||
#else
|
||||
return m_currentRoom->memberAvatar(memberId).url();
|
||||
#endif
|
||||
}
|
||||
if (role == ObjectRole) {
|
||||
return QVariant::fromValue(memberId);
|
||||
@@ -176,11 +172,7 @@ void UserListModel::refreshAllMembers()
|
||||
|
||||
if (m_currentRoom != nullptr) {
|
||||
m_members = m_currentRoom->joinedMemberIds();
|
||||
#if Quotient_VERSION_MINOR > 8
|
||||
MemberSorter sorter;
|
||||
#else
|
||||
MemberSorter sorter(m_currentRoom);
|
||||
#endif
|
||||
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 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