Compare commits

..

2 Commits

Author SHA1 Message Date
Carlos De Maine
bf754711e3 skip windows as one test is failing 2025-07-06 09:34:01 +10:00
Carlos De Maine
32d0f846ee Testing for VM based CI 2025-07-06 09:15:21 +10:00
173 changed files with 26482 additions and 31701 deletions

View File

@@ -20,16 +20,8 @@
"--talk-name=org.kde.kwalletd5", "--talk-name=org.kde.kwalletd5",
"--talk-name=org.kde.StatusNotifierWatcher", "--talk-name=org.kde.StatusNotifierWatcher",
"--talk-name=org.freedesktop.secrets", "--talk-name=org.freedesktop.secrets",
"--talk-name=org.kde.kuiserver",
"--own-name=org.kde.StatusNotifierItem-2-2" "--own-name=org.kde.StatusNotifierItem-2-2"
], ],
"cleanup": [
"/include",
"/lib/*.a",
"/lib/cmake",
"/lib/pkgconfig",
"/share/ndk-modules"
],
"modules": [ "modules": [
{ {
"name": "kirigamiaddons", "name": "kirigamiaddons",
@@ -90,8 +82,8 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.7.tar.xz", "url": "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.6.tar.xz",
"sha256": "6b452e4750590a2b5617adc40026f28d2f4903de15f1250e1d1c40bfd68ed55e", "sha256": "747b8c175be108c880d3adfb9c3537ea66e520e4ad2dccf5dce58003aeeca090",
"x-checker-data": { "x-checker-data": {
"type": "gnome", "type": "gnome",
"name": "libsecret", "name": "libsecret",
@@ -164,13 +156,13 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.kde.org/stable/release-service/25.04.3/src/kunifiedpush-25.04.3.tar.xz", "url": "https://download.kde.org/stable/kunifiedpush/kunifiedpush-1.0.0.tar.xz",
"sha256": "a16ffe4117b14baa02f3b8ae7de9e509a17359c1b67dcd851aef4f3c3661a1df", "sha256": "2ddeba21306d0307114ec50a2c38159ec62359f9fc6cdd58da30a369fbd550cf",
"x-checker-data": { "x-checker-data": {
"type": "anitya", "type": "anitya",
"project-id": 8763, "project-id": 375055,
"stable-only": true, "stable-only": true,
"url-template": "https://download.kde.org/stable/release-service/$version/src/kunifiedpush-$version.tar.xz" "url-template": "https://download.kde.org/stable/kunifiedpush/kunifiedpush-$version.tar.xz"
} }
} }
] ]

View File

@@ -3,19 +3,20 @@
include: include:
- project: sysadmin/ci-utilities - project: sysadmin/ci-utilities
ref: work/switch-vm-ci
file: file:
- /gitlab-templates/reuse-lint.yml #- /gitlab-templates/reuse-lint.yml
- /gitlab-templates/json-validation.yml #- /gitlab-templates/json-validation.yml
- /gitlab-templates/xml-lint.yml #- /gitlab-templates/xml-lint.yml
- /gitlab-templates/yaml-lint.yml #- /gitlab-templates/yaml-lint.yml
- /gitlab-templates/android-qt6.yml #- /gitlab-templates/android-qt6.yml
- /gitlab-templates/linux-qt6.yml - /gitlab-templates/linux-qt6.yml
- /gitlab-templates/linux-qt6-next.yml - /gitlab-templates/linux-qt6-next.yml
- /gitlab-templates/windows-qt6.yml #- /gitlab-templates/windows-qt6.yml
- /gitlab-templates/freebsd-qt6.yml #- /gitlab-templates/freebsd-qt6.yml
- /gitlab-templates/flatpak.yml - /gitlab-templates/flatpak.yml
- /gitlab-templates/snap-snapcraft-lxd.yml - /gitlab-templates/snap-snapcraft-lxd.yml
- /gitlab-templates/craft-android-qt6-apks.yml #- /gitlab-templates/craft-android-qt6-apks.yml
- /gitlab-templates/craft-appimage-qt6.yml #- /gitlab-templates/craft-appimage-qt6.yml
- /gitlab-templates/craft-windows-x86-64-qt6.yml - /gitlab-templates/craft-windows-x86-64-qt6.yml
- /gitlab-templates/craft-windows-appx-qt6.yml - /gitlab-templates/craft-windows-appx-qt6.yml

View File

@@ -6,7 +6,6 @@
#include <QObject> #include <QObject>
#include <QTest> #include <QTest>
#include <QSignalSpy>
#include <Quotient/roommember.h> #include <Quotient/roommember.h>
#include <Quotient/syncdata.h> #include <Quotient/syncdata.h>
#include <qtestcase.h> #include <qtestcase.h>
@@ -33,7 +32,6 @@ private Q_SLOTS:
void noRoom(); void noRoom();
void badParent(); void badParent();
void reply(); void reply();
void replyMissingUser();
void edit(); void edit();
void attachment(); void attachment();
}; };
@@ -104,33 +102,6 @@ void ChatBarCacheTest::reply()
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s)); QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s); QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
QCOMPARE(chatBarCache->attachmentPath(), QString()); QCOMPARE(chatBarCache->attachmentPath(), QString());
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
}
void ChatBarCacheTest::replyMissingUser()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(u"some text"_s);
chatBarCache->setAttachmentPath(u"some/path"_s);
chatBarCache->setReplyId(u"$153456789:example.org"_s);
QCOMPARE(chatBarCache->text(), u"some text"_s);
QCOMPARE(chatBarCache->isReplying(), true);
QCOMPARE(chatBarCache->replyId(), u"$153456789:example.org"_s);
QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
QCOMPARE(chatBarCache->attachmentPath(), QString());
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
QSignalSpy relationAuthorIsPresentSpy(chatBarCache.get(), &ChatBarCache::relationAuthorIsPresentChanged);
// sync again, which will simulate the reply user leaving the room
room->syncNewEvents(u"test-min-sync-extra-sync.json"_s);
QTRY_COMPARE(relationAuthorIsPresentSpy.count(), 1);
QCOMPARE(chatBarCache->relationAuthorIsPresent(), false);
} }
void ChatBarCacheTest::edit() void ChatBarCacheTest::edit()

View File

@@ -1,20 +0,0 @@
{
"state": {
"events": [
{
"content": {
"membership": "leave"
},
"event_id": "$1432735824666PhrSA:example.org",
"origin_server_ts": 1432735824666,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@example:example.org",
"type": "m.room.member",
"unsigned": {
"replaces_state": "$143273582443PhrSn:example.org"
}
}
]
}
}

View File

@@ -130,8 +130,7 @@ void EventHandlerTest::timeString()
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().time(), QLocale::ShortFormat)); QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().time(), QLocale::ShortFormat));
QCOMPARE(EventHandler::timeString(room, event, true), QCOMPARE(EventHandler::timeString(room, event, true),
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().date(), QLocale::ShortFormat)); format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().date(), QLocale::ShortFormat));
QCOMPARE(EventHandler::timeString(room, event, u"hh:mm"_s), QCOMPARE(EventHandler::timeString(room, event, u"hh:mm"_s), QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toString(u"hh:mm"_s));
QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::LocalTime)).toString(u"hh:mm"_s));
const auto txID = room->postJson("m.room.message"_L1, event->fullJson()); const auto txID = room->postJson("m.room.message"_L1, event->fullJson());
QCOMPARE(room->pendingEvents().size(), 1); QCOMPARE(room->pendingEvents().size(), 1);

View File

@@ -10,7 +10,7 @@
#include <Quotient/roommember.h> #include <Quotient/roommember.h>
#include <Quotient/syncdata.h> #include <Quotient/syncdata.h>
#include "models/eventmessagecontentmodel.h" #include "models/messagecontentmodel.h"
#include "neochatconnection.h" #include "neochatconnection.h"
#include "testutils.h" #include "testutils.h"
@@ -39,13 +39,13 @@ void MessageContentModelTest::initTestCase()
void MessageContentModelTest::missingEvent() void MessageContentModelTest::missingEvent()
{ {
auto room = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s); auto room = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
auto model1 = EventMessageContentModel(room, u"$153456789:example.org"_s); auto model1 = MessageContentModel(room, u"$153456789:example.org"_s);
QCOMPARE(model1.rowCount(), 1); QCOMPARE(model1.rowCount(), 1);
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading); QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading"_s); QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading"_s);
auto model2 = EventMessageContentModel(room, u"$153456789:example.org"_s, true); auto model2 = MessageContentModel(room, u"$153456789:example.org"_s, true);
QCOMPARE(model2.rowCount(), 1); QCOMPARE(model2.rowCount(), 1);
QCOMPARE(model2.data(model2.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading); QCOMPARE(model2.data(model2.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);

View File

@@ -9,7 +9,7 @@
#include <Quotient/events/roommessageevent.h> #include <Quotient/events/roommessageevent.h>
#include "models/eventmessagecontentmodel.h" #include "models/messagecontentmodel.h"
#include "testutils.h" #include "testutils.h"
using namespace Quotient; using namespace Quotient;
@@ -21,7 +21,7 @@ class ReactionModelTest : public QObject
private: private:
Connection *connection = nullptr; Connection *connection = nullptr;
TestUtils::TestRoom *room = nullptr; TestUtils::TestRoom *room = nullptr;
EventMessageContentModel *parentModel; MessageContentModel *parentModel;
private Q_SLOTS: private Q_SLOTS:
void initTestCase(); void initTestCase();
@@ -34,7 +34,7 @@ void ReactionModelTest::initTestCase()
{ {
connection = Connection::makeMockConnection(u"@bob:kde.org"_s); connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-reactionmodel-sync.json"_s); room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-reactionmodel-sync.json"_s);
parentModel = new EventMessageContentModel(room, "123456"_L1); parentModel = new MessageContentModel(room, "123456"_L1);
} }
void ReactionModelTest::basicReaction() void ReactionModelTest::basicReaction()

View File

@@ -75,7 +75,6 @@
<summary xml:lang="nl">Chat op Matrix</summary> <summary xml:lang="nl">Chat op Matrix</summary>
<summary xml:lang="nn">Prat med via Matrix</summary> <summary xml:lang="nn">Prat med via Matrix</summary>
<summary xml:lang="pl">Rozmawiaj na Matriksie</summary> <summary xml:lang="pl">Rozmawiaj na Matriksie</summary>
<summary xml:lang="pt-BR">Bate-papo na Matrix</summary>
<summary xml:lang="ru">Общение в Matrix</summary> <summary xml:lang="ru">Общение в Matrix</summary>
<summary xml:lang="sa">Matrix इत्यत्र गपशपं कुर्वन्तु</summary> <summary xml:lang="sa">Matrix इत्यत्र गपशपं कुर्वन्तु</summary>
<summary xml:lang="sl">Klepet na Matrixu</summary> <summary xml:lang="sl">Klepet na Matrixu</summary>
@@ -110,7 +109,6 @@
<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="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="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="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="pt-BR">O NeoChat é um aplicativo de bate-papo que permite que você aproveite ao máximo a rede Matrix. Ele oferece uma maneira segura de enviar mensagens de texto, vídeos e arquivos de áudio para sua família, colegas e amigos.</p>
<p xml:lang="ru">NeoChat — приложение для общения, предоставляющее все преимущества сети Matrix. С его помощью можно безопасно отправлять текстовые сообщения, видеозаписи и звуковые файлы родственникам, коллегам и друзьям.</p> <p xml:lang="ru">NeoChat — приложение для общения, предоставляющее все преимущества сети Matrix. С его помощью можно безопасно отправлять текстовые сообщения, видеозаписи и звуковые файлы родственникам, коллегам и друзьям.</p>
<p xml:lang="sa">NeoChat इति एकं गपशप-अनुप्रयोगं यत् भवान् Matrix-जालस्य पूर्णं लाभं ग्रहीतुं शक्नोति । एतत् भवन्तं भवतः परिवाराय, सहकारिभ्यः, मित्रेभ्यः च पाठसन्देशान्, भिडियो, श्रव्यसञ्चिकाः च प्रेषयितुं सुरक्षितं मार्गं प्रदाति ।</p> <p xml:lang="sa">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="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>
@@ -144,7 +142,6 @@
<p xml:lang="nn">NeoChat har som mål å støtta all funksjonalitet i Matrix-spesifikasjonen. Førebels er alt i den gjeldande stabile spesifikasjonen støtta, med unntak av VoIP, trådar og nokre delar av ende-til-kryptering. Det finst òg andre småting som ikkje er støtta, sidan Matrix-spesifikasjon er i stadig endring, men målet er altså støtte for alt.</p> <p xml:lang="nn">NeoChat har som mål å støtta all funksjonalitet i Matrix-spesifikasjonen. Førebels er alt i den gjeldande stabile spesifikasjonen støtta, med unntak av VoIP, trådar og nokre delar av ende-til-kryptering. Det finst òg andre småting som ikkje er støtta, sidan Matrix-spesifikasjon er i stadig endring, men målet er altså støtte for alt.</p>
<p xml:lang="pl">NeoChat w zamyśle ma być pełnowartościową aplikacją wg wytycznych Matriksa. Z tego powodu, wszystko, co jest obecnie w stabilnych wytycznych z pominięciem VoIP, wątków i niektórych części szyfrowania Użytkownik-do-Użytkownika są obecnie obsługiwane. Pominięto też kilka mniejszych rzeczy ze względu na ciągły rozwój wytycznych Matriksa, lecz celem nadal jest zapewnienie obsługi wszystkich wytycznych.</p> <p xml:lang="pl">NeoChat w zamyśle ma być pełnowartościową aplikacją wg wytycznych Matriksa. Z tego powodu, wszystko, co jest obecnie w stabilnych wytycznych z pominięciem VoIP, wątków i niektórych części szyfrowania Użytkownik-do-Użytkownika są obecnie obsługiwane. Pominięto też kilka mniejszych rzeczy ze względu na ciągły rozwój wytycznych Matriksa, lecz celem nadal jest zapewnienie obsługi wszystkich wytycznych.</p>
<p xml:lang="pt">O NeoChat pretende ser uma aplicação completa para a especificação do Matrix. Como tal, tudo o que existe na especificação estável actual, com as notáveis excepções do VoIP, tópicos e alguns aspectos da Encriptação Ponto-a-Ponto, são suportados. Existem mais algumas omissões, devido ao facto que a norma do Matrix está em constante evolução, mas o objectivo continua a ser oferecer o suporte eventual para a norma por inteiro.</p> <p xml:lang="pt">O NeoChat pretende ser uma aplicação completa para a especificação do Matrix. Como tal, tudo o que existe na especificação estável actual, com as notáveis excepções do VoIP, tópicos e alguns aspectos da Encriptação Ponto-a-Ponto, são suportados. Existem mais algumas omissões, devido ao facto que a norma do Matrix está em constante evolução, mas o objectivo continua a ser oferecer o suporte eventual para a norma por inteiro.</p>
<p xml:lang="pt-BR">O NeoChat pretende ser um aplicativo completo para a especificação Matrix. Dessa forma, tudo na especificação estável atual, com as notáveis exceções de VoIP, tópicos e alguns aspectos da criptografia de ponta a ponta, é suportado. Há algumas outras pequenas omissões devido ao fato de a especificação Matrix estar em constante evolução, mas o objetivo continua sendo fornecer suporte eventual para toda a especificação.</p>
<p xml:lang="ru">Целью создания NeoChat является полноценная реализация программы для спецификации Matrix. Как следствие, реализовано всё в текущей стабильной спецификации (за исключением голосовой интернет-связи, потоков и некоторых аспектов сквозного шифрования). Есть также несколько других незначительных пробелов, обусловленных постоянными изменениями спецификации Matrix. Тем не менее, стоит задача в итоге предоставить полную поддержку спецификации.</p> <p xml:lang="ru">Целью создания NeoChat является полноценная реализация программы для спецификации Matrix. Как следствие, реализовано всё в текущей стабильной спецификации (за исключением голосовой интернет-связи, потоков и некоторых аспектов сквозного шифрования). Есть также несколько других незначительных пробелов, обусловленных постоянными изменениями спецификации Matrix. Тем не менее, стоит задача в итоге предоставить полную поддержку спецификации.</p>
<p xml:lang="sa">NeoChat इत्यस्य उद्देश्यं Matrix विनिर्देशस्य कृते पूर्णतया विशेषतायुक्तः अनुप्रयोगः भवितुम् अस्ति । यथा तथा वर्तमानस्थिरविनिर्देशे सर्वं VoIP इत्यस्य उल्लेखनीयअपवादैः सह, थ्रेड्स तथा च End-to-End Encryption इत्यस्य केचन पक्षाः समर्थिताः सन्ति । अन्ये कतिचन लघु लोपाः सन्ति यतोहि Matrix spec निरन्तरं विकसितः अस्ति परन्तु उद्देश्यं सम्पूर्ण spec कृते अन्ततः समर्थनं प्रदातुं अवशिष्टम् अस्ति</p> <p xml:lang="sa">NeoChat इत्यस्य उद्देश्यं Matrix विनिर्देशस्य कृते पूर्णतया विशेषतायुक्तः अनुप्रयोगः भवितुम् अस्ति । यथा तथा वर्तमानस्थिरविनिर्देशे सर्वं VoIP इत्यस्य उल्लेखनीयअपवादैः सह, थ्रेड्स तथा च End-to-End Encryption इत्यस्य केचन पक्षाः समर्थिताः सन्ति । अन्ये कतिचन लघु लोपाः सन्ति यतोहि Matrix spec निरन्तरं विकसितः अस्ति परन्तु उद्देश्यं सम्पूर्ण spec कृते अन्ततः समर्थनं प्रदातुं अवशिष्टम् अस्ति</p>
<p xml:lang="sl">Neochat cilja, da bi bila popolna aplikacija po specifikaciji Matrixa. Kot takšna vsebuje vse v trenutni stabilni specifikaciji z pomembnimi izjemami pri VoIP, nitih in nekaterih vidikov šifriranja od konca do konca. Obstaja nekaj drugih manjših opustitev zaradi dejstva, da se specifikacija Matrix nenehno razvija, vendar cilj ostaja zagotoviti morebitno podporo celotni specifikaciji.</p> <p xml:lang="sl">Neochat cilja, da bi bila popolna aplikacija po specifikaciji Matrixa. Kot takšna vsebuje vse v trenutni stabilni specifikaciji z pomembnimi izjemami pri VoIP, nitih in nekaterih vidikov šifriranja od konca do konca. Obstaja nekaj drugih manjših opustitev zaradi dejstva, da se specifikacija Matrix nenehno razvija, vendar cilj ostaja zagotoviti morebitno podporo celotni specifikaciji.</p>
@@ -178,7 +175,6 @@
<p xml:lang="nn">På grunn av måten Matrix-spesifikasjonen vert utvikla på, støttar NeoChat òg nokre uferdige funksjonar:</p> <p xml:lang="nn">På grunn av måten Matrix-spesifikasjonen vert utvikla på, støttar NeoChat òg nokre uferdige funksjonar:</p>
<p xml:lang="pl">Ze względu na sposób rozwoju Matriksa, NeoChat obsługuje także kilka niestabilnych możliwości. Obecnie są to:</p> <p xml:lang="pl">Ze względu na sposób rozwoju Matriksa, NeoChat obsługuje także kilka niestabilnych możliwości. Obecnie są to:</p>
<p xml:lang="pt">Devido à natureza do desenvolvimento da especificação do Matrix, o NeoChat também suporta diversas funcionalidades instáveis. De momento são:</p> <p xml:lang="pt">Devido à natureza do desenvolvimento da especificação do Matrix, o NeoChat também suporta diversas funcionalidades instáveis. De momento são:</p>
<p xml:lang="pt-BR">Devido à natureza do desenvolvimento da especificação Matrix, o NeoChat também suporta diversos recursos instáveis. Atualmente, são eles:</p>
<p xml:lang="ru">В силу природы разработки спецификации Matrix в NeoChat тоже предусмотрена поддержка многочисленных нестабильных возможностей. В текущей версии это следующие возможности:</p> <p xml:lang="ru">В силу природы разработки спецификации Matrix в NeoChat тоже предусмотрена поддержка многочисленных нестабильных возможностей. В текущей версии это следующие возможности:</p>
<p xml:lang="sa">Matrix विनिर्देशविकासस्य प्रकृतेः कारणात् NeoChat अपि अनेकानाम् अस्थिरविशेषतानां समर्थनं करोति । सम्प्रति एते सन्ति :</p> <p xml:lang="sa">Matrix विनिर्देशविकासस्य प्रकृतेः कारणात् NeoChat अपि अनेकानाम् अस्थिरविशेषतानां समर्थनं करोति । सम्प्रति एते सन्ति :</p>
<p xml:lang="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p> <p xml:lang="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p>
@@ -191,8 +187,8 @@
<ul> <ul>
<li>Polls - MSC3381</li> <li>Polls - MSC3381</li>
<li xml:lang="ar">التصويت - MSC3381</li> <li xml:lang="ar">التصويت - MSC3381</li>
<li xml:lang="ca">Votacions - MSC3381</li> <li xml:lang="ca">Enquestes - MSC3381</li>
<li xml:lang="ca-valencia">Votacions - MSC3381</li> <li xml:lang="ca-valencia">Enquestes - MSC3381</li>
<li xml:lang="el">Δημοσκοπήσεις - MSC3381</li> <li xml:lang="el">Δημοσκοπήσεις - MSC3381</li>
<li xml:lang="en-GB">Polls - MSC3381</li> <li xml:lang="en-GB">Polls - MSC3381</li>
<li xml:lang="eo">Enketoj - MSC3381</li> <li xml:lang="eo">Enketoj - MSC3381</li>
@@ -213,7 +209,6 @@
<li xml:lang="nn">Avstemmingar  MSC3381</li> <li xml:lang="nn">Avstemmingar  MSC3381</li>
<li xml:lang="pl">Ankiety - MSC3381</li> <li xml:lang="pl">Ankiety - MSC3381</li>
<li xml:lang="pt">Inquéritos - MSC3381</li> <li xml:lang="pt">Inquéritos - MSC3381</li>
<li xml:lang="pt-BR">Enquetes - MSC3381</li>
<li xml:lang="ru">Голосования — MSC3381</li> <li xml:lang="ru">Голосования — MSC3381</li>
<li xml:lang="sa">मतदान - MSC3381</li> <li xml:lang="sa">मतदान - MSC3381</li>
<li xml:lang="sl">Polls - MSC3381</li> <li xml:lang="sl">Polls - MSC3381</li>
@@ -247,7 +242,6 @@
<li xml:lang="nn">Klistremerke-pakkar  MSC2545</li> <li xml:lang="nn">Klistremerke-pakkar  MSC2545</li>
<li xml:lang="pl">Paczki naklejek - MSC2545</li> <li xml:lang="pl">Paczki naklejek - MSC2545</li>
<li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li> <li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li>
<li xml:lang="pt-BR">Pacotes de Stickers - MSC2545</li>
<li xml:lang="ru">Наборы стикеров — MSC2545</li> <li xml:lang="ru">Наборы стикеров — MSC2545</li>
<li xml:lang="sa">स्टिकर पैक - MSC2545</li> <li xml:lang="sa">स्टिकर पैक - MSC2545</li>
<li xml:lang="sl">Sticker Packs - MSC2545</li> <li xml:lang="sl">Sticker Packs - MSC2545</li>
@@ -281,7 +275,6 @@
<li xml:lang="nn">Posisjonshendingar  MSC3488</li> <li xml:lang="nn">Posisjonshendingar  MSC3488</li>
<li xml:lang="pl">Wydarzenia w miejscach - MSC3488</li> <li xml:lang="pl">Wydarzenia w miejscach - MSC3488</li>
<li xml:lang="pt">Eventos com Localizações - MSC3488</li> <li xml:lang="pt">Eventos com Localizações - MSC3488</li>
<li xml:lang="pt-BR">Localização de eventos - MSC3488</li>
<li xml:lang="ru">События местоположения — MSC3488</li> <li xml:lang="ru">События местоположения — MSC3488</li>
<li xml:lang="sa">स्थान घटनाएँ - MSC3488</li> <li xml:lang="sa">स्थान घटनाएँ - MSC3488</li>
<li xml:lang="sl">Location Events - MSC3488</li> <li xml:lang="sl">Location Events - MSC3488</li>
@@ -351,7 +344,6 @@
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption> <caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption> <caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption> <caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
<caption xml:lang="pt-BR">Visão principal com lista de salas, bate-papo e informações sobre as salas</caption>
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption> <caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
<caption xml:lang="sa">कक्षसूची, गपशपः, कक्षसूचना च सह मुख्यदृश्यम्</caption> <caption xml:lang="sa">कक्षसूची, गपशपः, कक्षसूचना च सह मुख्यदृश्यम्</caption>
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption> <caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
@@ -388,7 +380,6 @@
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption> <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="nn">Oppdag nye fellesskap med Matrix Spaces</caption>
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption> <caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
<caption xml:lang="pt-BR">Descubra novas comunidades com os Espaços Matrix</caption>
<caption xml:lang="ru">Поиск новых сообществ с помощью Matrix Spaces</caption> <caption xml:lang="ru">Поиск новых сообществ с помощью Matrix Spaces</caption>
<caption xml:lang="sa">Matrix Spaces इत्यनेन सह नूतनानां समुदायानाम् अन्वेषणं कुर्वन्तु</caption> <caption xml:lang="sa">Matrix Spaces इत्यनेन सह नूतनानां समुदायानाम् अन्वेषणं कुर्वन्तु</caption>
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption> <caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
@@ -433,7 +424,6 @@
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption> <caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption> <caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption> <caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
<caption xml:lang="pt-BR">Visão principal com lista de salas, bate-papo e informações sobre as salas</caption>
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption> <caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
<caption xml:lang="sa">कक्षसूची, गपशपः, कक्षसूचना च सह मुख्यदृश्यम्</caption> <caption xml:lang="sa">कक्षसूची, गपशपः, कक्षसूचना च सह मुख्यदृश्यम्</caption>
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption> <caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
@@ -472,7 +462,6 @@
<caption xml:lang="nn">Innloggingsbilete</caption> <caption xml:lang="nn">Innloggingsbilete</caption>
<caption xml:lang="pl">Ekran logowania</caption> <caption xml:lang="pl">Ekran logowania</caption>
<caption xml:lang="pt">Ecrã de autenticação</caption> <caption xml:lang="pt">Ecrã de autenticação</caption>
<caption xml:lang="pt-BR">Tela de login</caption>
<caption xml:lang="ru">Окно входа</caption> <caption xml:lang="ru">Окно входа</caption>
<caption xml:lang="sa">लॉगिन् स्क्रीन</caption> <caption xml:lang="sa">लॉगिन् स्क्रीन</caption>
<caption xml:lang="sl">Prijavni zaslon</caption> <caption xml:lang="sl">Prijavni zaslon</caption>
@@ -488,7 +477,6 @@
<content_attribute id="social-chat">intense</content_attribute> <content_attribute id="social-chat">intense</content_attribute>
</content_rating> </content_rating>
<releases> <releases>
<release version="25.08.0" date="2025-08-14"/>
<release version="25.04.3" date="2025-07-03"/> <release version="25.04.3" date="2025-07-03"/>
<release version="25.04.2" date="2025-06-05"/> <release version="25.04.2" date="2025-06-05"/>
<release version="25.04.1" date="2025-05-08"/> <release version="25.04.1" date="2025-05-08"/>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,122 +0,0 @@
<?xml version="1.0" ?>
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
<!ENTITY % Russian "INCLUDE">
]>
<!--
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
SPDX-License-Identifier: CC-BY-SA-4.0
-->
<refentry lang="&language;">
<refentryinfo>
<title
>Руководство пользователя NeoChat</title>
<author
><firstname
>Carl</firstname
><surname
>Schwan</surname
> <contrib
>man-страница NeoChat.</contrib
> <email
>carl@carlschwan.eu</email
></author>
<date
>2022-11-01</date>
<releaseinfo
>22.09</releaseinfo>
<productname
>NeoChat</productname>
</refentryinfo>
<refmeta>
<refentrytitle>
<command
>neochat</command>
</refentrytitle>
<manvolnum
>1</manvolnum>
</refmeta>
<refnamediv>
<refname
>neochat</refname>
<refpurpose
>Клиент для взаимодействия с протоколом обмена сообщениями Matrix</refpurpose>
</refnamediv>
<!-- body begins here -->
<refsynopsisdiv id='synopsis'>
<cmdsynopsis
><command
>neochat</command
> <arg choice="opt"
><replaceable
>URI</replaceable
></arg
> </cmdsynopsis>
</refsynopsisdiv>
<refsect1 id="description">
<title
>Описание</title>
<para
><command
>neochat</command
> — приложение для настольных и мобильных устройств, позволяющее общаться в чатах с помощью протокола Matrix. </para>
</refsect1>
<refsect1 id="options"
><title
>Параметры</title>
<variablelist>
<varlistentry>
<term
><option
>URI</option
></term>
<listitem>
<para
>URI-адрес пользователя или комнаты в Matrix, например: matrix:u/user:example.org и matrix:r/root:example.org. NeoChat попытается открыть указанную комнату или беседу. </para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="bug">
<title
>Отчёты об ошибках</title>
<para
>Сообщать об ошибках и отправлять предложения по улучшению можно по адресу <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&amp;component=General"
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&amp;component=General</ulink
></para>
</refsect1>
<refsect1>
<title
>Смотрите также</title>
<simplelist>
<member
>Список наиболее часто задаваемых вопросов о Matrix <ulink url="https://matrix.org/faq/"
>https://matrix.org/faq/</ulink
> </member>
<member
>kf5options(7)</member>
<member
>qt5options(7)</member>
</simplelist>
</refsect1>
<refsect1 id="copyright"
><title
>Авторские права</title>
<para
>Авторские права &copy; Tobias Fella, 20202022 </para>
<para
>Авторские права &copy; Carl Schwan, 20202022 </para>
<para
>Лицензия: стандартная общественная лицензия GNU версии 3 или любой более поздней версии &lt;<ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
>&gt;</para>
</refsect1>
</refentry>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@
#include "controller.h" #include "controller.h"
#include <Quotient/connection.h> #include <Quotient/connection.h>
#include <qt6keychain/keychain.h>
#include <KLocalizedString> #include <KLocalizedString>
@@ -13,6 +14,7 @@
#include <signal.h> #include <signal.h>
#include <Quotient/csapi/notifications.h>
#include <Quotient/events/roommemberevent.h> #include <Quotient/events/roommemberevent.h>
#include <Quotient/qt_connection_util.h> #include <Quotient/qt_connection_util.h>
#include <Quotient/settings.h> #include <Quotient/settings.h>
@@ -22,6 +24,7 @@
#include "mediasizehelper.h" #include "mediasizehelper.h"
#include "models/actionsmodel.h" #include "models/actionsmodel.h"
#include "models/messagemodel.h" #include "models/messagemodel.h"
#include "models/pushrulemodel.h"
#include "models/roomlistmodel.h" #include "models/roomlistmodel.h"
#include "models/roomtreemodel.h" #include "models/roomtreemodel.h"
#include "neochatconfig.h" #include "neochatconfig.h"

View File

@@ -7,6 +7,7 @@
#include <QQmlEngine> #include <QQmlEngine>
#include "neochatconnection.h" #include "neochatconnection.h"
#include "neochatroom.h"
#include <Quotient/events/roommessageevent.h> #include <Quotient/events/roommessageevent.h>
#include <Quotient/roommember.h> #include <Quotient/roommember.h>
@@ -24,7 +25,11 @@ class CommonRoomsModel : public QAbstractListModel
public: public:
enum Roles { enum Roles {
RoomIdRole = Qt::DisplayRole, TextRole = Qt::DisplayRole,
LongitudeRole,
LatitudeRole,
AssetRole,
AuthorRole,
}; };
Q_ENUM(Roles) Q_ENUM(Roles)

View File

@@ -176,7 +176,7 @@ void ServerListModel::initialize()
true, true,
false, false,
}); });
endResetModel(); beginResetModel();
} }
#include "moc_serverlistmodel.cpp" #include "moc_serverlistmodel.cpp"

View File

@@ -189,10 +189,6 @@
<label>Don't hide any events in the timeline</label> <label>Don't hide any events in the timeline</label>
<default>false</default> <default>false</default>
</entry> </entry>
<entry name="RelateAnyEvent" type="bool">
<label>Send relations to any event, including state events and events normally hidden.</label>
<default>false</default>
</entry>
<entry name="AlwaysVerifyDevice" type="bool"> <entry name="AlwaysVerifyDevice" type="bool">
<label>Always allow device verification</label> <label>Always allow device verification</label>
<default>false</default> <default>false</default>

View File

@@ -93,3 +93,4 @@ X-Plasma-API=DBus
X-Plasma-DBusRunner-Service=org.kde.neochat X-Plasma-DBusRunner-Service=org.kde.neochat
X-Plasma-DBusRunner-Path=/RoomRunner X-Plasma-DBusRunner-Path=/RoomRunner
X-Plasma-Request-Actions-Once=true X-Plasma-Request-Actions-Once=true
X-Plasma-Runner-Min-Letter-Count=3

View File

@@ -1,10 +1,9 @@
// SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com> // SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Controls as QQC2 import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components as KirigamiComponents import org.kde.kirigamiaddons.components as KirigamiComponents
@@ -19,17 +18,21 @@ KirigamiComponents.ConvergentContextMenu {
required property NeoChatConnection connection required property NeoChatConnection connection
required property Kirigami.ApplicationWindow window required property Kirigami.ApplicationWindow window
Kirigami.Action { QQC2.Action {
text: i18nc("@action:button", "Show QR Code") text: i18nc("@action:button", "Show QR Code")
icon.name: "view-barcode-qr-symbolic" icon.name: "view-barcode-qr-symbolic"
onTriggered: { onTriggered: {
(Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, { let qrMax = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
text: "https://matrix.to/#/" + root.connection.localUser.id, text: "https://matrix.to/#/" + root.connection.localUser.id,
title: root.connection.localUser.displayName, title: root.connection.localUser.displayName,
subtitle: root.connection.localUser.id, subtitle: root.connection.localUser.id,
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl. // 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) : "" avatarSource: root.connection.localUser.avatarUrl.toString().length > 0 ? root.connection.makeMediaUrl(root.connection.localUser.avatarUrl) : ""
}) as QrCodeMaximizeComponent).open(); });
if (typeof root.closeDialog === "function") {
root.closeDialog();
}
qrMax.open();
} }
} }
@@ -37,27 +40,26 @@ KirigamiComponents.ConvergentContextMenu {
text: i18nc("@action:inmenu", "Switch Account") text: i18nc("@action:inmenu", "Switch Account")
icon.name: "system-switch-user" icon.name: "system-switch-user"
shortcut: "Ctrl+U" shortcut: "Ctrl+U"
onTriggered: (Qt.createComponent("org.kde.neochat", "AccountSwitchDialog").createObject(QQC2.Overlay.overlay, { onTriggered: accountSwitchDialog.createObject(QQC2.Overlay.overlay, {
connection: root.connection connection: root.connection
}) as Kirigami.Dialog).open(); }).open();
} }
QQC2.Action {
Kirigami.Action { text: i18n("Edit This Account")
text: i18nc("@action:inmenu", "Edit This Account")
icon.name: "document-edit" icon.name: "document-edit"
onTriggered: NeoChatSettingsView.openWithInitialProperties("accounts", {initialAccount: root.connection}); onTriggered: NeoChatSettingsView.openWithInitialProperties("accounts", {initialAccount: root.connection});
} }
Kirigami.Action { QQC2.Action {
text: i18nc("@action:inmenu", "Notification Settings") text: i18n("Notification Settings")
icon.name: "notifications" icon.name: "notifications"
onTriggered: { onTriggered: {
NeoChatSettingsView.open('notifications'); NeoChatSettingsView.open('notifications');
} }
} }
Kirigami.Action { QQC2.Action {
text: i18nc("@action:inmenu", "Devices") text: i18n("Devices")
icon.name: "computer-symbolic" icon.name: "computer-symbolic"
onTriggered: { onTriggered: {
NeoChatSettingsView.open('devices'); NeoChatSettingsView.open('devices');
@@ -65,10 +67,10 @@ KirigamiComponents.ConvergentContextMenu {
} }
Kirigami.Action { Kirigami.Action {
text: i18nc("@action:inmenu", "Open Developer Tools") text: i18n("Open Developer Tools")
icon.name: "tools" icon.name: "tools"
visible: NeoChatConfig.developerTools visible: NeoChatConfig.developerTools
onTriggered: root.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'DevtoolsPage'), { onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'DevtoolsPage'), {
connection: root.connection connection: root.connection
}, { }, {
title: i18nc("@title:window", "Developer Tools"), title: i18nc("@title:window", "Developer Tools"),
@@ -86,10 +88,9 @@ KirigamiComponents.ConvergentContextMenu {
}) })
} }
Kirigami.Action { QQC2.Action {
text: i18nc("@action:inmenu", "Verify This Device") text: i18nc("@action:inmenu", "Verify This Device")
icon.name: "security-low" icon.name: "security-low"
visible: !root.connection.isVerifiedSession()
onTriggered: { onTriggered: {
root.connection.startSelfVerification(); root.connection.startSelfVerification();
const dialog = Qt.createComponent("org.kde.kirigami", "PromptDialog").createObject(QQC2.Overlay.overlay, { const dialog = Qt.createComponent("org.kde.kirigami", "PromptDialog").createObject(QQC2.Overlay.overlay, {
@@ -98,17 +99,19 @@ KirigamiComponents.ConvergentContextMenu {
standardButtons: Kirigami.Dialog.Ok standardButtons: Kirigami.Dialog.Ok
}) })
dialog.open(); dialog.open();
root.connection.newKeyVerificationSession.connect(() => { root.connection.onNewKeyVerificationSession.connect(() => {
dialog.close(); dialog.close();
}); });
} }
} }
Kirigami.Action { QQC2.Action {
text: i18nc("@action:inmenu", "Logout") text: i18n("Logout")
icon.name: "im-kick-user" icon.name: "im-kick-user"
onTriggered: (Qt.createComponent("org.kde.neochat", "ConfirmLogoutDialog").createObject(QQC2.Overlay.overlay, { onTriggered: confirmLogoutDialogComponent.createObject(root).open()
connection: root.connection }
}) as Kirigami.Dialog).open()
readonly property Component confirmLogoutDialogComponent: ConfirmLogoutDialog {
connection: root.connection
} }
} }

View File

@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts import QtQuick.Layouts
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
@@ -17,6 +16,8 @@ Kirigami.Dialog {
required property NeoChatConnection connection required property NeoChatConnection connection
parent: applicationWindow().overlay
leftPadding: 0 leftPadding: 0
rightPadding: 0 rightPadding: 0
topPadding: 0 topPadding: 0
@@ -24,7 +25,7 @@ Kirigami.Dialog {
standardButtons: Kirigami.Dialog.NoButton standardButtons: Kirigami.Dialog.NoButton
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24) width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
title: i18nc("@title: dialog to switch between logged in accounts", "Switch Account") title: i18nc("@title: dialog to switch between logged in accounts", "Switch Account")
onVisibleChanged: if (visible) { onVisibleChanged: if (visible) {
@@ -52,7 +53,7 @@ Kirigami.Dialog {
} }
text: i18nc("@button: login to or register a new account.", "Add Account") text: i18nc("@button: login to or register a new account.", "Add Account")
contentItem: Delegates.SubtitleContentItem { contentItem: Delegates.SubtitleContentItem {
itemDelegate: addDelegate itemDelegate: parent
subtitle: i18n("Log in or create a new account") subtitle: i18n("Log in or create a new account")
labelItem.textFormat: Text.PlainText labelItem.textFormat: Text.PlainText
subtitleItem.textFormat: Text.PlainText subtitleItem.textFormat: Text.PlainText

View File

@@ -33,7 +33,7 @@ ColumnLayout {
} }
QQC2.ToolButton { QQC2.ToolButton {
id: editImageButton id: editImageButton
visible: root.hasImage visible: hasImage
icon.name: "document-edit" icon.name: "document-edit"
text: i18n("Edit") text: i18n("Edit")
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
@@ -46,9 +46,9 @@ ColumnLayout {
} }
onClicked: { onClicked: {
let imageEditor = (Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(imageEditorPage); let imageEditor = applicationWindow().pageStack.pushDialogLayer(imageEditorPage);
imageEditor.newPathChanged.connect(function (newPath) { imageEditor.newPathChanged.connect(function (newPath) {
imageEditor.closeDialog(); applicationWindow().pageStack.layers.pop();
root.attachmentPath = newPath; root.attachmentPath = newPath;
}); });
} }
@@ -61,7 +61,7 @@ ColumnLayout {
action: Kirigami.Action { action: Kirigami.Action {
text: i18n("Cancel sending attachment") text: i18n("Cancel sending attachment")
icon.name: "dialog-close" icon.name: "dialog-close"
onTriggered: root.attachmentCancelled() onTriggered: attachmentCancelled()
shortcut: "Escape" shortcut: "Escape"
} }
QQC2.ToolTip.text: text QQC2.ToolTip.text: text
@@ -75,8 +75,8 @@ ColumnLayout {
asynchronous: true asynchronous: true
cache: false // Cache is not needed. Images will rarely be shown repeatedly. cache: false // Cache is not needed. Images will rarely be shown repeatedly.
source: root.hasImage ? root.attachmentPath : "" source: hasImage ? root.attachmentPath : ""
visible: root.hasImage visible: hasImage
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
onSourceChanged: { onSourceChanged: {
@@ -114,11 +114,11 @@ ColumnLayout {
id: mimetypeIcon id: mimetypeIcon
implicitWidth: Kirigami.Units.iconSizes.smallMedium implicitWidth: Kirigami.Units.iconSizes.smallMedium
implicitHeight: Kirigami.Units.iconSizes.smallMedium implicitHeight: Kirigami.Units.iconSizes.smallMedium
source: root.attachmentMimetype.iconName source: attachmentMimetype.iconName
} }
QQC2.Label { QQC2.Label {
id: fileLabel id: fileLabel
text: root.baseFileName text: baseFileName
} }
} }
} }

View File

@@ -3,9 +3,12 @@
// SPDX-License-Identifier: LGPL-2.0-or-later // SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2 import QtQuick.Controls as QQC2
import QtQuick.Templates as T
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.delegates as Delegates import org.kde.kirigamiaddons.delegates as Delegates
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
Delegates.RoundedItemDelegate { Delegates.RoundedItemDelegate {
id: root id: root

View File

@@ -8,6 +8,7 @@ import QtQml.Models
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.labs.components as KirigamiComponents import org.kde.kirigamiaddons.labs.components as KirigamiComponents
import org.kde.kitemmodels
import org.kde.neochat import org.kde.neochat

View File

@@ -59,7 +59,7 @@ ApplicationWindow {
Connections { Connections {
target: mapView.map target: mapView.map
function onCopyrightLinkActivated(link: string): void { function onCopyrightLinkActivated() {
Qt.openUrlExternally(link); Qt.openUrlExternally(link);
} }
} }

View File

@@ -17,6 +17,23 @@ Labs.MenuBar {
required property NeoChatConnection connection required property NeoChatConnection connection
Labs.Menu {
title: i18nc("menu", "NeoChat")
Labs.MenuItem {
enabled: pageStack.layers.currentItem.title !== i18n("Configure NeoChat…")
text: i18nc("menu", "Configure NeoChat…")
shortcut: StandardKey.Preferences
onTriggered: NeoChatSettingsView.open()
}
Labs.MenuItem {
text: i18nc("menu", "Quit NeoChat")
shortcut: StandardKey.Quit
onTriggered: Qt.quit()
}
}
Labs.Menu { Labs.Menu {
title: i18nc("menu", "File") title: i18nc("menu", "File")
@@ -57,19 +74,6 @@ Labs.MenuBar {
}); });
} }
} }
Labs.MenuItem {
enabled: pageStack.layers.currentItem.title !== i18n("Configure NeoChat…")
text: i18nc("menu", "Configure NeoChat…")
shortcut: StandardKey.Preferences
onTriggered: NeoChatSettingsView.open()
}
Labs.MenuItem {
text: i18nc("menu", "Quit NeoChat")
shortcut: StandardKey.Quit
onTriggered: Qt.quit()
}
} }
EditMenu { EditMenu {
title: i18nc("menu", "Edit") title: i18nc("menu", "Edit")

View File

@@ -52,15 +52,6 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
} }
Kirigami.SelectableLabel {
Layout.fillWidth: true
font: Kirigami.Theme.smallFont
textFormat: TextEdit.PlainText
visible: root.currentRoom && root.currentRoom.canonicalAlias
text: root.currentRoom && root.currentRoom.canonicalAlias ? root.currentRoom.canonicalAlias : ""
color: Kirigami.Theme.disabledTextColor
}
Kirigami.Heading { Kirigami.Heading {
text: root.currentRoom.displayName text: root.currentRoom.displayName
@@ -79,14 +70,7 @@ ColumnLayout {
spacing: Kirigami.Units.smallSpacing spacing: Kirigami.Units.smallSpacing
Kirigami.Heading { Kirigami.Heading {
text: root.invitingMember.displayName text: root.currentRoom.displayName
Layout.alignment: Qt.AlignHCenter
}
QQC2.Label {
text: root.invitingMember.id
color: Kirigami.Theme.disabledTextColor
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
} }
@@ -175,7 +159,7 @@ ColumnLayout {
QQC2.Label { QQC2.Label {
color: Kirigami.Theme.disabledTextColor color: Kirigami.Theme.disabledTextColor
text: xi18nc("@info:label Ensure you are referring to the same translation used for that settings page", "You can reject invitations from unknown users under the <interface>Security & Safety</interface> settings.") text: i18nc("@info:label", "You can reject invitations from unknown users under Security settings.")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
// + 5 to prevent it from wrapping unnecessarily // + 5 to prevent it from wrapping unnecessarily

View File

@@ -8,6 +8,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components as KirigamiComponents import org.kde.kirigamiaddons.components as KirigamiComponents
import org.kde.kirigamiaddons.formcard as FormCard import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.prison
import org.kde.neochat import org.kde.neochat
@@ -24,7 +25,7 @@ Kirigami.Dialog {
standardButtons: Kirigami.Dialog.NoButton standardButtons: Kirigami.Dialog.NoButton
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24) width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
title: i18nc("@title:dialog", "Join Room") title: i18nc("@title:dialog", "Join Room")
contentItem: ColumnLayout { contentItem: ColumnLayout {

View File

@@ -60,21 +60,21 @@ Kirigami.ApplicationWindow {
Connections { Connections {
target: LoginHelper target: LoginHelper
function onLoaded(): void { function onLoaded() {
root.load(); root.load();
} }
} }
Connections { Connections {
target: Registration target: Registration
function onLoaded(): void { function onLoaded() {
root.load(); root.load();
} }
} }
Connections { Connections {
target: root.quitAction target: root.quitAction
function onTriggered(): void { function onTriggered() {
Qt.quit(); Qt.quit();
} }
} }
@@ -98,40 +98,42 @@ Kirigami.ApplicationWindow {
Connections { Connections {
target: RoomManager target: RoomManager
function onCurrentRoomChanged(): void { function onCurrentRoomChanged() {
if (RoomManager.currentRoom && pageStack.depth <= 1 && root.initialized && Kirigami.Settings.isMobile) { if (RoomManager.currentRoom && pageStack.depth <= 1 && root.initialized && Kirigami.Settings.isMobile) {
let roomPage = pageStack.layers.push(Qt.createComponent('org.kde.neochat', 'RoomPage')); let roomPage = pageStack.layers.push(Qt.createComponent('org.kde.neochat', 'RoomPage'), {
connection: root.connection
});
roomPage.backRequested.connect(event => { roomPage.backRequested.connect(event => {
RoomManager.clearCurrentRoom(); RoomManager.clearCurrentRoom();
}); });
} }
} }
function onAskJoinRoom(room: NeoChatRoom): void { function onAskJoinRoom(room) {
Qt.createComponent("org.kde.neochat", "JoinRoomDialog").createObject(root, { Qt.createComponent("org.kde.neochat", "JoinRoomDialog").createObject(root, {
room: room, room: room,
connection: root.connection connection: root.connection
}).open(); }).open();
} }
function onShowUserDetail(user, room: NeoChatRoom): void { function onShowUserDetail(user, room) {
root.showUserDetail(user, room); root.showUserDetail(user, room);
} }
function goToEvent(event: string): void { function goToEvent(event) {
if (event.length > 0) { if (event.length > 0) {
roomItem.goToEvent(event); roomItem.goToEvent(event);
} }
roomItem.forceActiveFocus(); roomItem.forceActiveFocus();
} }
function onAskDirectChatConfirmation(user): void { function onAskDirectChatConfirmation(user) {
Qt.createComponent("org.kde.neochat", "AskDirectChatConfirmation").createObject(this, { Qt.createComponent("org.kde.neochat", "AskDirectChatConfirmation").createObject(this, {
user: user user: user
}).open(); }).open();
} }
function onExternalUrl(url): void { function onExternalUrl(url) {
let dialog = Qt.createComponent("org.kde.neochat", "ConfirmUrlDialog").createObject(this); let dialog = Qt.createComponent("org.kde.neochat", "ConfirmUrlDialog").createObject(this);
dialog.link = url; dialog.link = url;
dialog.open(); dialog.open();
@@ -336,7 +338,7 @@ Kirigami.ApplicationWindow {
} }
} }
function handleShare(): void { function handleShare(): void {
const dialog = root.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), { const dialog = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), {
connection: root.connection connection: root.connection
}, { }, {
title: i18nc("@title", "Share"), title: i18nc("@title", "Share"),
@@ -363,7 +365,9 @@ Kirigami.ApplicationWindow {
RoomManager.loadInitialRoom(); RoomManager.loadInitialRoom();
if (!Kirigami.Settings.isMobile) { if (!Kirigami.Settings.isMobile) {
let roomPage = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage')); let roomPage = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage'), {
connection: root.connection
});
roomPage.forceActiveFocus(); roomPage.forceActiveFocus();
} }

View File

@@ -47,7 +47,7 @@ Kirigami.Page {
icon.name: "document-edit" icon.name: "document-edit"
visible: root.allowEdit visible: root.allowEdit
enabled: room.canSendState(root.type) && (!root.stateKey.startsWith("@") || root.stateKey === root.room.connection.localUserId) && root.type !== "m.room.create" enabled: room.canSendState(root.type) && (!root.stateKey.startsWith("@") || root.stateKey === root.room.connection.localUserId) && root.type !== "m.room.create"
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "EditStateDialog"), { onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "EditStateDialog.qml"), {
room: root.room, room: root.room,
type: root.type, type: root.type,
stateKey: root.stateKey, stateKey: root.stateKey,

View File

@@ -72,7 +72,7 @@ Components.AlbumMaximizeComponent {
Connections { Connections {
target: MediaManager target: MediaManager
function onPlaybackStarted(): void { function onPlaybackStarted() {
if (currentItem.playbackState === MediaPlayer.PlayingState) { if (currentItem.playbackState === MediaPlayer.PlayingState) {
currentItem.pause(); currentItem.pause();
} }
@@ -82,7 +82,7 @@ Components.AlbumMaximizeComponent {
Connections { Connections {
target: currentRoom target: currentRoom
function onFileTransferProgress(id: string, progress: int, total: int): void { function onFileTransferProgress(id, progress, total) {
if (id == root.currentEventId) { if (id == root.currentEventId) {
root.downloadAction.progress = progress / total * 100.0; root.downloadAction.progress = progress / total * 100.0;
} }
@@ -130,7 +130,7 @@ Components.AlbumMaximizeComponent {
Connections { Connections {
target: RoomManager target: RoomManager
function onCloseFullScreen(): void { function onCloseFullScreen() {
root.close(); root.close();
} }
} }

View File

@@ -34,7 +34,7 @@ Kirigami.Dialog {
} }
] ]
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24) width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
title: i18nc("@title: create new poll in the room", "Create Poll") title: i18nc("@title: create new poll in the room", "Create Poll")
contentItem: ColumnLayout { contentItem: ColumnLayout {

View File

@@ -22,7 +22,7 @@ Kirigami.Page {
Connections { Connections {
target: root.QQC2.ApplicationWindow.window target: root.QQC2.ApplicationWindow.window
function onClosing(): void { function onClosing() {
root.destroy(); root.destroy();
} }
} }

View File

@@ -6,6 +6,7 @@ import QtQuick.Controls as QQC2
import QtQuick.Layouts import QtQuick.Layouts
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kitemmodels
import org.kde.neochat import org.kde.neochat

View File

@@ -15,6 +15,8 @@ Kirigami.Dialog {
property var connection property var connection
parent: applicationWindow().overlay
leftPadding: 0 leftPadding: 0
rightPadding: 0 rightPadding: 0
topPadding: 0 topPadding: 0
@@ -22,7 +24,7 @@ Kirigami.Dialog {
title: i18nc("@title Join <name of a space>", "Join %1", SpaceHierarchyCache.recommendedSpaceDisplayName) title: i18nc("@title Join <name of a space>", "Join %1", SpaceHierarchyCache.recommendedSpaceDisplayName)
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24) width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
contentItem: ColumnLayout { contentItem: ColumnLayout {
FormCard.AbstractFormDelegate { FormCard.AbstractFormDelegate {

View File

@@ -8,6 +8,7 @@ import QtQuick.Layouts
import QtQuick.Window import QtQuick.Window
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kitemmodels
import org.kde.neochat import org.kde.neochat
@@ -63,9 +64,9 @@ Kirigami.Page {
actions: [ actions: [
Kirigami.Action { Kirigami.Action {
visible: Kirigami.Settings.isMobile || !root.Kirigami.PageStack.pageStack.wideMode visible: Kirigami.Settings.isMobile || !applicationWindow().pageStack.wideMode
icon.name: "view-right-new" icon.name: "view-right-new"
onTriggered: (root.QQC2.ApplicationWindow.window as Main).openRoomDrawer() onTriggered: applicationWindow().openRoomDrawer()
} }
] ]
@@ -80,9 +81,9 @@ Kirigami.Page {
Connections { Connections {
target: root.currentRoom.connection target: root.currentRoom.connection
function onIsOnlineChanged(): void { function onIsOnlineChanged() {
if (!root.currentRoom.connection.isOnline) { if (!root.currentRoom.connection.isOnline) {
banner.text = i18nc("@info:status", "NeoChat is offline. Please check your network connection."); banner.text = i18n("NeoChat is offline. Please check your network connection.");
banner.visible = true; banner.visible = true;
banner.type = Kirigami.MessageType.Error; banner.type = Kirigami.MessageType.Error;
} else { } else {
@@ -137,8 +138,8 @@ Kirigami.Page {
anchors.centerIn: parent anchors.centerIn: parent
sourceComponent: Kirigami.PlaceholderMessage { sourceComponent: Kirigami.PlaceholderMessage {
icon.name: "org.kde.neochat" icon.name: "org.kde.neochat"
text: i18nc("@title", "Welcome to NeoChat") text: i18n("Welcome to NeoChat")
explanation: i18nc("@info:usagetip", "Select or join a room to get started") explanation: i18n("Select or join a room to get started")
} }
} }
@@ -162,20 +163,20 @@ Kirigami.Page {
Connections { Connections {
target: RoomManager target: RoomManager
function onCurrentRoomChanged(): void { function onCurrentRoomChanged() {
if (root.currentRoom && root.currentRoom.isInvite) { if (root.currentRoom && root.currentRoom.isInvite) {
Controller.clearInvitationNotification(root.currentRoom.id); Controller.clearInvitationNotification(root.currentRoom.id);
} }
} }
function onGoToEvent(eventId: string): void { function onGoToEvent(eventId) {
(timelineViewLoader.item as TimelineView).goToEvent(eventId); (timelineViewLoader.item as TimelineView).goToEvent(eventId);
} }
} }
Connections { Connections {
target: root.currentRoom.connection target: root.currentRoom.connection
function onJoinedRoom(room: NeoChatRoom, invited: NeoChatRoom): void { function onJoinedRoom(room, invited) {
if (root.currentRoom.id === invited.id) { if (root.currentRoom.id === invited.id) {
RoomManager.resolveResource(room.id); RoomManager.resolveResource(room.id);
} }
@@ -195,22 +196,22 @@ Kirigami.Page {
Connections { Connections {
target: RoomManager target: RoomManager
function onShowMessage(messageType: Kirigami.MessageType, message: string): void { function onShowMessage(messageType, message) {
banner.text = message; banner.text = message;
banner.type = messageType; banner.type = messageType;
banner.visible = true; banner.visible = true;
} }
function onShowEventSource(eventId: string): void { function onShowEventSource(eventId) {
(root.Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), { applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
sourceText: root.currentRoom.getEventJsonSource(eventId) sourceText: root.currentRoom.getEventJsonSource(eventId)
}, { }, {
title: i18nc("@title:dialog", "Message Source"), title: i18n("Message Source"),
width: Kirigami.Units.gridUnit * 25 width: Kirigami.Units.gridUnit * 25
}); });
} }
function onShowMessageMenu(eventId: string, author, messageComponentType, plainText: string, htmlText: string, selectedText: string, hoveredLink: string, isThread: bool): void { function onShowMessageMenu(eventId, author, messageComponentType, plainText, htmlText, selectedText, hoveredLink, isThread) {
const contextMenu = messageDelegateContextMenu.createObject(root, { const contextMenu = messageDelegateContextMenu.createObject(root, {
selectedText: selectedText, selectedText: selectedText,
hoveredLink: hoveredLink, hoveredLink: hoveredLink,

View File

@@ -67,14 +67,10 @@ QQC2.ComboBox {
QQC2.ToolButton { QQC2.ToolButton {
visible: serverItem.isAddServerDelegate || serverItem.isDeletable visible: serverItem.isAddServerDelegate || serverItem.isDeletable
icon.name: serverItem.isAddServerDelegate ? "list-add" : "dialog-close" icon.name: serverItem.isAddServerDelegate ? "list-add" : "dialog-close"
text: serverItem.isAddServerDelegate ? i18nc("@action:button", "Add new server") : i18nc("@action:button", "Remove server") text: i18nc("@action:button", "Add new server")
Accessible.name: text Accessible.name: text
display: QQC2.AbstractButton.IconOnly display: QQC2.AbstractButton.IconOnly
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
onClicked: { onClicked: {
if (root.currentIndex === serverItem.index && serverItem.isDeletable) { if (root.currentIndex === serverItem.index && serverItem.isDeletable) {
root.currentIndex = 0; root.currentIndex = 0;
@@ -177,7 +173,7 @@ QQC2.ComboBox {
Connections { Connections {
target: serverListModel target: serverListModel
function onServerCheckComplete(url: string, valid: bool): void { function onServerCheckComplete(url, valid) {
if (url == serverUrlField.text && valid) { if (url == serverUrlField.text && valid) {
serverUrlField.isValidServer = true; serverUrlField.isValidServer = true;
} }

View File

@@ -23,6 +23,8 @@ Kirigami.Action {
text: i18n("Share") text: i18n("Share")
tooltip: i18n("Share the selected media") tooltip: i18n("Share the selected media")
visible: false
/** /**
* This property holds the input data for purpose. * This property holds the input data for purpose.
* *
@@ -58,7 +60,7 @@ Kirigami.Action {
if (id != root.eventId) { if (id != root.eventId) {
return; return;
} }
pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "ShareDialog"), { applicationWindow().pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "ShareDialog"), {
title: root.text, title: root.text,
index: index, index: index,
model: root._instantiator.model model: root._instantiator.model

View File

@@ -261,7 +261,7 @@ Kirigami.Dialog {
icon.name: "delete" icon.name: "delete"
icon.color: Kirigami.Theme.negativeTextColor icon.color: Kirigami.Theme.negativeTextColor
onTriggered: { onTriggered: {
let dialog = pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), { let dialog = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
title: i18nc("@title:dialog", "Remove Messages"), title: i18nc("@title:dialog", "Remove Messages"),
placeholder: i18nc("@info:placeholder", "Reason for removing this user's recent messages"), placeholder: i18nc("@info:placeholder", "Reason for removing this user's recent messages"),
actionText: i18nc("@action:button 'Remove' as in 'Remove these messages'", "Remove"), actionText: i18nc("@action:button 'Remove' as in 'Remove these messages'", "Remove"),

View File

@@ -236,18 +236,11 @@ void RoomManager::resolveResource(Uri uri, const QString &action)
} }
} }
void RoomManager::maximizeMedia(const QString &eventId) void RoomManager::maximizeMedia(int index)
{ {
if (eventId.isEmpty()) { if (index < -1 || index > m_mediaMessageFilterModel->rowCount()) {
qWarning() << "Tried to open media for empty event id";
return; return;
} }
const auto index = m_mediaMessageFilterModel->getRowForEventId(eventId);
if (index == -1) {
return;
}
Q_EMIT showMaximizedMedia(index); Q_EMIT showMaximizedMedia(index);
} }
@@ -271,17 +264,8 @@ void RoomManager::viewEventSource(const QString &eventId)
void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText, const QString &hoveredLink) void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText, const QString &hoveredLink)
{ {
if (eventId.isEmpty()) { const auto &event = **room->findInTimeline(eventId);
qWarning() << "Tried to open event menu with empty event id";
return;
}
const auto it = room->findInTimeline(eventId);
if (it == room->historyEdge()) {
// This is probably a pending event
return;
}
const auto &event = **it;
if (EventHandler::mediaInfo(room, &event).contains("mimeType"_L1)) { if (EventHandler::mediaInfo(room, &event).contains("mimeType"_L1)) {
Q_EMIT showFileMenu(eventId, Q_EMIT showFileMenu(eventId,
sender, sender,
@@ -374,6 +358,19 @@ void RoomManager::visitRoom(Room *r, const QString &eventId)
if (m_currentRoom && !m_currentRoom->editCache()->editId().isEmpty()) { if (m_currentRoom && !m_currentRoom->editCache()->editId().isEmpty()) {
m_currentRoom->editCache()->setEditId({}); m_currentRoom->editCache()->setEditId({});
} }
if (m_currentRoom && !m_currentRoom->isSpace() && m_chatDocumentHandler) {
// We're doing these things here because it is critical that they are switched at the same time
if (m_chatDocumentHandler->document()) {
m_currentRoom->mainCache()->setSavedText(m_chatDocumentHandler->document()->textDocument()->toPlainText());
m_chatDocumentHandler->setRoom(room);
if (room) {
m_chatDocumentHandler->document()->textDocument()->setPlainText(room->mainCache()->savedText());
room->mainCache()->setText(room->mainCache()->savedText());
}
} else {
m_chatDocumentHandler->setRoom(room);
}
}
if (!room) { if (!room) {
setCurrentRoom({}); setCurrentRoom({});
@@ -396,9 +393,7 @@ void RoomManager::joinRoom(Quotient::Connection *account, const QString &roomAli
// If no one gives us a homeserver suggestion, try the server specified in the alias/id. // If no one gives us a homeserver suggestion, try the server specified in the alias/id.
// Otherwise joining a remote room not on our homeserver will fail. // Otherwise joining a remote room not on our homeserver will fail.
// This is a hack and we're not supposed to do it. With room ids not containing the server going forward, it won't work anymore for new room versions. if (vias.empty()) {
// FIXME: Let's keep it around anyway for now, remove it at some point, though
if (vias.empty() && roomAliasOrId.contains(':'_L1)) {
vias.append(roomAliasOrId.mid(roomAliasOrId.lastIndexOf(':'_L1) + 1)); vias.append(roomAliasOrId.mid(roomAliasOrId.lastIndexOf(':'_L1) + 1));
} }
@@ -473,6 +468,18 @@ bool RoomManager::visitNonMatrix(const QUrl &url)
return true; return true;
} }
ChatDocumentHandler *RoomManager::chatDocumentHandler() const
{
return m_chatDocumentHandler;
}
void RoomManager::setChatDocumentHandler(ChatDocumentHandler *handler)
{
m_chatDocumentHandler = handler;
m_chatDocumentHandler->setRoom(m_currentRoom);
Q_EMIT chatDocumentHandlerChanged();
}
void RoomManager::setConnection(NeoChatConnection *connection) void RoomManager::setConnection(NeoChatConnection *connection)
{ {
if (m_connection == connection) { if (m_connection == connection) {

View File

@@ -11,6 +11,7 @@
#include <Quotient/roommember.h> #include <Quotient/roommember.h>
#include <Quotient/uriresolver.h> #include <Quotient/uriresolver.h>
#include "chatdocumenthandler.h"
#include "enums/messagecomponenttype.h" #include "enums/messagecomponenttype.h"
#include "enums/messagetype.h" #include "enums/messagetype.h"
#include "models/mediamessagefiltermodel.h" #include "models/mediamessagefiltermodel.h"
@@ -136,6 +137,13 @@ class RoomManager : public QObject, public UriResolverBase
*/ */
Q_PROPERTY(bool hasOpenRoom READ hasOpenRoom NOTIFY currentRoomChanged) Q_PROPERTY(bool hasOpenRoom READ hasOpenRoom NOTIFY currentRoomChanged)
/**
* @brief The ChatDocumentHandler for the open room.
*
* @sa ChatDocumentHandler
*/
Q_PROPERTY(ChatDocumentHandler *chatDocumentHandler READ chatDocumentHandler WRITE setChatDocumentHandler NOTIFY chatDocumentHandlerChanged)
public: public:
virtual ~RoomManager(); virtual ~RoomManager();
static RoomManager &instance(); static RoomManager &instance();
@@ -204,8 +212,12 @@ public:
/** /**
* @brief Show a media item maximized. * @brief Show a media item maximized.
*
* @param index the index to open the maximize delegate model at. This is the
* index in the MediaMessageFilterModel owned by this RoomManager. A value
* of -1 opens a the default item.
*/ */
Q_INVOKABLE void maximizeMedia(const QString &eventId); Q_INVOKABLE void maximizeMedia(int index);
Q_INVOKABLE void maximizeCode(NeochatRoomMember *author, const QDateTime &time, const QString &codeText, const QString &language); Q_INVOKABLE void maximizeCode(NeochatRoomMember *author, const QDateTime &time, const QString &codeText, const QString &language);
@@ -225,6 +237,9 @@ public:
Q_INVOKABLE void Q_INVOKABLE void
viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText = {}, const QString &hoveredLink = {}); viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText = {}, const QString &hoveredLink = {});
ChatDocumentHandler *chatDocumentHandler() const;
void setChatDocumentHandler(ChatDocumentHandler *handler);
/** /**
* @brief Set a URL to be loaded as the initial room. * @brief Set a URL to be loaded as the initial room.
*/ */
@@ -327,6 +342,8 @@ Q_SIGNALS:
*/ */
void showMessage(MessageType::Type messageType, const QString &message); void showMessage(MessageType::Type messageType, const QString &message);
void chatDocumentHandlerChanged();
void connectionChanged(); void connectionChanged();
void directChatsActiveChanged(); void directChatsActiveChanged();
@@ -355,6 +372,7 @@ private:
KConfigGroup m_lastRoomConfig; KConfigGroup m_lastRoomConfig;
KConfigGroup m_lastSpaceConfig; KConfigGroup m_lastSpaceConfig;
KConfigGroup m_directChatsConfig; KConfigGroup m_directChatsConfig;
QPointer<ChatDocumentHandler> m_chatDocumentHandler;
RoomListModel *m_roomListModel; RoomListModel *m_roomListModel;
SortFilterRoomListModel *m_sortFilterRoomListModel; SortFilterRoomListModel *m_sortFilterRoomListModel;

View File

@@ -5,8 +5,6 @@
#include <QDBusMetaType> #include <QDBusMetaType>
#include <KWindowSystem>
#include "controller.h" #include "controller.h"
#include "models/roomlistmodel.h" #include "models/roomlistmodel.h"
#include "models/sortfilterroomlistmodel.h" #include "models/sortfilterroomlistmodel.h"
@@ -88,9 +86,4 @@ void Runner::Run(const QString &id, const QString &actionId)
WindowController::instance().showAndRaiseWindow(QString()); WindowController::instance().showAndRaiseWindow(QString());
} }
void Runner::SetActivationToken(const QString &token)
{
KWindowSystem::setCurrentXdgActivationToken(token);
}
#include "moc_runner.cpp" #include "moc_runner.cpp"

View File

@@ -190,8 +190,6 @@ public:
*/ */
Q_SCRIPTABLE void Run(const QString &id, const QString &actionId); Q_SCRIPTABLE void Run(const QString &id, const QString &actionId);
Q_SCRIPTABLE void SetActivationToken(const QString &token);
Q_SIGNALS: Q_SIGNALS:
void roomListModelChanged(); void roomListModelChanged();

View File

@@ -87,7 +87,7 @@ QQC2.Control {
displayHint: Kirigami.DisplayHint.IconOnly displayHint: Kirigami.DisplayHint.IconOnly
onTriggered: { onTriggered: {
let dialog = (Clipboard.hasImage ? attachDialog : openFileDialog).createObject(root.QQC2.Overlay.overlay); let dialog = (Clipboard.hasImage ? attachDialog : openFileDialog).createObject(applicationWindow().overlay);
dialog.chosen.connect(path => _private.chatBarCache.attachmentPath = path); dialog.chosen.connect(path => _private.chatBarCache.attachmentPath = path);
dialog.open(); dialog.open();
} }
@@ -197,22 +197,6 @@ QQC2.Control {
visible: root.currentRoom.mainCache.replyId.length > 0 visible: root.currentRoom.mainCache.replyId.length > 0
sourceComponent: replyPane sourceComponent: replyPane
} }
RowLayout {
visible: replyLoader.visible && !root.currentRoom.mainCache.relationAuthorIsPresent
spacing: Kirigami.Units.smallSpacing
Kirigami.Icon {
source: "help-hint-symbolic"
color: Kirigami.Theme.disabledTextColor
Layout.preferredWidth: Kirigami.Units.iconSizes.small
Layout.preferredHeight: Kirigami.Units.iconSizes.small
}
QQC2.Label {
text: i18nc("@info", "The user you're replying to has left the room, and can't be notified.")
color: Kirigami.Theme.disabledTextColor
}
}
Loader { Loader {
id: attachLoader id: attachLoader
@@ -398,6 +382,8 @@ QQC2.Control {
implicitHeight: replyComponent.implicitHeight implicitHeight: replyComponent.implicitHeight
ReplyComponent { ReplyComponent {
id: replyComponent id: replyComponent
replyEventId: _private.chatBarCache.replyId
replyAuthor: _private.chatBarCache.relationAuthor
replyContentModel: ContentProvider.contentModelForEvent(root.currentRoom, _private.chatBarCache.replyId, true) replyContentModel: ContentProvider.contentModelForEvent(root.currentRoom, _private.chatBarCache.replyId, true)
Message.maxContentWidth: replyLoader.item.width Message.maxContentWidth: replyLoader.item.width
@@ -438,6 +424,7 @@ QQC2.Control {
QtObject { QtObject {
id: _private id: _private
property ChatBarCache chatBarCache property ChatBarCache chatBarCache
onChatBarCacheChanged: documentHandler.chatBarCache = chatBarCache
function postMessage() { function postMessage() {
_private.chatBarCache.postMessage(); _private.chatBarCache.postMessage();
@@ -499,14 +486,15 @@ QQC2.Control {
ChatDocumentHandler { ChatDocumentHandler {
id: documentHandler id: documentHandler
type: ChatBarType.Room
room: root.currentRoom
document: textField.textDocument document: textField.textDocument
cursorPosition: textField.cursorPosition cursorPosition: textField.cursorPosition
selectionStart: textField.selectionStart selectionStart: textField.selectionStart
selectionEnd: textField.selectionEnd selectionEnd: textField.selectionEnd
mentionColor: Kirigami.Theme.linkColor mentionColor: Kirigami.Theme.linkColor
errorColor: Kirigami.Theme.negativeTextColor errorColor: Kirigami.Theme.negativeTextColor
Component.onCompleted: {
RoomManager.chatDocumentHandler = documentHandler;
}
} }
Component { Component {

View File

@@ -25,7 +25,7 @@ QQC2.Popup {
Connections { Connections {
target: RoomManager target: RoomManager
function onCurrentRoomChanged(): void { function onCurrentRoomChanged() {
root.close(); root.close();
} }
} }
@@ -65,7 +65,7 @@ QQC2.Popup {
padding: 2 padding: 2
implicitHeight: Kirigami.Units.gridUnit * 20 + 2 * padding implicitHeight: Kirigami.Units.gridUnit * 20 + 2 * padding
width: Math.min(contentItem.categoryIconSize * 11 + 2 * padding, QQC2.ApplicationWindow.window.width) width: Math.min(contentItem.categoryIconSize * 11 + 2 * padding, applicationWindow().width)
contentItem: EmojiPicker { contentItem: EmojiPicker {
id: emojiPicker id: emojiPicker
height: 400 height: 400

View File

@@ -100,7 +100,7 @@ Kirigami.Page {
} }
Connections { Connections {
target: selectionTool.selectionArea target: selectionTool.selectionArea
function onDoubleClicked(): void { function onDoubleClicked() {
rootEditorView.crop(); rootEditorView.crop();
} }
} }

View File

@@ -20,13 +20,6 @@ FormCard.FormCard {
onToggled: NeoChatConfig.showAllEvents = checked onToggled: NeoChatConfig.showAllEvents = checked
} }
FormCard.FormCheckDelegate {
text: i18nc("@option:check", "Allow sending relations to any event in the timeline")
description: i18nc("@info", "This includes state events")
checked: NeoChatConfig.relateAnyEvent
onToggled: NeoChatConfig.relateAnyEvent = checked
}
FormCard.FormCheckDelegate { FormCard.FormCheckDelegate {
id: roomAccountDataVisibleCheck id: roomAccountDataVisibleCheck
text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification") text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification")

View File

@@ -7,6 +7,7 @@ import QtQuick.Window
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.kitemmodels
import org.kde.neochat import org.kde.neochat

View File

@@ -7,6 +7,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.kitemmodels
import org.kde.neochat import org.kde.neochat

View File

@@ -7,6 +7,7 @@ import QtQuick.Window
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.kitemmodels
import org.kde.neochat import org.kde.neochat

View File

@@ -22,7 +22,6 @@ target_sources(LibNeoChat PRIVATE
texthandler.cpp texthandler.cpp
urlhelper.cpp urlhelper.cpp
utils.cpp utils.cpp
enums/chatbartype.h
enums/messagecomponenttype.h enums/messagecomponenttype.h
enums/messagetype.h enums/messagetype.h
enums/powerlevel.cpp enums/powerlevel.cpp

View File

@@ -173,7 +173,7 @@ void AccountManager::addConnection(NeoChatConnection *connection)
}); });
connect(connection, &NeoChatConnection::loggedOut, this, [this, connection] { connect(connection, &NeoChatConnection::loggedOut, this, [this, connection] {
// Only set the connection if the account being logged out is currently active // Only set the connection if the account being logged out is currently active
if (m_accountRegistry->accounts().count() == 1 && connection == activeConnection()) { if (m_accountRegistry->accounts().count() > 1 && connection == activeConnection()) {
setActiveConnection(dynamic_cast<NeoChatConnection *>(m_accountRegistry->accounts()[0])); setActiveConnection(dynamic_cast<NeoChatConnection *>(m_accountRegistry->accounts()[0]));
} else { } else {
setActiveConnection(nullptr); setActiveConnection(nullptr);

View File

@@ -15,18 +15,6 @@ using namespace Qt::StringLiterals;
ChatBarCache::ChatBarCache(QObject *parent) ChatBarCache::ChatBarCache(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
if (parent == nullptr) {
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
return;
}
auto room = dynamic_cast<NeoChatRoom *>(parent);
if (room == nullptr) {
qWarning() << "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.";
return;
}
connect(room, &NeoChatRoom::memberLeft, this, &ChatBarCache::relationAuthorIsPresentChanged);
connect(room, &NeoChatRoom::memberJoined, this, &ChatBarCache::relationAuthorIsPresentChanged);
connect(this, &ChatBarCache::relationIdChanged, this, &ChatBarCache::relationAuthorIsPresentChanged);
} }
QString ChatBarCache::text() const QString ChatBarCache::text() const
@@ -149,11 +137,6 @@ Quotient::RoomMember ChatBarCache::relationAuthor() const
return room->member((*room->findInTimeline(m_relationId))->senderId()); return room->member((*room->findInTimeline(m_relationId))->senderId());
} }
bool ChatBarCache::relationAuthorIsPresent() const
{
return relationAuthor().membershipState() == Quotient::Membership::Join;
}
QString ChatBarCache::relationMessage() const QString ChatBarCache::relationMessage() const
{ {
if (parent() == nullptr) { if (parent() == nullptr) {

View File

@@ -99,13 +99,6 @@ class ChatBarCache : public QObject
*/ */
Q_PROPERTY(Quotient::RoomMember relationAuthor READ relationAuthor NOTIFY relationIdChanged) Q_PROPERTY(Quotient::RoomMember relationAuthor READ relationAuthor NOTIFY relationIdChanged)
/**
* @brief If the author for the message being replied to is still present in the room.
*
* @sa Quotient::RoomMember
*/
Q_PROPERTY(bool relationAuthorIsPresent READ relationAuthorIsPresent NOTIFY relationAuthorIsPresentChanged)
/** /**
* @brief The content of the related message. * @brief The content of the related message.
* *
@@ -160,7 +153,6 @@ public:
void setEditId(const QString &editId); void setEditId(const QString &editId);
Quotient::RoomMember relationAuthor() const; Quotient::RoomMember relationAuthor() const;
bool relationAuthorIsPresent() const;
QString relationMessage() const; QString relationMessage() const;
@@ -204,7 +196,6 @@ Q_SIGNALS:
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId); void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
void attachmentPathChanged(); void attachmentPathChanged();
void mentionAdded(const QString &mention); void mentionAdded(const QString &mention);
void relationAuthorIsPresentChanged();
private: private:
QString m_text = QString(); QString m_text = QString();

View File

@@ -14,7 +14,6 @@
#include <Sonnet/BackgroundChecker> #include <Sonnet/BackgroundChecker>
#include <Sonnet/Settings> #include <Sonnet/Settings>
#include "chatbartype.h"
#include "chatdocumenthandler_logging.h" #include "chatdocumenthandler_logging.h"
#include "eventhandler.h" #include "eventhandler.h"
@@ -68,11 +67,7 @@ public:
if (!room) { if (!room) {
return; return;
} }
const auto chatchache = handler->chatBarCache(); auto mentions = handler->chatBarCache()->mentions();
if (!chatchache) {
return;
}
auto mentions = chatchache->mentions();
mentions->erase(std::remove_if(mentions->begin(), mentions->erase(std::remove_if(mentions->begin(),
mentions->end(), mentions->end(),
[this](auto &mention) { [this](auto &mention) {
@@ -110,6 +105,18 @@ ChatDocumentHandler::ChatDocumentHandler(QObject *parent)
, m_highlighter(new SyntaxHighlighter(this)) , m_highlighter(new SyntaxHighlighter(this))
, m_completionModel(new CompletionModel(this)) , m_completionModel(new CompletionModel(this))
{ {
connect(this, &ChatDocumentHandler::roomChanged, this, [this]() {
m_completionModel->setRoom(m_room);
static QPointer<NeoChatRoom> previousRoom = nullptr;
if (previousRoom) {
disconnect(m_chatBarCache, &ChatBarCache::textChanged, this, nullptr);
}
previousRoom = m_room;
connect(m_chatBarCache, &ChatBarCache::textChanged, this, [this]() {
int start = completionStartIndex();
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
});
});
connect(this, &ChatDocumentHandler::documentChanged, this, [this]() { connect(this, &ChatDocumentHandler::documentChanged, this, [this]() {
if (!m_document) { if (!m_document) {
m_highlighter->setDocument(nullptr); m_highlighter->setDocument(nullptr);
@@ -146,20 +153,6 @@ int ChatDocumentHandler::completionStartIndex() const
return start; return start;
} }
ChatBarType::Type ChatDocumentHandler::type() const
{
return m_type;
}
void ChatDocumentHandler::setType(ChatBarType::Type type)
{
if (type == m_type) {
return;
}
m_type = type;
Q_EMIT typeChanged();
}
QQuickTextDocument *ChatDocumentHandler::document() const QQuickTextDocument *ChatDocumentHandler::document() const
{ {
return m_document; return m_document;
@@ -205,36 +198,22 @@ void ChatDocumentHandler::setRoom(NeoChatRoom *room)
return; return;
} }
if (m_room && m_type != ChatBarType::None) {
m_room->cacheForType(m_type)->disconnect(this);
if (!m_room->isSpace() && m_document && m_type == ChatBarType::Room) {
m_room->mainCache()->setSavedText(document()->textDocument()->toPlainText());
}
}
m_room = room; m_room = room;
m_completionModel->setRoom(m_room);
if (m_room && m_type != ChatBarType::None) {
connect(m_room->cacheForType(m_type), &ChatBarCache::textChanged, this, [this]() {
int start = completionStartIndex();
m_completionModel->setText(getText().mid(start, cursorPosition() - start), getText().mid(start));
});
if (!m_room->isSpace() && m_document && m_type == ChatBarType::Room) {
document()->textDocument()->setPlainText(room->mainCache()->savedText());
m_room->mainCache()->setText(room->mainCache()->savedText());
}
}
Q_EMIT roomChanged(); Q_EMIT roomChanged();
} }
ChatBarCache *ChatDocumentHandler::chatBarCache() const ChatBarCache *ChatDocumentHandler::chatBarCache() const
{ {
if (!m_room || m_type == ChatBarType::None) { return m_chatBarCache;
return nullptr; }
void ChatDocumentHandler::setChatBarCache(ChatBarCache *chatBarCache)
{
if (m_chatBarCache == chatBarCache) {
return;
} }
return m_room->cacheForType(m_type); m_chatBarCache = chatBarCache;
Q_EMIT chatBarCacheChanged();
} }
void ChatDocumentHandler::complete(int index) void ChatDocumentHandler::complete(int index)
@@ -334,20 +313,20 @@ void ChatDocumentHandler::setSelectionEnd(int position)
QString ChatDocumentHandler::getText() const QString ChatDocumentHandler::getText() const
{ {
if (!m_room || m_type == ChatBarType::None) { if (!m_chatBarCache) {
qCWarning(ChatDocumentHandling) << "getText called with no ChatBarCache available. ChatBarType: " << m_type << " Room: " << m_room; qCWarning(ChatDocumentHandling) << "getText called with m_chatBarCache set to nullptr.";
return {}; return {};
} }
return m_room->cacheForType(m_type)->text(); return m_chatBarCache->text();
} }
void ChatDocumentHandler::pushMention(const Mention mention) const void ChatDocumentHandler::pushMention(const Mention mention) const
{ {
if (!m_room || m_type == ChatBarType::None) { if (!m_chatBarCache) {
qCWarning(ChatDocumentHandling) << "pushMention called with no ChatBarCache available. ChatBarType: " << m_type << " Room: " << m_room; qCWarning(ChatDocumentHandling) << "pushMention called with m_chatBarCache set to nullptr.";
return; return;
} }
m_room->cacheForType(m_type)->mentions()->push_back(mention); m_chatBarCache->mentions()->push_back(mention);
} }
QColor ChatDocumentHandler::mentionColor() const QColor ChatDocumentHandler::mentionColor() const
@@ -386,7 +365,7 @@ void ChatDocumentHandler::updateMentions(QQuickTextDocument *document, const QSt
{ {
setDocument(document); setDocument(document);
if (editId.isEmpty() || m_type == ChatBarType::None || !m_room) { if (editId.isEmpty() || !m_chatBarCache || !m_room) {
return; return;
} }
@@ -395,7 +374,7 @@ void ChatDocumentHandler::updateMentions(QQuickTextDocument *document, const QSt
// Replaces the mentions that are baked into the HTML but plaintext in the original markdown // Replaces the mentions that are baked into the HTML but plaintext in the original markdown
const QRegularExpression re(uR"lit(<a\shref="https:\/\/matrix.to\/#\/([\S]*)"\s?>([\S]*)<\/a>)lit"_s); const QRegularExpression re(uR"lit(<a\shref="https:\/\/matrix.to\/#\/([\S]*)"\s?>([\S]*)<\/a>)lit"_s);
m_room->cacheForType(m_type)->mentions()->clear(); m_chatBarCache->mentions()->clear();
int linkSize = 0; int linkSize = 0;
auto matches = re.globalMatch(EventHandler::rawMessageBody(*roomMessageEvent)); auto matches = re.globalMatch(EventHandler::rawMessageBody(*roomMessageEvent));

View File

@@ -9,7 +9,6 @@
#include <QTextCursor> #include <QTextCursor>
#include "chatbarcache.h" #include "chatbarcache.h"
#include "enums/chatbartype.h"
#include "models/completionmodel.h" #include "models/completionmodel.h"
#include "neochatroom.h" #include "neochatroom.h"
@@ -63,11 +62,6 @@ class ChatDocumentHandler : public QObject
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
/**
* @brief The QQuickTextDocument that is being handled.
*/
Q_PROPERTY(ChatBarType::Type type READ type WRITE setType NOTIFY typeChanged)
/** /**
* @brief The QQuickTextDocument that is being handled. * @brief The QQuickTextDocument that is being handled.
*/ */
@@ -101,6 +95,11 @@ class ChatDocumentHandler : public QObject
*/ */
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged) Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
/**
* @brief The cache for the chat bar the text document is being handled for.
*/
Q_PROPERTY(ChatBarCache *chatBarCache READ chatBarCache WRITE setChatBarCache NOTIFY chatBarCacheChanged)
/** /**
* @brief The color to highlight user mentions. * @brief The color to highlight user mentions.
*/ */
@@ -114,9 +113,6 @@ class ChatDocumentHandler : public QObject
public: public:
explicit ChatDocumentHandler(QObject *parent = nullptr); explicit ChatDocumentHandler(QObject *parent = nullptr);
ChatBarType::Type type() const;
void setType(ChatBarType::Type type);
[[nodiscard]] QQuickTextDocument *document() const; [[nodiscard]] QQuickTextDocument *document() const;
void setDocument(QQuickTextDocument *document); void setDocument(QQuickTextDocument *document);
@@ -132,7 +128,8 @@ public:
[[nodiscard]] NeoChatRoom *room() const; [[nodiscard]] NeoChatRoom *room() const;
void setRoom(NeoChatRoom *room); void setRoom(NeoChatRoom *room);
ChatBarCache *chatBarCache() const; [[nodiscard]] ChatBarCache *chatBarCache() const;
void setChatBarCache(ChatBarCache *chatBarCache);
Q_INVOKABLE void complete(int index); Q_INVOKABLE void complete(int index);
@@ -150,10 +147,10 @@ public:
Q_INVOKABLE void updateMentions(QQuickTextDocument *document, const QString &editId); Q_INVOKABLE void updateMentions(QQuickTextDocument *document, const QString &editId);
Q_SIGNALS: Q_SIGNALS:
void typeChanged();
void documentChanged(); void documentChanged();
void cursorPositionChanged(); void cursorPositionChanged();
void roomChanged(); void roomChanged();
void chatBarCacheChanged();
void selectionStartChanged(); void selectionStartChanged();
void selectionEndChanged(); void selectionEndChanged();
void errorColorChanged(); void errorColorChanged();
@@ -162,10 +159,10 @@ Q_SIGNALS:
private: private:
int completionStartIndex() const; int completionStartIndex() const;
ChatBarType::Type m_type = ChatBarType::None;
QPointer<QQuickTextDocument> m_document; QPointer<QQuickTextDocument> m_document;
QPointer<NeoChatRoom> m_room; QPointer<NeoChatRoom> m_room;
QPointer<ChatBarCache> m_chatBarCache;
QColor m_mentionColor; QColor m_mentionColor;
QColor m_errorColor; QColor m_errorColor;

View File

@@ -1,31 +0,0 @@
// SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <QObject>
#include <QQmlEngine>
/**
* @class ChatBarType
*
* This class is designed to define the ChatBarType enumeration.
*/
class ChatBarType : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
public:
/**
* @brief The type of chatbar.
*/
enum Type {
Room = 0, /**< A standard room chatbar for creating new messages. */
Edit, /**< A chatbar for editing an existing message. */
Thread, /**< A chatbar for creating a new threaded message. */
None, /**< Undefined. */
};
Q_ENUM(Type);
};

View File

@@ -70,23 +70,13 @@ public:
* *
* @param event the event to return a type for. * @param event the event to return a type for.
* *
* @param isInReply whether this event is to be treated like a replied-to event (i.e., a basic text fallback should be shown if no other type is used)
*
* @sa Type * @sa Type
*/ */
static Type typeForEvent(const Quotient::RoomEvent &event, bool isInReply = false) static Type typeForEvent(const Quotient::RoomEvent &event)
{ {
using namespace Quotient; using namespace Quotient;
if (event.isRedacted()) {
return MessageComponentType::Text;
}
if (const auto e = eventCast<const RoomMessageEvent>(&event)) { if (const auto e = eventCast<const RoomMessageEvent>(&event)) {
if (e->rawMsgtype() == u"m.key.verification.request"_s) {
return MessageComponentType::Verification;
}
switch (e->msgtype()) { switch (e->msgtype()) {
case MessageEventType::Emote: case MessageEventType::Emote:
return MessageComponentType::Text; return MessageComponentType::Text;
@@ -113,8 +103,7 @@ public:
if (event.matrixType() == u"org.matrix.msc3672.beacon_info"_s) { if (event.matrixType() == u"org.matrix.msc3672.beacon_info"_s) {
return MessageComponentType::LiveLocation; return MessageComponentType::LiveLocation;
} }
// In the (unlikely) case that this is a reply to a state event, we do want to show something return MessageComponentType::Other;
return isInReply ? MessageComponentType::Text : MessageComponentType::Other;
} }
if (is<const EncryptedEvent>(event)) { if (is<const EncryptedEvent>(event)) {
return MessageComponentType::Encrypted; return MessageComponentType::Encrypted;
@@ -127,8 +116,7 @@ public:
return MessageComponentType::Poll; return MessageComponentType::Poll;
} }
// In the (unlikely) case that this is a reply to an unusual event, we do want to show something return MessageComponentType::Other;
return isInReply ? MessageComponentType::Text : MessageComponentType::Other;
} }
/** /**

View File

@@ -198,10 +198,6 @@ bool EventHandler::isHidden(const NeoChatRoom *room, const Quotient::RoomEvent *
Qt::TextFormat EventHandler::messageBodyInputFormat(const Quotient::RoomMessageEvent &event) Qt::TextFormat EventHandler::messageBodyInputFormat(const Quotient::RoomMessageEvent &event)
{ {
if (event.isRedacted() && !event.isStateEvent()) {
return Qt::RichText;
}
if (event.mimeType().name() == "text/plain"_L1) { if (event.mimeType().name() == "text/plain"_L1) {
return Qt::PlainText; return Qt::PlainText;
} else { } else {
@@ -211,11 +207,6 @@ Qt::TextFormat EventHandler::messageBodyInputFormat(const Quotient::RoomMessageE
QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event) QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
{ {
if (event.isRedacted() && !event.isStateEvent()) {
auto reason = event.redactedBecause()->reason();
return (reason.isEmpty()) ? i18n("<i>[This message was deleted]</i>") : i18n("<i>[This message was deleted: %1]</i>", reason.toHtmlEscaped());
}
QString body; QString body;
if (event.has<EventContent::FileContent>()) { if (event.has<EventContent::FileContent>()) {
@@ -457,12 +448,6 @@ QString EventHandler::getBody(const NeoChatRoom *room, const Quotient::RoomEvent
[](const PollStartEvent &e) { [](const PollStartEvent &e) {
return e.question(); return e.question();
}, },
[](const EncryptedEvent &) {
return i18nc("@info In room list", "Encrypted event");
},
[](const ReactionEvent &e) {
return i18nc("[user] reacted with <emoji>", "reacted with %1", e.key());
},
i18n("Unknown event")); i18n("Unknown event"));
} }

View File

@@ -7,12 +7,12 @@
struct MessageComponent { struct MessageComponent {
MessageComponentType::Type type = MessageComponentType::Other; MessageComponentType::Type type = MessageComponentType::Other;
QString display; QString content;
QVariantMap attributes; QVariantMap attributes;
bool operator==(const MessageComponent &right) const bool operator==(const MessageComponent &right) const
{ {
return type == right.type && display == right.display && attributes == right.attributes; return type == right.type && content == right.content && attributes == right.attributes;
} }
bool isEmpty() const bool isEmpty() const

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