Compare commits
175 Commits
work/thiag
...
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 |
@@ -110,7 +110,7 @@
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/quotient-im/libQuotient.git",
|
||||
"branch": "dev",
|
||||
"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'
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "25")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "03")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||
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"
|
||||
|
||||
@@ -12,7 +12,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||
classpath 'com.android.tools.build:gradle:8.6.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"), {}}};
|
||||
|
||||
@@ -54,11 +54,16 @@
|
||||
<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>
|
||||
@@ -66,6 +71,7 @@
|
||||
<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>
|
||||
@@ -113,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>
|
||||
@@ -287,7 +293,6 @@
|
||||
<value key="KDE::windows_store::StoreLogoSquare">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/storelogo-1080x1080.png</value>
|
||||
<value key="KDE::windows_store::Icon">https://invent.kde.org/network/neochat/-/raw/master/icons/300-apps-neochat.png</value>
|
||||
<value key="KDE::windows_store::PromotionalArt16x9">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/promoimage-1920x1080.png</value>
|
||||
<value key="KDE::supporters">Tanguy Fardet</value>
|
||||
</custom>
|
||||
<launchable type="desktop-id">org.kde.neochat.desktop</launchable>
|
||||
<screenshots>
|
||||
@@ -442,6 +447,10 @@
|
||||
<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"/>
|
||||
|
||||
@@ -88,20 +88,32 @@ GenericName[x-test]=xxMatrix Clientxx
|
||||
GenericName[zh_CN]=Matrix 客户端
|
||||
GenericName[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[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[tr]=Matrix Üzerinde Sohbet Et
|
||||
Comment[sv]=Chatta på Matrix
|
||||
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும்
|
||||
Comment[tr]=Matrix üzerinde sohbet edin
|
||||
Comment[uk]=Спілкування у Matrix
|
||||
Comment[x-test]=xxChat on Matrixxx
|
||||
Comment[zh_CN]=在 Matrix 上聊天
|
||||
Comment[zh_TW]=在 Matrix 上聊天
|
||||
MimeType=x-scheme-handler/matrix;
|
||||
Exec=neochat %u
|
||||
Terminal=false
|
||||
|
||||
365
po/ar/neochat.po
365
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
334
po/az/neochat.po
334
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
634
po/ca/neochat.po
634
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
334
po/cs/neochat.po
334
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/da/neochat.po
334
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
681
po/de/neochat.po
681
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/el/neochat.po
334
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
459
po/eo/neochat.po
459
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/es/neochat.po
334
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
396
po/eu/neochat.po
396
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1614
po/fi/neochat.po
1614
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
346
po/fr/neochat.po
346
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
392
po/gl/neochat.po
392
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
411
po/hu/neochat.po
411
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
336
po/ia/neochat.po
336
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/id/neochat.po
334
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/ie/neochat.po
334
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
338
po/it/neochat.po
338
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/ja/neochat.po
334
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
338
po/ka/neochat.po
338
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/ko/neochat.po
334
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/lt/neochat.po
334
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/lv/neochat.po
334
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
342
po/nl/neochat.po
342
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
371
po/nn/neochat.po
371
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/pa/neochat.po
334
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
346
po/pl/neochat.po
346
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
334
po/pt/neochat.po
334
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
334
po/ru/neochat.po
334
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
937
po/sk/neochat.po
937
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
336
po/sl/neochat.po
336
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
362
po/sv/neochat.po
362
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
363
po/ta/neochat.po
363
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
350
po/tr/neochat.po
350
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
336
po/uk/neochat.po
336
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.9.0
|
||||
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
|
||||
|
||||
@@ -200,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
|
||||
@@ -311,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)
|
||||
@@ -416,6 +418,7 @@ target_link_libraries(neochat PUBLIC
|
||||
KF6::ConfigGui
|
||||
KF6::CoreAddons
|
||||
KF6::SonnetCore
|
||||
KF6::IconThemes
|
||||
KF6::ColorScheme
|
||||
KF6::ItemModels
|
||||
QuotientQt6
|
||||
@@ -489,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"
|
||||
@@ -526,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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -319,7 +319,8 @@ void ChatBarCache::postMessage()
|
||||
return;
|
||||
}
|
||||
|
||||
room->postMessage(text(), sendText, *std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result), replyId(), editId(), threadId());
|
||||
auto type = std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result);
|
||||
room->postMessage(text(), sendText, type ? *type : Quotient::RoomMessageEvent::MsgType::Text, replyId(), editId(), threadId());
|
||||
clearCache();
|
||||
}
|
||||
|
||||
|
||||
@@ -168,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();
|
||||
|
||||
@@ -423,10 +422,14 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -600,14 +600,19 @@ bool ActionsModel::handleQuickEditAction(NeoChatRoom *room, const QString &messa
|
||||
} 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(), {}, event->id());
|
||||
room->postHtmlMessage(messageText, originalString.replace(regex, replacement), event->msgtype(), {}, replaceId);
|
||||
} else {
|
||||
room->postHtmlMessage(messageText,
|
||||
originalString.replace(originalString.indexOf(regex), regex.size(), replacement),
|
||||
event->msgtype(),
|
||||
{},
|
||||
event->id());
|
||||
replaceId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -34,7 +34,7 @@ MessageContentModel::MessageContentModel(NeoChatRoom *room, const QString &event
|
||||
: QAbstractListModel(parent)
|
||||
, m_room(room)
|
||||
, m_eventId(eventId)
|
||||
, m_currentState(isPending ? Pending : Unknown)
|
||||
, m_isPending(isPending)
|
||||
, m_isReply(isReply)
|
||||
{
|
||||
initializeModel();
|
||||
@@ -45,27 +45,19 @@ void MessageContentModel::initializeModel()
|
||||
Q_ASSERT(m_room != nullptr);
|
||||
Q_ASSERT(!m_eventId.isEmpty());
|
||||
|
||||
connect(m_room, &NeoChatRoom::pendingEventAdded, this, [this]() {
|
||||
if (m_room != nullptr && m_currentState == Unknown) {
|
||||
initializeEvent();
|
||||
updateReplyModel();
|
||||
resetModel();
|
||||
}
|
||||
});
|
||||
connect(this, &MessageContentModel::eventUnavailable, this, &MessageContentModel::getEvent);
|
||||
|
||||
connect(m_room, &NeoChatRoom::pendingEventAboutToMerge, this, [this](Quotient::RoomEvent *serverEvent) {
|
||||
if (m_room != nullptr) {
|
||||
if (m_eventId == serverEvent->id() || m_eventId == serverEvent->transactionId()) {
|
||||
beginResetModel();
|
||||
m_isPending = false;
|
||||
m_eventId = serverEvent->id();
|
||||
initializeEvent();
|
||||
endResetModel();
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(m_room, &NeoChatRoom::pendingEventMerged, this, [this]() {
|
||||
if (m_room != nullptr && m_currentState == Pending) {
|
||||
initializeEvent();
|
||||
updateReplyModel();
|
||||
resetModel();
|
||||
}
|
||||
});
|
||||
connect(m_room, &NeoChatRoom::addedMessages, this, [this](int fromIndex, int toIndex) {
|
||||
if (m_room != nullptr) {
|
||||
for (int i = fromIndex; i <= toIndex; i++) {
|
||||
@@ -151,33 +143,20 @@ void MessageContentModel::initializeModel()
|
||||
});
|
||||
|
||||
initializeEvent();
|
||||
if (m_currentState == Available || m_currentState == Pending) {
|
||||
updateReplyModel();
|
||||
}
|
||||
updateReplyModel();
|
||||
resetModel();
|
||||
}
|
||||
|
||||
void MessageContentModel::initializeEvent()
|
||||
{
|
||||
if (m_currentState == UnAvailable) {
|
||||
const auto event = m_room->getEvent(m_eventId);
|
||||
if (event == nullptr) {
|
||||
Q_EMIT eventUnavailable();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto eventResult = m_room->getEvent(m_eventId);
|
||||
if (eventResult.first == nullptr) {
|
||||
if (m_currentState != Pending) {
|
||||
getEvent();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (eventResult.second) {
|
||||
m_currentState = Pending;
|
||||
} else {
|
||||
m_currentState = Available;
|
||||
}
|
||||
|
||||
if (m_eventSenderObject == nullptr) {
|
||||
auto senderId = eventResult.first->senderId();
|
||||
auto senderId = event->senderId();
|
||||
// A pending event might not have a sender ID set yet but in that case it must
|
||||
// be the local member.
|
||||
if (senderId.isEmpty()) {
|
||||
@@ -193,6 +172,7 @@ void MessageContentModel::getEvent()
|
||||
Quotient::connectUntil(m_room.get(), &NeoChatRoom::extraEventLoaded, this, [this](const QString &eventId) {
|
||||
if (m_room != nullptr) {
|
||||
if (eventId == m_eventId) {
|
||||
m_notFound = false;
|
||||
initializeEvent();
|
||||
updateReplyModel();
|
||||
resetModel();
|
||||
@@ -204,7 +184,7 @@ void MessageContentModel::getEvent()
|
||||
Quotient::connectUntil(m_room.get(), &NeoChatRoom::extraEventNotFound, this, [this](const QString &eventId) {
|
||||
if (m_room != nullptr) {
|
||||
if (eventId == m_eventId) {
|
||||
m_currentState = UnAvailable;
|
||||
m_notFound = true;
|
||||
resetModel();
|
||||
return true;
|
||||
}
|
||||
@@ -257,7 +237,7 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
||||
const auto component = m_components[index.row()];
|
||||
|
||||
const auto event = m_room->getEvent(m_eventId);
|
||||
if (event.first == nullptr) {
|
||||
if (event == nullptr) {
|
||||
if (role == DisplayRole) {
|
||||
if (m_isReply) {
|
||||
return i18n("Loading reply");
|
||||
@@ -272,7 +252,7 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
|
||||
if (role == DisplayRole) {
|
||||
if (m_currentState == UnAvailable || m_room->connection()->isIgnored(m_eventSenderId)) {
|
||||
if (m_notFound || m_room->connection()->isIgnored(m_eventSenderId)) {
|
||||
Kirigami::Platform::PlatformTheme *theme =
|
||||
static_cast<Kirigami::Platform::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::Platform::PlatformTheme>(this, true));
|
||||
|
||||
@@ -296,7 +276,7 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
||||
if (!component.content.isEmpty()) {
|
||||
return component.content;
|
||||
}
|
||||
return EventHandler::richBody(m_room, event.first);
|
||||
return EventHandler::richBody(m_room, event);
|
||||
}
|
||||
if (role == ComponentTypeRole) {
|
||||
return component.type;
|
||||
@@ -305,53 +285,53 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
||||
return component.attributes;
|
||||
}
|
||||
if (role == EventIdRole) {
|
||||
return EventHandler::id(event.first);
|
||||
return EventHandler::id(event);
|
||||
}
|
||||
if (role == TimeRole) {
|
||||
const auto pendingIt = std::find_if(m_room->pendingEvents().cbegin(), m_room->pendingEvents().cend(), [event](const PendingEventItem &pendingEvent) {
|
||||
return event.first->transactionId() == pendingEvent->transactionId();
|
||||
return event->transactionId() == pendingEvent->transactionId();
|
||||
});
|
||||
|
||||
auto lastUpdated = pendingIt == m_room->pendingEvents().cend() ? QDateTime() : pendingIt->lastUpdated();
|
||||
return EventHandler::time(event.first, m_currentState == Pending, lastUpdated);
|
||||
return EventHandler::time(event, m_isPending, lastUpdated);
|
||||
}
|
||||
if (role == TimeStringRole) {
|
||||
const auto pendingIt = std::find_if(m_room->pendingEvents().cbegin(), m_room->pendingEvents().cend(), [event](const PendingEventItem &pendingEvent) {
|
||||
return event.first->transactionId() == pendingEvent->transactionId();
|
||||
return event->transactionId() == pendingEvent->transactionId();
|
||||
});
|
||||
|
||||
auto lastUpdated = pendingIt == m_room->pendingEvents().cend() ? QDateTime() : pendingIt->lastUpdated();
|
||||
return EventHandler::timeString(event.first, QStringLiteral("hh:mm"), m_currentState == Pending, lastUpdated);
|
||||
return EventHandler::timeString(event, QStringLiteral("hh:mm"), m_isPending, lastUpdated);
|
||||
}
|
||||
if (role == AuthorRole) {
|
||||
return QVariant::fromValue<NeochatRoomMember *>(m_eventSenderObject.get());
|
||||
}
|
||||
if (role == MediaInfoRole) {
|
||||
return EventHandler::mediaInfo(m_room, event.first);
|
||||
return EventHandler::mediaInfo(m_room, event);
|
||||
}
|
||||
if (role == FileTransferInfoRole) {
|
||||
return QVariant::fromValue(m_room->cachedFileTransferInfo(event.first));
|
||||
return QVariant::fromValue(m_room->cachedFileTransferInfo(event));
|
||||
}
|
||||
if (role == ItineraryModelRole) {
|
||||
return QVariant::fromValue<ItineraryModel *>(m_itineraryModel);
|
||||
}
|
||||
if (role == LatitudeRole) {
|
||||
return EventHandler::latitude(event.first);
|
||||
return EventHandler::latitude(event);
|
||||
}
|
||||
if (role == LongitudeRole) {
|
||||
return EventHandler::longitude(event.first);
|
||||
return EventHandler::longitude(event);
|
||||
}
|
||||
if (role == AssetRole) {
|
||||
return EventHandler::locationAssetType(event.first);
|
||||
return EventHandler::locationAssetType(event);
|
||||
}
|
||||
if (role == PollHandlerRole) {
|
||||
return QVariant::fromValue<PollHandler *>(m_room->poll(m_eventId));
|
||||
}
|
||||
if (role == ReplyEventIdRole) {
|
||||
return EventHandler::replyId(event.first);
|
||||
return EventHandler::replyId(event);
|
||||
}
|
||||
if (role == ReplyAuthorRole) {
|
||||
return QVariant::fromValue(EventHandler::replyAuthor(m_room, event.first));
|
||||
return QVariant::fromValue(EventHandler::replyAuthor(m_room, event));
|
||||
}
|
||||
if (role == ReplyContentModelRole) {
|
||||
return QVariant::fromValue<MessageContentModel *>(m_replyModel);
|
||||
@@ -407,17 +387,18 @@ QHash<int, QByteArray> MessageContentModel::roleNames() const
|
||||
|
||||
void MessageContentModel::resetModel()
|
||||
{
|
||||
const auto event = m_room->getEvent(m_eventId);
|
||||
|
||||
beginResetModel();
|
||||
m_components.clear();
|
||||
|
||||
if (m_room->connection()->isIgnored(m_eventSenderId) || m_currentState == UnAvailable) {
|
||||
if (m_room->connection()->isIgnored(m_eventSenderId) || m_notFound) {
|
||||
m_components += MessageComponent{MessageComponentType::Text, QString(), {}};
|
||||
endResetModel();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto event = m_room->getEvent(m_eventId);
|
||||
if (event.first == nullptr) {
|
||||
if (event == nullptr) {
|
||||
m_components += MessageComponent{MessageComponentType::Loading, QString(), {}};
|
||||
endResetModel();
|
||||
return;
|
||||
@@ -450,19 +431,19 @@ void MessageContentModel::resetContent(bool isEditing, bool isThreading)
|
||||
QList<MessageComponent> MessageContentModel::messageContentComponents(bool isEditing, bool isThreading)
|
||||
{
|
||||
const auto event = m_room->getEvent(m_eventId);
|
||||
if (event.first == nullptr) {
|
||||
if (event == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QList<MessageComponent> newComponents;
|
||||
|
||||
if (eventCast<const Quotient::RoomMessageEvent>(event.first)
|
||||
&& eventCast<const Quotient::RoomMessageEvent>(event.first)->rawMsgtype() == QStringLiteral("m.key.verification.request")) {
|
||||
if (eventCast<const Quotient::RoomMessageEvent>(event)
|
||||
&& eventCast<const Quotient::RoomMessageEvent>(event)->rawMsgtype() == QStringLiteral("m.key.verification.request")) {
|
||||
newComponents += MessageComponent{MessageComponentType::Verification, QString(), {}};
|
||||
return newComponents;
|
||||
}
|
||||
|
||||
if (event.first->isRedacted()) {
|
||||
if (event->isRedacted()) {
|
||||
newComponents += MessageComponent{MessageComponentType::Text, QString(), {}};
|
||||
return newComponents;
|
||||
}
|
||||
@@ -474,7 +455,7 @@ QList<MessageComponent> MessageContentModel::messageContentComponents(bool isEdi
|
||||
if (isEditing) {
|
||||
newComponents += MessageComponent{MessageComponentType::ChatBar, QString(), {}};
|
||||
} else {
|
||||
newComponents.append(componentsForType(MessageComponentType::typeForEvent(*event.first)));
|
||||
newComponents.append(componentsForType(MessageComponentType::typeForEvent(*event)));
|
||||
}
|
||||
|
||||
if (m_room->urlPreviewEnabled()) {
|
||||
@@ -482,7 +463,7 @@ QList<MessageComponent> MessageContentModel::messageContentComponents(bool isEdi
|
||||
}
|
||||
|
||||
// If the event is already threaded the ThreadModel will handle displaying a chat bar.
|
||||
if (isThreading && !EventHandler::isThreaded(event.first)) {
|
||||
if (isThreading && !EventHandler::isThreaded(event)) {
|
||||
newComponents += MessageComponent{MessageComponentType::ChatBar, QString(), {}};
|
||||
}
|
||||
|
||||
@@ -492,11 +473,11 @@ QList<MessageComponent> MessageContentModel::messageContentComponents(bool isEdi
|
||||
void MessageContentModel::updateReplyModel()
|
||||
{
|
||||
const auto event = m_room->getEvent(m_eventId);
|
||||
if (event.first == nullptr || m_isReply) {
|
||||
if (event == nullptr || m_isReply) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EventHandler::hasReply(event.first) || (EventHandler::isThreaded(event.first) && NeoChatConfig::self()->threads())) {
|
||||
if (!EventHandler::hasReply(event) || (EventHandler::isThreaded(event) && NeoChatConfig::self()->threads())) {
|
||||
if (m_replyModel) {
|
||||
delete m_replyModel;
|
||||
}
|
||||
@@ -507,7 +488,7 @@ void MessageContentModel::updateReplyModel()
|
||||
return;
|
||||
}
|
||||
|
||||
m_replyModel = new MessageContentModel(m_room, EventHandler::replyId(event.first), true, false, this);
|
||||
m_replyModel = new MessageContentModel(m_room, EventHandler::replyId(event), true, false, this);
|
||||
|
||||
connect(m_replyModel, &MessageContentModel::eventUpdated, this, [this]() {
|
||||
Q_EMIT dataChanged(index(0), index(0), {ReplyAuthorRole});
|
||||
@@ -517,13 +498,13 @@ void MessageContentModel::updateReplyModel()
|
||||
QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentType::Type type)
|
||||
{
|
||||
const auto event = m_room->getEvent(m_eventId);
|
||||
if (event.first == nullptr) {
|
||||
if (event == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case MessageComponentType::Text: {
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event.first);
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
||||
auto body = EventHandler::rawMessageBody(*roomMessageEvent);
|
||||
return TextHandler().textComponents(body,
|
||||
EventHandler::messageBodyInputFormat(*roomMessageEvent),
|
||||
@@ -534,11 +515,11 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
|
||||
case MessageComponentType::File: {
|
||||
QList<MessageComponent> components;
|
||||
components += MessageComponent{MessageComponentType::File, QString(), {}};
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event.first);
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
||||
|
||||
if (m_emptyItinerary) {
|
||||
if (!m_isReply) {
|
||||
auto fileTransferInfo = m_room->cachedFileTransferInfo(event.first);
|
||||
auto fileTransferInfo = m_room->cachedFileTransferInfo(event);
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
Q_ASSERT(roomMessageEvent->content() != nullptr && roomMessageEvent->has<EventContent::FileContent>());
|
||||
@@ -586,17 +567,24 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
|
||||
case MessageComponentType::Image:
|
||||
case MessageComponentType::Audio:
|
||||
case MessageComponentType::Video: {
|
||||
if (!event.first->is<StickerEvent>()) {
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event.first);
|
||||
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;
|
||||
if (!event->is<StickerEvent>()) {
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event);
|
||||
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:
|
||||
@@ -672,13 +660,13 @@ void MessageContentModel::closeLinkPreview(int row)
|
||||
void MessageContentModel::updateItineraryModel()
|
||||
{
|
||||
const auto event = m_room->getEvent(m_eventId);
|
||||
if (m_room == nullptr || event.first == nullptr) {
|
||||
if (m_room == nullptr || event == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event.first)) {
|
||||
if (auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event)) {
|
||||
if (roomMessageEvent->has<EventContent::FileContent>()) {
|
||||
auto filePath = m_room->cachedFileTransferInfo(event.first).localPath;
|
||||
auto filePath = m_room->cachedFileTransferInfo(event).localPath;
|
||||
if (filePath.isEmpty() && m_itineraryModel != nullptr) {
|
||||
delete m_itineraryModel;
|
||||
m_itineraryModel = nullptr;
|
||||
|
||||
@@ -31,14 +31,6 @@ class MessageContentModel : public QAbstractListModel
|
||||
Q_PROPERTY(bool showAuthor READ showAuthor WRITE setShowAuthor NOTIFY showAuthorChanged)
|
||||
|
||||
public:
|
||||
enum MessageState {
|
||||
Unknown, /**< The message state is unknown. */
|
||||
Pending, /**< The message is a new pending message which the server has not yet acknowledged. */
|
||||
Available, /**< The message is available and acknowledged by the server. */
|
||||
UnAvailable, /**< The message can't be retrieved either because it doesn't exist or is blocked. */
|
||||
};
|
||||
Q_ENUM(MessageState)
|
||||
|
||||
/**
|
||||
* @brief Defines the model roles.
|
||||
*/
|
||||
@@ -106,6 +98,7 @@ public:
|
||||
|
||||
Q_SIGNALS:
|
||||
void showAuthorChanged();
|
||||
void eventUnavailable();
|
||||
void eventUpdated();
|
||||
|
||||
private:
|
||||
@@ -114,9 +107,10 @@ private:
|
||||
QString m_eventSenderId;
|
||||
std::unique_ptr<NeochatRoomMember> m_eventSenderObject = nullptr;
|
||||
|
||||
MessageState m_currentState = Unknown;
|
||||
bool m_isPending;
|
||||
bool m_showAuthor = true;
|
||||
bool m_isReply;
|
||||
bool m_notFound = false;
|
||||
|
||||
void initializeModel();
|
||||
void initializeEvent();
|
||||
|
||||
@@ -160,21 +160,12 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
||||
refreshLastUserEvents(i);
|
||||
}
|
||||
});
|
||||
#if Quotient_VERSION_MINOR > 9 || (Quotient_VERSION_MINOR == 9 && Quotient_VERSION_PATCH > 0)
|
||||
connect(m_currentRoom, &Room::pendingEventAdded, this, [this](const Quotient::RoomEvent *event) {
|
||||
m_initialized = true;
|
||||
createEventObjects(event, true);
|
||||
beginInsertRows({}, 0, 0);
|
||||
endInsertRows();
|
||||
});
|
||||
#else
|
||||
connect(m_currentRoom, &Room::pendingEventAboutToAdd, this, [this](Quotient::RoomEvent *event) {
|
||||
m_initialized = true;
|
||||
createEventObjects(event, true);
|
||||
createEventObjects(event);
|
||||
beginInsertRows({}, 0, 0);
|
||||
});
|
||||
connect(m_currentRoom, &Room::pendingEventAdded, this, &MessageEventModel::endInsertRows);
|
||||
#endif
|
||||
connect(m_currentRoom, &Room::pendingEventAboutToMerge, this, [this](RoomEvent *, int i) {
|
||||
Q_EMIT dataChanged(index(i, 0), index(i, 0), {IsPendingRole});
|
||||
if (i == 0) {
|
||||
@@ -514,7 +505,8 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
|
||||
if (role == ProgressInfoRole) {
|
||||
if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
|
||||
if (e->has<EventContent::FileContent>()) {
|
||||
if (e->has<EventContent::FileContent>() || e->has<EventContent::ImageContent>() || e->has<EventContent::VideoContent>()
|
||||
|| e->has<EventContent::AudioContent>()) {
|
||||
return QVariant::fromValue(m_currentRoom->cachedFileTransferInfo(&evt));
|
||||
}
|
||||
}
|
||||
@@ -627,7 +619,7 @@ int MessageEventModel::eventIdToRow(const QString &eventID) const
|
||||
return it - m_currentRoom->messageEvents().rbegin() + timelineBaseIndex();
|
||||
}
|
||||
|
||||
void MessageEventModel::createEventObjects(const Quotient::RoomEvent *event, bool isPending)
|
||||
void MessageEventModel::createEventObjects(const Quotient::RoomEvent *event)
|
||||
{
|
||||
if (event == nullptr) {
|
||||
return;
|
||||
@@ -650,7 +642,7 @@ void MessageEventModel::createEventObjects(const Quotient::RoomEvent *event, boo
|
||||
|
||||
if (!m_contentModels.contains(eventId) && !m_contentModels.contains(event->transactionId())) {
|
||||
if (!event->isStateEvent() || event->matrixType() == QStringLiteral("org.matrix.msc3672.beacon_info")) {
|
||||
m_contentModels[eventId] = std::unique_ptr<MessageContentModel>(new MessageContentModel(m_currentRoom, eventId, false, isPending));
|
||||
m_contentModels[eventId] = std::unique_ptr<MessageContentModel>(new MessageContentModel(m_currentRoom, eventId));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ private:
|
||||
int refreshEventRoles(const QString &eventId, const QList<int> &roles = {});
|
||||
void moveReadMarker(const QString &toEventId);
|
||||
|
||||
void createEventObjects(const Quotient::RoomEvent *event, bool isPending = false);
|
||||
void createEventObjects(const Quotient::RoomEvent *event);
|
||||
// Hack to ensure that we don't call endInsertRows when we haven't called beginInsertRows
|
||||
bool m_initialized = false;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -324,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();
|
||||
|
||||
@@ -261,7 +261,7 @@ Action=Popup
|
||||
Name=Share
|
||||
Name[ar]=شارك
|
||||
Name[ca]=Compartició
|
||||
Name[ca@valencia]=Compartició
|
||||
Name[ca@valencia]=Compartiu
|
||||
Name[cs]=Sdílet
|
||||
Name[de]=Teilen
|
||||
Name[el]=Κοινοποίηση
|
||||
@@ -289,6 +289,7 @@ Name[ta]=பகிர்
|
||||
Name[tr]=Paylaş
|
||||
Name[uk]=Оприлюднення
|
||||
Name[x-test]=xxSharexx
|
||||
Name[zh_CN]=分享
|
||||
Name[zh_TW]=分享
|
||||
Comment=The result of sharing a piece of content
|
||||
Comment[ar]=نتيجة مشاركة محتوى
|
||||
@@ -320,5 +321,6 @@ Comment[ta]=எதையோ பகிர்ந்ததன் விளைவ
|
||||
Comment[tr]=Bir parça içerik paylaşımının sonucu
|
||||
Comment[uk]=Результат оприлюднення даних
|
||||
Comment[x-test]=xxThe result of sharing a piece of contentxx
|
||||
Comment[zh_CN]=分享一个内容得到的结果
|
||||
Comment[zh_TW]=分享一份內容之後的結果
|
||||
Action=Popup
|
||||
|
||||
@@ -109,10 +109,6 @@ void NeoChatConnection::connectSignals()
|
||||
Q_EMIT homeHaveHighlightNotificationsChanged();
|
||||
});
|
||||
});
|
||||
connect(this, &NeoChatConnection::invitedRoom, this, [this](Quotient::Room *room) {
|
||||
auto r = dynamic_cast<NeoChatRoom *>(room);
|
||||
connect(r, &NeoChatRoom::showInviteNotification, this, &NeoChatConnection::showInviteNotification);
|
||||
});
|
||||
connect(this, &NeoChatConnection::leftRoom, this, [this](Room *room, Room *prev) {
|
||||
Q_UNUSED(room)
|
||||
if (prev && prev->isDirectChat()) {
|
||||
|
||||
@@ -205,11 +205,6 @@ Q_SIGNALS:
|
||||
*/
|
||||
void errorOccured(const QString &error);
|
||||
|
||||
/**
|
||||
* @brief Request a notification be shown for an invite to this room.
|
||||
*/
|
||||
void showInviteNotification(NeoChatRoom *room);
|
||||
|
||||
private:
|
||||
bool m_isOnline = true;
|
||||
void setIsOnline(bool isOnline);
|
||||
|
||||
@@ -124,9 +124,6 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
|
||||
updatePushNotificationState(QStringLiteral("m.push_rules"));
|
||||
|
||||
Q_EMIT canEncryptRoomChanged();
|
||||
if (this->joinState() == JoinState::Invite) {
|
||||
Q_EMIT showInviteNotification(this);
|
||||
}
|
||||
},
|
||||
Qt::SingleShotConnection);
|
||||
connect(this, &Room::changed, this, [this] {
|
||||
@@ -431,9 +428,9 @@ QDateTime NeoChatRoom::lastActiveTime()
|
||||
return messageEvents().rbegin()->get()->originTimestamp();
|
||||
}
|
||||
|
||||
QString NeoChatRoom::avatarMediaId() const
|
||||
QUrl NeoChatRoom::avatarMediaUrl() const
|
||||
{
|
||||
if (const auto avatar = Room::avatarMediaId(); !avatar.isEmpty()) {
|
||||
if (const auto avatar = Room::avatarUrl(); !avatar.isEmpty()) {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
@@ -441,7 +438,7 @@ QString NeoChatRoom::avatarMediaId() const
|
||||
const auto directChatMembers = this->directChatMembers();
|
||||
for (const auto member : directChatMembers) {
|
||||
if (member != localMember()) {
|
||||
return member.avatarMediaId();
|
||||
return member.avatarUrl();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,7 +747,10 @@ QList<QString> NeoChatRoom::restrictedIds() const
|
||||
|
||||
QString NeoChatRoom::historyVisibility() const
|
||||
{
|
||||
return currentState().get("m.room.history_visibility"_ls)->contentJson()["history_visibility"_ls].toString();
|
||||
if (auto stateEvent = currentState().get("m.room.history_visibility"_ls)) {
|
||||
return stateEvent->contentJson()["history_visibility"_ls].toString();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void NeoChatRoom::setHistoryVisibility(const QString &historyVisibilityRule)
|
||||
@@ -1749,31 +1749,25 @@ void NeoChatRoom::downloadEventFromServer(const QString &eventId)
|
||||
});
|
||||
}
|
||||
|
||||
std::pair<const Quotient::RoomEvent *, bool> NeoChatRoom::getEvent(const QString &eventId) const
|
||||
const RoomEvent *NeoChatRoom::getEvent(const QString &eventId) const
|
||||
{
|
||||
if (eventId.isEmpty()) {
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
const auto timelineIt = findInTimeline(eventId);
|
||||
if (timelineIt != historyEdge()) {
|
||||
return std::make_pair(timelineIt->get(), false);
|
||||
return timelineIt->get();
|
||||
}
|
||||
|
||||
auto pendingIt = findPendingEvent(eventId);
|
||||
const auto pendingIt = findPendingEvent(eventId);
|
||||
if (pendingIt != pendingEvents().end()) {
|
||||
return std::make_pair(pendingIt->event(), true);
|
||||
}
|
||||
// findPendingEvent() searches by transaction ID, we also need to check event ID.
|
||||
for (const auto &event : pendingEvents()) {
|
||||
if (event->id() == eventId || event->transactionId() == eventId) {
|
||||
return std::make_pair(event.event(), true);
|
||||
}
|
||||
return pendingIt->event();
|
||||
}
|
||||
|
||||
auto extraIt = std::find_if(m_extraEvents.begin(), m_extraEvents.end(), [eventId](const Quotient::event_ptr_tt<Quotient::RoomEvent> &event) {
|
||||
return event->id() == eventId;
|
||||
});
|
||||
return std::make_pair(extraIt != m_extraEvents.end() ? extraIt->get() : nullptr, false);
|
||||
return extraIt != m_extraEvents.end() ? extraIt->get() : nullptr;
|
||||
}
|
||||
|
||||
const RoomEvent *NeoChatRoom::getReplyForEvent(const RoomEvent &event) const
|
||||
|
||||
@@ -69,9 +69,9 @@ class NeoChatRoom : public Quotient::Room
|
||||
Q_PROPERTY(bool readMarkerLoaded READ readMarkerLoaded NOTIFY readMarkerLoadedChanged)
|
||||
|
||||
/**
|
||||
* @brief The avatar image to be used for the room.
|
||||
* @brief The avatar image to be used for the room, as a mxc:// URL.
|
||||
*/
|
||||
Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged STORED false)
|
||||
Q_PROPERTY(QUrl avatarMediaUrl READ avatarMediaUrl NOTIFY avatarChanged STORED false)
|
||||
|
||||
/**
|
||||
* @brief Get a RoomMember object for the other person in a direct chat.
|
||||
@@ -320,7 +320,7 @@ public:
|
||||
|
||||
[[nodiscard]] bool readMarkerLoaded() const;
|
||||
|
||||
[[nodiscard]] QString avatarMediaId() const;
|
||||
[[nodiscard]] QUrl avatarMediaUrl() const;
|
||||
|
||||
NeochatRoomMember *directChatRemoteMember();
|
||||
|
||||
@@ -570,7 +570,7 @@ public:
|
||||
*
|
||||
* The result will be nullptr if not found so needs to be managed.
|
||||
*/
|
||||
std::pair<const Quotient::RoomEvent *, bool> getEvent(const QString &eventId) const;
|
||||
const Quotient::RoomEvent *getEvent(const QString &eventId) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the event that is being replied to. This includes events that were manually loaded using NeoChatRoom::loadReply.
|
||||
@@ -654,14 +654,6 @@ Q_SIGNALS:
|
||||
*/
|
||||
void showMessage(MessageType::Type messageType, const QString &message);
|
||||
|
||||
/**
|
||||
* @brief Request a notification be shown for an invite to this room.
|
||||
*
|
||||
* @note This may later be blocked if there are any rules on where invites can
|
||||
* come from, but this is not NeoChatRoom's responsibility.
|
||||
*/
|
||||
void showInviteNotification(NeoChatRoom *room);
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* @brief Upload a file to the matrix server and post the file to the room.
|
||||
|
||||
@@ -153,15 +153,6 @@ QColor NeochatRoomMember::color() const
|
||||
return m_room->member(m_memberId).color();
|
||||
}
|
||||
|
||||
QString NeochatRoomMember::avatarMediaId() const
|
||||
{
|
||||
if (m_room == nullptr || m_memberId.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return m_room->member(m_memberId).avatarMediaId();
|
||||
}
|
||||
|
||||
QUrl NeochatRoomMember::avatarUrl() const
|
||||
{
|
||||
if (m_room == nullptr || m_memberId.isEmpty()) {
|
||||
|
||||
@@ -70,7 +70,6 @@ public:
|
||||
int hue() const;
|
||||
qreal hueF() const;
|
||||
QColor color() const;
|
||||
QString avatarMediaId() const;
|
||||
QUrl avatarUrl() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
@@ -127,9 +127,8 @@ void NotificationsManager::processNotificationJob(QPointer<NeoChatConnection> co
|
||||
}
|
||||
auto sender = room->member(notification["event"_ls]["sender"_ls].toString());
|
||||
|
||||
// Don't display notifications for events in invited rooms
|
||||
// This should prevent empty notifications from appearing when they shouldn't
|
||||
if (room->joinState() == JoinState::Invite) {
|
||||
postInviteNotification(qobject_cast<NeoChatRoom *>(room));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Comment[ru]=Поиск комнат NeoChat
|
||||
Comment[sl]=Najdi sobe v NeoChatu
|
||||
Comment[sv]=Sök efter rum i NeoChat
|
||||
Comment[ta]=நியோச்சாட்டில் அரங்குகளை கண்டுபிடிக்கும்
|
||||
Comment[tr]=NeoChat'te odalar bulun
|
||||
Comment[tr]=NeoChat’te odalar bulun
|
||||
Comment[uk]=Пошук кімнат у NeoChat
|
||||
Comment[x-test]=xxFind rooms in NeoChatxx
|
||||
Comment[zh_CN]=在 NeoChat 查找聊天室
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"Name[nl]": "Tobias Fella",
|
||||
"Name[nn]": "Tobias Fella",
|
||||
"Name[pl]": "Tobias Fella",
|
||||
"Name[pt_BR]": "Tobias Fella",
|
||||
"Name[ru]": "Tobias Fella",
|
||||
"Name[sk]": "Tobias Fella",
|
||||
"Name[sl]": "Tobias Fella",
|
||||
@@ -33,6 +34,7 @@
|
||||
"Name[tr]": "Tobias Fella",
|
||||
"Name[uk]": "Tobias Fella",
|
||||
"Name[x-test]": "xxTobias Fellaxx",
|
||||
"Name[zh_CN]": "Tobias Fella",
|
||||
"Name[zh_TW]": "Tobias Fella"
|
||||
}
|
||||
],
|
||||
@@ -59,6 +61,7 @@
|
||||
"Description[nl]": "Delen via NeoChat",
|
||||
"Description[nn]": "Del via NeoChat",
|
||||
"Description[pl]": "Udostępnij przez NeoChat",
|
||||
"Description[pt_BR]": "Compartilhar via NeoChat",
|
||||
"Description[ru]": "Опубликовать в NeoChat",
|
||||
"Description[sl]": "Deli prek NeoChat",
|
||||
"Description[sv]": "Dela via NeoChat",
|
||||
@@ -66,8 +69,9 @@
|
||||
"Description[tr]": "NeoChat ile Paylaş",
|
||||
"Description[uk]": "Оприлюднити за допомогою NeoChat",
|
||||
"Description[x-test]": "xxShare via NeoChatxx",
|
||||
"Description[zh_CN]": "通过 NeoChat 分享",
|
||||
"Description[zh_TW]": "透過 NeoChat 分享",
|
||||
"Icon": "org.kde.neochat",
|
||||
"Icon": "org.kde.neochat.tray",
|
||||
"License": "GPL",
|
||||
"Name": "NeoChat",
|
||||
"Name[ar]": "نيوتشات",
|
||||
@@ -93,6 +97,7 @@
|
||||
"Name[nl]": "NeoChat",
|
||||
"Name[nn]": "NeoChat",
|
||||
"Name[pl]": "NeoChat",
|
||||
"Name[pt_BR]": "NeoChat",
|
||||
"Name[ru]": "NeoChat",
|
||||
"Name[sk]": "NeoChat",
|
||||
"Name[sl]": "NeoChat",
|
||||
@@ -101,6 +106,7 @@
|
||||
"Name[tr]": "NeoChat",
|
||||
"Name[uk]": "NeoChat",
|
||||
"Name[x-test]": "xxNeoChatxx",
|
||||
"Name[zh_CN]": "NeoChat",
|
||||
"Name[zh_TW]": "NeoChat",
|
||||
"X-Purpose-ActionDisplay": "NeoChat"
|
||||
},
|
||||
|
||||
@@ -27,7 +27,8 @@ QQC2.Menu {
|
||||
text: "https://matrix.to/#/" + root.connection.localUser.id,
|
||||
title: root.connection.localUser.displayName,
|
||||
subtitle: root.connection.localUser.id,
|
||||
avatarSource: root.connection.makeMediaUrl(root.connection.localUser.avatarUrl)
|
||||
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl.
|
||||
avatarSource: root.connection.localUser.avatarUrl.toString().length > 0 ? root.connection.makeMediaUrl(root.connection.localUser.avatarUrl) : ""
|
||||
});
|
||||
if (typeof root.closeDialog === "function") {
|
||||
root.closeDialog();
|
||||
|
||||
@@ -125,7 +125,7 @@ Kirigami.Dialog {
|
||||
width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
|
||||
height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
|
||||
}
|
||||
source: userDelegate.connection.localUser.avatarMediaId ? userDelegate.connection.makeMediaUrl("mxc://" + userDelegate.connection.localUser.avatarMediaId) : ""
|
||||
source: userDelegate.connection.localUser.avatarUrl.toString().length > 0 ? userDelegate.connection.makeMediaUrl(userDelegate.connection.localUser.avatarUrl) : ""
|
||||
name: userDelegate.connection.localUser.displayName ?? userDelegate.connection.localUser.id
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ QQC2.ItemDelegate {
|
||||
required property NeoChatRoom currentRoom
|
||||
required property bool categoryVisible
|
||||
required property string filterText
|
||||
required property string avatar
|
||||
required property url avatar
|
||||
required property string displayName
|
||||
|
||||
topPadding: Kirigami.Units.largeSpacing
|
||||
@@ -32,7 +32,7 @@ QQC2.ItemDelegate {
|
||||
visible: root.categoryVisible || filterText.length > 0
|
||||
|
||||
contentItem: KirigamiComponents.Avatar {
|
||||
source: root.avatar ? root.currentRoom.connection.makeMediaUrl("mxc://" + root.avatar) : ""
|
||||
source: root.avatar
|
||||
name: root.displayName
|
||||
|
||||
sourceSize {
|
||||
|
||||
@@ -163,7 +163,7 @@ Loader {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
KirigamiComponents.Avatar {
|
||||
id: avatar
|
||||
source: room.avatarMediaId ? root.connection.makeMediaUrl("mxc://" + room.avatarMediaId) : ""
|
||||
source: room.avatarMediaUrl
|
||||
name: room.displayName
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import Qt.labs.qmlmodels
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
@@ -177,10 +178,25 @@ Loader {
|
||||
|
||||
Repeater {
|
||||
model: root.actions
|
||||
QQC2.MenuItem {
|
||||
visible: modelData.visible
|
||||
action: modelData
|
||||
onClicked: root.item.close()
|
||||
DelegateChooser {
|
||||
role: "separator"
|
||||
DelegateChoice {
|
||||
roleValue: true
|
||||
|
||||
QQC2.MenuSeparator {
|
||||
visible: modelData.visible
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: false
|
||||
|
||||
QQC2.MenuItem {
|
||||
visible: modelData.visible
|
||||
action: modelData
|
||||
onClicked: root.item.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
QQC2.Menu {
|
||||
@@ -196,7 +212,7 @@ Loader {
|
||||
model: WebShortcutModel {
|
||||
id: webshortcutmodel
|
||||
selectedText: root.selectedText.length > 0 ? root.selectedText : root.plainText
|
||||
onOpenUrl: RoomManager.resolveResource(url)
|
||||
onOpenUrl: url => RoomManager.resolveResource(url.toString())
|
||||
}
|
||||
delegate: QQC2.MenuItem {
|
||||
text: model.display
|
||||
@@ -341,15 +357,30 @@ Loader {
|
||||
id: listViewAction
|
||||
model: root.actions
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
icon.name: modelData.icon.name
|
||||
icon.color: modelData.icon.color ?? undefined
|
||||
enabled: modelData.enabled
|
||||
visible: modelData.visible
|
||||
text: modelData.text
|
||||
onClicked: {
|
||||
modelData.triggered();
|
||||
root.item.close();
|
||||
DelegateChooser {
|
||||
role: "separator"
|
||||
DelegateChoice {
|
||||
roleValue: true
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
visible: modelData.visible
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: false
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
icon.name: modelData.icon.name
|
||||
icon.color: modelData.icon.color ?? undefined
|
||||
enabled: modelData.enabled
|
||||
visible: modelData.visible
|
||||
text: modelData.text
|
||||
onClicked: {
|
||||
modelData.triggered();
|
||||
root.item.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ ColumnLayout {
|
||||
|
||||
contentItem: KirigamiComponents.Avatar {
|
||||
name: root.room ? root.room.displayName : ""
|
||||
source: root.room ? root.room.connection.makeMediaUrl("mxc://" + root.room.avatarMediaId) : ""
|
||||
source: root.room ? root.room.avatarMediaUrl : ""
|
||||
|
||||
Rectangle {
|
||||
visible: root.room.usesEncryption
|
||||
|
||||
@@ -54,8 +54,8 @@ DelegateContextMenu {
|
||||
icon.name: "document-save"
|
||||
onTriggered: {
|
||||
var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay);
|
||||
dialog.selectedFile = currentRoom.fileNameToDownload(eventId);
|
||||
dialog.open();
|
||||
dialog.currentFile = dialog.folder + "/" + currentRoom.fileNameToDownload(eventId);
|
||||
}
|
||||
},
|
||||
DelegateContextMenu.ReplyMessageAction {},
|
||||
|
||||
@@ -102,7 +102,7 @@ Labs.MenuBar {
|
||||
}
|
||||
Labs.MenuItem {
|
||||
text: i18nc("menu", "About KDE")
|
||||
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDE"))
|
||||
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDEPage"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ ColumnLayout {
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.large
|
||||
|
||||
name: root.room ? root.room.displayName : ""
|
||||
source: root.room ? root.room.connection.makeMediaUrl("mxc://" + root.room.avatarMediaId) : ""
|
||||
source: root.room ? root.room.avatarMediaUrl : ""
|
||||
|
||||
Rectangle {
|
||||
visible: room.usesEncryption
|
||||
@@ -75,6 +75,7 @@ ColumnLayout {
|
||||
textFormat: TextEdit.PlainText
|
||||
visible: root.room && root.room.canonicalAlias
|
||||
text: root.room && root.room.canonicalAlias ? root.room.canonicalAlias : ""
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
}
|
||||
}
|
||||
QQC2.AbstractButton {
|
||||
@@ -88,11 +89,11 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
let map = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(parent, {
|
||||
let map = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||
text: barcode.content,
|
||||
title: root.room ? root.room.displayName : "",
|
||||
subtitle: root.room ? root.room.id : "",
|
||||
avatarSource: root.room && root.room.avatarMediaId ? root.room.connection.makeMediaUrl("mxc://" + root.room.avatarMediaId) : ""
|
||||
avatarSource: root.room ? root.room.avatarMediaUrl : ""
|
||||
});
|
||||
map.open();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import QtQuick.Layouts
|
||||
import QtCore as Core
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
||||
import org.kde.kquickimageeditor as KQuickImageEditor
|
||||
|
||||
Kirigami.Page {
|
||||
@@ -168,10 +167,11 @@ Kirigami.Page {
|
||||
}
|
||||
}
|
||||
|
||||
footer: KirigamiComponents.Banner {
|
||||
footer: Kirigami.InlineMessage {
|
||||
id: msg
|
||||
type: Kirigami.MessageType.Error
|
||||
showCloseButton: true
|
||||
visible: false
|
||||
position: Kirigami.InlineMessage.Position.Header
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,11 +318,13 @@ Kirigami.ApplicationWindow {
|
||||
})
|
||||
}
|
||||
function showUserDetail(user, room) {
|
||||
Qt.createComponent("org.kde.neochat", "UserDetailDialog").createObject(root.QQC2.ApplicationWindow.window, {
|
||||
const dialog = Qt.createComponent("org.kde.neochat", "UserDetailDialog").createObject(root, {
|
||||
room: room,
|
||||
user: user,
|
||||
connection: root.connection
|
||||
}).open();
|
||||
connection: root.connection,
|
||||
});
|
||||
dialog.parent = QmlUtils.focusedWindowItem(); // Kirigami Dialogs overwrite the parent, so we need to set it again
|
||||
dialog.open();
|
||||
}
|
||||
|
||||
function load() {
|
||||
|
||||
@@ -29,13 +29,20 @@ Components.AlbumMaximizeComponent {
|
||||
|
||||
readonly property var currentProgressInfo: model.data(model.index(content.currentIndex, 0), MessageEventModel.ProgressInfoRole)
|
||||
|
||||
onCurrentProgressInfoChanged: () => {
|
||||
if (root.currentProgressInfo) {
|
||||
root.downloadAction.progress = root.currentProgressInfo.progress / root.currentProgressInfo.total * 100.0;
|
||||
} else {
|
||||
root.downloadAction.progress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Whether the delegate is part of a thread timeline.
|
||||
*/
|
||||
property bool isThread: false
|
||||
|
||||
downloadAction: Components.DownloadAction {
|
||||
id: downloadAction
|
||||
onTriggered: {
|
||||
currentRoom.downloadFile(root.currentEventId, Core.StandardPaths.writableLocation(Core.StandardPaths.CacheLocation) + "/" + root.currentEventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(root.currentEventId));
|
||||
}
|
||||
@@ -62,19 +69,11 @@ Components.AlbumMaximizeComponent {
|
||||
|
||||
function onFileTransferProgress(id, progress, total) {
|
||||
if (id == root.currentEventId) {
|
||||
downloadAction.progress = progress / total * 100.0;
|
||||
root.downloadAction.progress = progress / total * 100.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: content
|
||||
|
||||
function onCurrentIndexChanged() {
|
||||
downloadAction.progress = currentProgressInfo.progress / currentProgressInfo.total * 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
leading: RowLayout {
|
||||
Components.Avatar {
|
||||
id: userAvatar
|
||||
@@ -106,12 +105,12 @@ Components.AlbumMaximizeComponent {
|
||||
|
||||
onOpened: forceActiveFocus()
|
||||
|
||||
onItemRightClicked: RoomManager.viewEventMenu(root.currentEventId, root.currentRoom)
|
||||
onItemRightClicked: RoomManager.viewEventMenu(root.currentEventId, root.currentRoom, root.currentAuthor)
|
||||
|
||||
onSaveItem: {
|
||||
var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay);
|
||||
dialog.selectedFile = currentRoom.fileNameToDownload(root.currentEventId);
|
||||
dialog.open();
|
||||
dialog.currentFile = dialog.folder + "/" + currentRoom.fileNameToDownload(root.currentEventId);
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
||||
@@ -12,7 +12,7 @@ Components.AbstractMaximizeComponent {
|
||||
|
||||
required property string text
|
||||
property color avatarColor
|
||||
required property string avatarSource
|
||||
required property url avatarSource
|
||||
|
||||
onOpened: forceActiveFocus()
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ Kirigami.SearchDialog {
|
||||
onTextChanged: RoomManager.sortFilterRoomListModel.filterText = text
|
||||
model: RoomManager.sortFilterRoomListModel
|
||||
emptyText: i18nc("Placeholder message", "No room found")
|
||||
parent: QQC2.Overlay.overlay
|
||||
|
||||
delegate: RoomDelegate {
|
||||
connection: root.connection
|
||||
|
||||
@@ -30,9 +30,9 @@ Kirigami.Dialog {
|
||||
FormCard.AbstractFormDelegate {
|
||||
background: null
|
||||
contentItem: RowLayout {
|
||||
spacing: Kirigami.Units.largeSpacing * 4
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
Avatar {
|
||||
source: root.connection.makeMediaUrl(SpaceHierarchyCache.recommendedSpaceAvatar)
|
||||
source: SpaceHierarchyCache.recommendedSpaceAvatar.toString().length > 0 ? root.connection.makeMediaUrl(SpaceHierarchyCache.recommendedSpaceAvatar) : 0
|
||||
name: SpaceHierarchyCache.recommendedSpaceDisplayName
|
||||
}
|
||||
ColumnLayout {
|
||||
@@ -51,6 +51,7 @@ Kirigami.Dialog {
|
||||
FormCard.FormDelegateSeparator {}
|
||||
FormCard.FormButtonDelegate {
|
||||
text: i18nc("@action:button", "Join")
|
||||
icon.name: "list-add-symbolic"
|
||||
onClicked: {
|
||||
SpaceHierarchyCache.recommendedSpaceHidden = true;
|
||||
RoomManager.resolveResource(SpaceHierarchyCache.recommendedSpaceId, "join");
|
||||
@@ -58,6 +59,7 @@ Kirigami.Dialog {
|
||||
}
|
||||
}
|
||||
FormCard.FormButtonDelegate {
|
||||
icon.name: "mail-thread-ignored-symbolic"
|
||||
text: i18nc("@action:button", "Ignore")
|
||||
onClicked: {
|
||||
SpaceHierarchyCache.recommendedSpaceHidden = true;
|
||||
|
||||
@@ -21,7 +21,7 @@ Delegates.RoundedItemDelegate {
|
||||
required property bool hasHighlightNotifications
|
||||
required property NeoChatRoom currentRoom
|
||||
required property NeoChatConnection connection
|
||||
required property string avatar
|
||||
required property url avatar
|
||||
required property string subtitleText
|
||||
required property string displayName
|
||||
|
||||
@@ -55,7 +55,7 @@ Delegates.RoundedItemDelegate {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
AvatarNotification {
|
||||
source: root.avatar ? root.connection.makeMediaUrl("mxc://" + root.avatar) : ""
|
||||
source: root.avatar
|
||||
name: root.displayName
|
||||
visible: NeoChatConfig.showAvatarInRoomDrawer
|
||||
implicitHeight: Kirigami.Units.gridUnit + (NeoChatConfig.compactRoomList ? 0 : Kirigami.Units.largeSpacing * 2)
|
||||
|
||||
@@ -99,8 +99,11 @@ Kirigami.OverlayDrawer {
|
||||
Layout.preferredHeight: pageStack.globalToolBar.preferredHeight
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: 0
|
||||
|
||||
Kirigami.Heading {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
text: drawerItemLoader.item ? drawerItemLoader.item.title : ""
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ QQC2.ScrollView {
|
||||
required property int index
|
||||
required property string name
|
||||
required property string userId
|
||||
required property string avatar
|
||||
required property url avatar
|
||||
required property int powerLevel
|
||||
required property string powerLevelString
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
|
||||
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kitemmodels
|
||||
|
||||
@@ -99,11 +98,12 @@ Kirigami.Page {
|
||||
}
|
||||
}
|
||||
|
||||
header: KirigamiComponents.Banner {
|
||||
header: Kirigami.InlineMessage {
|
||||
id: banner
|
||||
|
||||
showCloseButton: true
|
||||
visible: false
|
||||
position: Kirigami.InlineMessage.Position.Header
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -198,7 +198,7 @@ Kirigami.Page {
|
||||
Shortcut {
|
||||
sequence: StandardKey.Cancel
|
||||
onActivated: {
|
||||
if (!timelineViewLoader.item.atYEnd || root.currentRoom.hasUnreadMessages) {
|
||||
if (!timelineViewLoader.item.atYEnd || !root.currentRoom.partiallyReadStats.empty()) {
|
||||
timelineViewLoader.item.goToLastMessage();
|
||||
root.currentRoom.markAllMessagesAsRead();
|
||||
} else {
|
||||
@@ -308,6 +308,7 @@ Kirigami.Page {
|
||||
NeochatMaximizeComponent {
|
||||
currentRoom: root.currentRoom
|
||||
model: root.mediaMessageFilterModel
|
||||
parent: root.QQC2.Overlay.overlay
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ QQC2.Control {
|
||||
|
||||
text: i18nc("@button View all one-on-one chats with your friends.", "Friends")
|
||||
contentItem: Kirigami.Icon {
|
||||
source: "system-users"
|
||||
source: "system-users-symbolic"
|
||||
|
||||
QQC2.Label {
|
||||
id: directChatNotificationCountLabel
|
||||
@@ -182,7 +182,7 @@ QQC2.Control {
|
||||
id: spaceDelegate
|
||||
|
||||
required property string displayName
|
||||
required property string avatar
|
||||
required property url avatar
|
||||
required property string roomId
|
||||
required property var currentRoom
|
||||
|
||||
@@ -191,7 +191,7 @@ QQC2.Control {
|
||||
Layout.maximumHeight: width - Kirigami.Units.smallSpacing
|
||||
|
||||
text: displayName
|
||||
source: avatar ? root.connection.makeMediaUrl("mxc://" + avatar) : ""
|
||||
source: avatar
|
||||
|
||||
notificationCount: spaceDelegate.currentRoom.childrenNotificationCount
|
||||
notificationHighlight: spaceDelegate.currentRoom.childrenHaveHighlightNotifications
|
||||
@@ -219,7 +219,7 @@ QQC2.Control {
|
||||
visible: SpaceHierarchyCache.recommendedSpaceId.length > 0 && !root.connection.room(SpaceHierarchyCache.recommendedSpaceId) && !SpaceHierarchyCache.recommendedSpaceHidden
|
||||
|
||||
text: i18nc("Join <name of a space>", "Join %1", SpaceHierarchyCache.recommendedSpaceDisplayName)
|
||||
source: SpaceHierarchyCache.recommendedSpaceAvatar.length > 0 ? root.connection.makeMediaUrl(SpaceHierarchyCache.recommendedSpaceAvatar) : ""
|
||||
source: SpaceHierarchyCache.recommendedSpaceAvatar.toString().length > 0 ? root.connection.makeMediaUrl(SpaceHierarchyCache.recommendedSpaceAvatar) : ""
|
||||
onSelected: {
|
||||
recommendedSpaceDialogComponent.createObject(QQC2.Overlay.overlay, {
|
||||
connection: root.connection
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user