Compare commits
1 Commits
v24.05.2
...
work/jz/fl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae155805e9 |
@@ -2,7 +2,7 @@
|
||||
"id": "org.kde.neochat",
|
||||
"branch": "master",
|
||||
"runtime": "org.kde.Platform",
|
||||
"runtime-version": "6.6",
|
||||
"runtime-version": "6.7",
|
||||
"sdk": "org.kde.Sdk",
|
||||
"command": "neochat",
|
||||
"tags": [
|
||||
@@ -110,7 +110,7 @@
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/quotient-im/libQuotient.git",
|
||||
"branch": "0.8.x",
|
||||
"branch": "dev",
|
||||
"disable-submodules": true
|
||||
}
|
||||
],
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,4 +12,3 @@ kate.project.ctags.*
|
||||
.idea/
|
||||
cmake-build-*
|
||||
src/res.generated.qrc
|
||||
.qmlls.ini
|
||||
|
||||
@@ -28,7 +28,6 @@ Dependencies:
|
||||
'frameworks/kio': '@latest-kf6'
|
||||
'frameworks/kwindowsystem': '@latest-kf6'
|
||||
'frameworks/kstatusnotifieritem': '@latest-kf6'
|
||||
'frameworks/kcrash': '@latest-kf6'
|
||||
- 'on': ['Linux', 'FreeBSD']
|
||||
'require':
|
||||
'frameworks/kdbusaddons': '@latest-kf6'
|
||||
@@ -40,4 +39,4 @@ Dependencies:
|
||||
|
||||
Options:
|
||||
per-test-timeout: 90
|
||||
require-passing-tests-on: [ 'Linux', 'Android', 'FreeBSD' ]
|
||||
require-passing-tests-on: [ '@all' ]
|
||||
|
||||
@@ -8,8 +8,8 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "24")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "05")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "2")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "04")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
@@ -84,7 +84,7 @@ if(ANDROID)
|
||||
)
|
||||
else()
|
||||
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem Crash)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem)
|
||||
find_package(KF6SyntaxHighlighting ${KF_MIN_VERSION} REQUIRED)
|
||||
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
|
||||
TYPE RUNTIME
|
||||
|
||||
48
README.md
48
README.md
@@ -1,6 +1,6 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2020-2021 Carl Schwan <carlschwan@kde.org>
|
||||
SPDX-FileCopyrightText: 2020-2024 Tobias Fella <tobias.fella@kde.org>
|
||||
SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
||||
SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
@@ -16,18 +16,19 @@ A Qt/QML based Matrix client.
|
||||
## Introduction
|
||||
|
||||
NeoChat is a client for [Matrix](https://matrix.org), the decentralized communication protocol for instant
|
||||
messaging.
|
||||
messaging. It is a fork of Spectral, using KDE frameworks, most notably [Kirigami](https://invent.kde.org/frameworks/kirigami)
|
||||
to provide a convergent experience across multiple platforms.
|
||||
|
||||
NeoChat is based on KDE frameworks and as [libQuotient](https://github.com/quotient-im/libQuotient), a
|
||||
NeoChat also make use of other KDE Frameworks as well as [libQuotient](https://github.com/quotient-im/libQuotient), a
|
||||
Qt-based SDK for the [Matrix Protocol](https://spec.matrix.org/).
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
NeoChat aims to be a fully featured application for the Matrix specification. As such most parts of the current specification are supported, with the notable exceptions
|
||||
of VoIP, threads, and some aspects of End-to-End Encryption. There are a few other smaller omissions due to the fact that the Matrix spec is constantly
|
||||
evolving, but the aim remains to provide eventual support for the entire spec.
|
||||
NeoChat aims to be a fully featured application for the Matrix specification. As such everything in the current stable specification with the notable exceptions
|
||||
of VoIP, threads and some aspects of End-to-End Encryption are supported. There are a few other smaller omissions due to the fact that the Matrix spec is constantly
|
||||
evolving but the aim remains to provide eventual support for the entire spec.
|
||||
|
||||
Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:
|
||||
- Polls - MSC3381
|
||||
@@ -38,9 +39,26 @@ Due to the nature of the Matrix specification development NeoChat also supports
|
||||
|
||||
Details where to find stable releases for NeoChat can be found on its [homepage](https://apps.kde.org/neochat).
|
||||
|
||||
Nightly builds for linux and windows can be downloaded from [cdn.kde.org](https://cdn.kde.org/ci-builds/network/neochat/).
|
||||
Nightly builds for android are available from [KDE's nightly F-Droid repository](https://community.kde.org/Android/F-Droid).
|
||||
Nightly Flatpaks are available from [KDE's nightly Flatpak repository](https://userbase.kde.org/Tutorials/Flatpak).
|
||||
In addition to the stable builds, unstable nightly builds are available for all platforms. These can be downloaded
|
||||
from the [binary factory](https://binary-factory.kde.org/). There are unstable versions for the following platforms
|
||||
in addition to stable ones:
|
||||
- Android
|
||||
- MacOS
|
||||
- Windows
|
||||
|
||||
Additionally the nightly Flatpak version can be obtained from the nightly Flatpak repo using the following commands in your terminal:
|
||||
|
||||
```
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
flatpak remote-add --if-not-exists kdeapps --from https://distribute.kde.org/kdeapps.flatpakrepo
|
||||
flatpak install kdeapps org.kde.neochat
|
||||
```
|
||||
|
||||
The unstable Android version can also be obtained from the [KDE nightly F-Droid repo](https://community.kde.org/Android/FDroid).
|
||||
|
||||
## Running
|
||||
|
||||
Just start the executable in your preferred way - either from the build directory or from the installed location.
|
||||
|
||||
## Building NeoChat
|
||||
|
||||
@@ -51,18 +69,14 @@ is primarily aimed at Linux development.
|
||||
For Windows and Android [Craft](https://invent.kde.org/packaging/craft) is the primary choice. There are guides for setting up
|
||||
development environments for [Windows](https://community.kde.org/Get_Involved/development/Windows) and [Android](https://develop.kde.org/docs/packaging/android/building_applications/).
|
||||
|
||||
## Running
|
||||
|
||||
Just start the executable in your preferred way - either from the build directory or from the installed location.
|
||||
|
||||
## Tests
|
||||
|
||||
Tests are in the repository under [autotests](autotests) and [appiumtests](appiumtests).
|
||||
Tests are in the repository under [autotests](autotests) and should all pass for any contribution.
|
||||
|
||||
The project has CI setup to test new commits to the repository. All tests are expected to pass for a merge request to
|
||||
be complete.
|
||||
|
||||
## Current build status
|
||||
Current build status
|
||||
|
||||

|
||||
|
||||
@@ -86,9 +100,9 @@ The best place to reach the maintainers is on the KDE Matrix instance in the Neo
|
||||
|
||||
## Acknowledgement
|
||||
|
||||
NeoChat utilizes [libQuotient](https://github.com/quotient-im/libQuotient/) as its Matrix SDK.
|
||||
This program utilizes [libQuotient](https://github.com/quotient-im/libQuotient/) as its Matrix SDK.
|
||||
|
||||
NeoChat is a fork of [Spectral](https://gitlab.com/spectral-im/spectral/).
|
||||
This program is a fork of [Spectral](https://gitlab.com/spectral-im/spectral/).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -39,10 +39,6 @@ class OpenUserDetailsTest(unittest.TestCase):
|
||||
|
||||
def test_open_sheet(self):
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="@user:localhost:1234").click()
|
||||
try:
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Expand Normal").click()
|
||||
except:
|
||||
pass
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Empty room (!room_id_1234:localhost:1234)").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="A Display Name").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Account Details")
|
||||
|
||||
@@ -130,7 +130,7 @@ void DelegateSizeHelperTest::equalBreakpoint_data()
|
||||
}
|
||||
|
||||
/**
|
||||
* We expect a default return except in the case where the two percentages are
|
||||
* We expect a default return except in the case where the the two percentages are
|
||||
* equal as that case can be calculated without dividing by zero.
|
||||
*/
|
||||
void DelegateSizeHelperTest::equalBreakpoint()
|
||||
|
||||
@@ -32,6 +32,8 @@ private Q_SLOTS:
|
||||
|
||||
void linkPreviewsReject_data();
|
||||
void linkPreviewsReject();
|
||||
|
||||
void editedLink();
|
||||
};
|
||||
|
||||
void LinkPreviewerTest::initTestCase()
|
||||
@@ -57,7 +59,7 @@ void LinkPreviewerTest::linkPreviewsMatch()
|
||||
QFETCH(QUrl, testOutputLink);
|
||||
|
||||
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
||||
auto linkPreviewer = LinkPreviewer(LinkPreviewer::linkPreview(event.get()), connection);
|
||||
auto linkPreviewer = LinkPreviewer(room, event.get());
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), false);
|
||||
QCOMPARE(linkPreviewer.url(), testOutputLink);
|
||||
@@ -77,7 +79,22 @@ void LinkPreviewerTest::linkPreviewsReject()
|
||||
QFETCH(QString, eventSource);
|
||||
|
||||
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
|
||||
auto linkPreviewer = LinkPreviewer(LinkPreviewer::linkPreview(event.get()), connection);
|
||||
auto linkPreviewer = LinkPreviewer(room, event.get());
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), true);
|
||||
QCOMPARE(linkPreviewer.url(), QUrl());
|
||||
}
|
||||
|
||||
void LinkPreviewerTest::editedLink()
|
||||
{
|
||||
room->syncNewEvents(QStringLiteral("test-linkpreviewerintial-sync.json"));
|
||||
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
|
||||
auto linkPreviewer = LinkPreviewer(room, event);
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), false);
|
||||
QCOMPARE(linkPreviewer.url(), QUrl("https://kde.org"_ls));
|
||||
|
||||
room->syncNewEvents(QStringLiteral("test-linkpreviewerreplace-sync.json"));
|
||||
|
||||
QCOMPARE(linkPreviewer.empty(), true);
|
||||
QCOMPARE(linkPreviewer.url(), QUrl());
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
<summary xml:lang="ca">Xategeu amb els vostres amics a Matrix</summary>
|
||||
<summary xml:lang="ca-valencia">Xategeu amb els vostres amics a Matrix</summary>
|
||||
<summary xml:lang="cs">Mluvte se svými přáteli na Matrixu</summary>
|
||||
<summary xml:lang="en-GB">Chat with your friends on matrix</summary>
|
||||
<summary xml:lang="eo">Babilu kun viaj amikoj sur matrix</summary>
|
||||
<summary xml:lang="es">Charle con sus amigos en matrix</summary>
|
||||
<summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary>
|
||||
@@ -80,15 +79,12 @@
|
||||
<summary xml:lang="zh-TW">在 Matrix 上與您的朋友聊天</summary>
|
||||
<description>
|
||||
<p>NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p>
|
||||
<p xml:lang="ar">نيوتشات هو تطبيق دردشة يتيح لك الاستفادة الكاملة من شبكة Matrix. فهو يوفر لك طريقة آمنة لإرسال الرسائل النصية ومقاطع الفيديو والملفات الصوتية إلى عائلتك وزملائك وأصدقائك.</p>
|
||||
<p xml:lang="ca">El NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat és una aplicació de xat que us permet aprofitar plenament la xarxa Matrix. Proporciona una manera segura d'enviar missatges de text, vídeos i arxius d'àudio a la vostra família, companys i amics.</p>
|
||||
<p xml:lang="en-GB">NeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.</p>
|
||||
<p xml:lang="eo">NeoChat estas babilej-apo, kiu ebligas al vi plene profiti de la Matrix-reto. Ĝi provizas al vi sekuran manieron sendi tekstmesaĝojn, filmetojn kaj sondosierojn al via familio, kolegoj kaj amikoj.</p>
|
||||
<p xml:lang="es">NeoChat es una aplicación de chat que le permite aprovechar al máximo la red Matrix. Le proporciona un modo seguro de enviar mensajes de texto, vídeos y archivos de sonido a su familia, colegas y amigos.</p>
|
||||
<p xml:lang="eu">NeoChat, Matrix sarearen abantaila guztiei probetsua ateratzeko aukera ematen dizun berriketa aplikaizo bat da. Zure familiari, kideei eta lagunei testu mezuak, bideoak eta audio fitxategiak era seguruan bidaltzeko aukera ematen dizu.</p>
|
||||
<p xml:lang="fi">NeoChat on keskustelusovellus, jolla Matrix-verkosta saa täyden hyödyn. Se tarjoaa salatun kanavan lähettää perheelle, työkavereille ja ystäville tekstiviestejä sekä video- ja äänitiedostoja.</p>
|
||||
<p xml:lang="fr">NeoChat est une application de discussions vous permettant de profiter pleinement du réseau Matrix. Elle vous offre un moyen sécurisé d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos ami(e)s.</p>
|
||||
<p xml:lang="fr">NeoChat est une application de discussions vous permettant de profiter pleinement du réseau Matrix. Elle vous offre un moyen sécurisé d’envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos ami(e)s.</p>
|
||||
<p xml:lang="hu">A NeoChat egy olyan csevegőalkalmazás, amellyel teljes mértékben kihasználhatja a Matrix hálózatot. Biztonságos módot biztosít szöveges üzenetek, videók és hangfájlok küldéséhez családtagjainak, kollégáinak és barátainak.</p>
|
||||
<p xml:lang="ia">NeoChat es un app de conversation que te permitte prender avantage plen del rete Matrix. Il te forni un modo secur de inviar messages de texto, videos e files audio a tui familia, collegas e amicos.</p>
|
||||
<p xml:lang="it">NeoChat è un'applicazione di chat che ti consente di sfruttare appieno la rete Matrix. Ti fornisce un modo sicuro per inviare messaggi di testo, video e file audio a familiari, colleghi e amici.</p>
|
||||
@@ -97,7 +93,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="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="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p>
|
||||
<p xml:lang="sv">NeoChat är ett chattprogram som låter dig dra full nytta av Matrix-nätverket. Det ger dig ett säkert sätt att skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner.</p>
|
||||
<p xml:lang="tr">NeoChat, Matrix ağının tüm özelliklerini kullanan bir sohbet uygulamasıdır. Ailenize, arkadaşlarınıza ve iş arkadaşlarınıza metin iletileri, ses ve video dosyaları göndermenin kolay bir yolunu sunar.</p>
|
||||
<p xml:lang="uk">NeoChat є програмою для спілкування, за допомогою якої ви можете скористатися усіма перевагами мережі Matrix. За її допомогою ви можете безпечно надсилати текстові повідомлення, відео та звукові файли вашим родичам, колегам та друзям.</p>
|
||||
<p xml:lang="x-test">xxNeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.xx</p>
|
||||
@@ -114,7 +109,7 @@
|
||||
<p xml:lang="fr">L'objectif de NeoChat est d'être une application complète pour le protocole Matrix. En tant que tel, tout dans la spécification stable actuelle avec les exceptions notables de VoIP, les processus et certains aspects du chiffrement de bout en bout sont pris en charge. Il y a quelques autres petites omissions en raison du fait que la spécification du protocole Matrix est en constante évolution. Cependant, l'objectif reste de fournir un soutien éventuel pour l'ensemble de la spécification.</p>
|
||||
<p xml:lang="gl">NeoChat pretende ser unha aplicación completa para a especificación de Matrix. Coas excepcións de VoIP, conversas fiadas e algúns aspectos da cifraxe de extremo a extremo, a versión estábel segue as especificacións. Existen algunhas outras pequenas omisións debido ao feito de que Matrix está en continua evolución pero a intención é implementar a especificación completa.</p>
|
||||
<p xml:lang="hu">A NeoChat célja, hogy a Matrix specifikációnak megfelelő teljes funkcionalitású alkalmazás legyen. Mint ilyen, a jelenlegi stabil specifikáció támogatott a VoIP, a szálak és a végpontok közötti titkosítás egyes elemeinek kivételével. Van még néhány kisebb hiányosság annak köszönhetően, hogy a Matrix specifikáció folyamatosan fejlődik, de végső cél a teljes specifikáció megvalósítása.</p>
|
||||
<p xml:lang="ia">NeoChat aspira a esser un application plenmente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p>
|
||||
<p xml:lang="ia">NeoChat aspira a esser un application plenemente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p>
|
||||
<p xml:lang="it">NeoChat mira ad essere un'applicazione completa per le specifiche Matrix. Pertanto, sono supportati tutti gli elementi dell'attuale specifica stabile con le notevoli eccezioni di VoIP, conversazioni e alcuni aspetti della cifratura end-to-end. Ci sono alcune altre piccole omissioni dovute al fatto che le specifiche Matrix sono in continua evoluzione, ma l'obiettivo rimane quello di fornire un eventuale supporto per l'intera specifica.</p>
|
||||
<p xml:lang="ka">NeoChat მიზნად ისახავს Matrix სპეციფიკაციის სრული განხორციელება ჰქონდეს. როგორც ასეთი, ყველაფერი მიმდინარე სპეციფიკაციიდან, VoIP-ის, ძაფებისა და გამჭოლი დაშიფვრის ზოგიერთი ასპექტის გარდა, მხარდაჭერილია. შეძლება ასევე იყოს მცირე ლაფსუსებიც იმის გამო, რომ Matrix-ის სპეციფიკაცია მუდმივად ვითარდება, მაგრამ ჩვენი მიზანი მისი სრული მხარდაჭერაა.</p>
|
||||
<p xml:lang="ko">NeoChat은 Matrix 표준을 따르는 프로그램을 목표로 합니다. 현재 안정 버전의 표준에서 제공하는 기능의 대부분을 지원하며, VoIP, 스레드, 일부 종단간 암호화와 같은 기능은 아직 지원하지 않습니다. Matrix 표준은 계속하여 진화 중이기 때문에 일부 기능이 빠져 있을 수도 있지만 장기적으로는 전체 표준을 지원하는 것이 목표입니다.</p>
|
||||
@@ -123,7 +118,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="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="ru">Целью создания NeoChat является полноценная реализация программы для спецификации Matrix. Как следствие, реализовано всё в текущей стабильной спецификации (за исключением голосовой интернет-связи, потоков и некоторых аспектов сквозного шифрования). Есть также несколько других незначительных пробелов, обусловленных постоянными изменениями спецификации Matrix. Тем не менее, стоит задача в итоге предоставить полную поддержку спецификации.</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="sv">NeoChat har som mål att vara ett fullständigt program enligt Matrix-specifikationen. Som sådant stöds allt i den nuvarande stabila specifikationen, med de nämnvärda undantagen VoIP, trådar och några aspekter av kryptering hela vägen. Det finns några ytterligare utelämnanden på grund av att Matrix-specifikationen hela tiden utvecklas, men målet förblir att till slut erbjuda stöd för hela specifikationen.</p>
|
||||
<p xml:lang="tr">NeoChat, Matrix belirtimi için tam özellikli bir uygulama olmayı hedefler. Bu nedenle; VoIP, ileti zincirleri ve Uçtan Uca Şifreleme’nin bazı yönleri gibi dikkate değer istisnalar dışında var olan kararlı belirtimdeki her şey desteklenir. Matrix belirtiminin sürekli gelişmesi nedeniyle birkaç küçük eksiklik daha var; ancak amaç tüm belirtim için nihai destek sağlamak olmayı sürdürüyor.</p>
|
||||
@@ -151,7 +145,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="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="ru">В силу природы разработки спецификации 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="sv">På grund av sättet Matrix-specifikationens utvecklas, stöder NeoChat också ett stor antal instabila funktioner. För närvarande är de:</p>
|
||||
<p xml:lang="ta">மேட்ரிக்ஸு நெறிமுறை வரையறுக்கப்படும் விதத்தின் காரணமாக, பல நிலையற்ற அம்சங்களையும் நியோச்சாட் ஆதரிக்கிறது. தற்போது ஆதரிக்கப்படுபவை:</p>
|
||||
@@ -209,11 +202,10 @@
|
||||
<li xml:lang="nn">Klistremerke-pakkar – MSC2545</li>
|
||||
<li xml:lang="pl">Paczki naklejek - MSC2545</li>
|
||||
<li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li>
|
||||
<li xml:lang="ru">Наборы стикеров — MSC2545</li>
|
||||
<li xml:lang="sl">Sticker Packs - MSC2545</li>
|
||||
<li xml:lang="sv">Sticker Packs - MSC2545</li>
|
||||
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
|
||||
<li xml:lang="tr">Çıkartma Paketleri — MSC2545</li>
|
||||
<li xml:lang="tr">Yapışkan Paketleri — MSC2545</li>
|
||||
<li xml:lang="uk">Пакунки наліпок - MSC2545</li>
|
||||
<li xml:lang="x-test">xxSticker Packs - MSC2545xx</li>
|
||||
<li xml:lang="zh-TW">貼圖包 - MSC2545</li>
|
||||
@@ -238,7 +230,6 @@
|
||||
<li xml:lang="nn">Posisjonshendingar – MSC3488</li>
|
||||
<li xml:lang="pl">Wydarzenia w miejscach - MSC3488</li>
|
||||
<li xml:lang="pt">Eventos com Localizações - MSC3488</li>
|
||||
<li xml:lang="ru">События местоположения — MSC3488</li>
|
||||
<li xml:lang="sl">Location Events - MSC3488</li>
|
||||
<li xml:lang="sv">Location Events - MSC3488</li>
|
||||
<li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li>
|
||||
@@ -284,7 +275,6 @@
|
||||
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
||||
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
|
||||
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
|
||||
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
|
||||
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
|
||||
@@ -301,7 +291,6 @@
|
||||
<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="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
|
||||
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
|
||||
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
|
||||
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
|
||||
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
|
||||
@@ -313,14 +302,11 @@
|
||||
<screenshot type="default">
|
||||
<image>https://cdn.kde.org/screenshots/neochat/spaces.png</image>
|
||||
<caption>Discover new communities with Matrix Spaces</caption>
|
||||
<caption xml:lang="ar">اكتشف مجتمعات جديدة مع فضاءات ماتركس</caption>
|
||||
<caption xml:lang="ca">Descobriu comunitats noves amb els espais de Matrix</caption>
|
||||
<caption xml:lang="ca-valencia">Descobriu comunitats noves amb els espais de Matrix</caption>
|
||||
<caption xml:lang="en-GB">Discover new communities with Matrix Spaces</caption>
|
||||
<caption xml:lang="eo">Malkovru novajn komunumojn per Matrix Spaces</caption>
|
||||
<caption xml:lang="es">Descubra nuevas comunidades con los espacios de Matrix</caption>
|
||||
<caption xml:lang="eu">Ezagutu komunitate berriak Matrixeko Tokiak erabiliz</caption>
|
||||
<caption xml:lang="fi">Löydä uusia yhteisöjä Matrix Spacesillä</caption>
|
||||
<caption xml:lang="fr">Découvrez de nouvelles communautés avec les espaces sous Matrix</caption>
|
||||
<caption xml:lang="hu">Fedezzen fel új közösségeket a Matrix Terek segítségével</caption>
|
||||
<caption xml:lang="ia">Discoperi nove communitate con Matrix Spaces (Spatios de Matrix)</caption>
|
||||
@@ -330,7 +316,6 @@
|
||||
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption>
|
||||
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
|
||||
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
|
||||
<caption xml:lang="sv">Upptäck nya gemenskaper med Matrix Spaces</caption>
|
||||
<caption xml:lang="tr">Matrix Alanlar ile yeni topluluklar keşfedin</caption>
|
||||
<caption xml:lang="uk">Пошук нових спільнот за допомогою Matrix Spaces</caption>
|
||||
<caption xml:lang="x-test">xxDiscover new communities with Matrix Spacesxx</caption>
|
||||
@@ -349,7 +334,6 @@
|
||||
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
||||
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="en-GB">Main view with room list, chat, and room information</caption>
|
||||
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
|
||||
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
|
||||
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
|
||||
@@ -366,7 +350,6 @@
|
||||
<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="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
|
||||
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
|
||||
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
|
||||
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
|
||||
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
|
||||
@@ -382,7 +365,6 @@
|
||||
<caption xml:lang="ca">Pantalla d'inici de sessió</caption>
|
||||
<caption xml:lang="ca-valencia">Pantalla d'inici de sessió</caption>
|
||||
<caption xml:lang="cs">Přihlašovací obrazovka</caption>
|
||||
<caption xml:lang="en-GB">Login screen</caption>
|
||||
<caption xml:lang="eo">Ensaluta ekrano</caption>
|
||||
<caption xml:lang="es">Pantalla de inicio de sesión</caption>
|
||||
<caption xml:lang="eu">Saio-hasteko pantaila</caption>
|
||||
@@ -399,7 +381,6 @@
|
||||
<caption xml:lang="nn">Innloggingsbilete</caption>
|
||||
<caption xml:lang="pl">Ekran logowania</caption>
|
||||
<caption xml:lang="pt">Ecrã de autenticação</caption>
|
||||
<caption xml:lang="ru">Окно входа</caption>
|
||||
<caption xml:lang="sl">Prijavni zaslon</caption>
|
||||
<caption xml:lang="sv">Inloggningsfönster</caption>
|
||||
<caption xml:lang="ta">நுழைவுத் திரை</caption>
|
||||
@@ -413,10 +394,6 @@
|
||||
<content_attribute id="social-chat">intense</content_attribute>
|
||||
</content_rating>
|
||||
<releases>
|
||||
<release version="24.05.2" date="2024-07-04"/>
|
||||
<release version="24.05.1" date="2024-06-13"/>
|
||||
<release version="24.05.0" date="2024-05-23"/>
|
||||
<release version="24.02.2" date="2024-04-11"/>
|
||||
<release version="24.02.1" date="2024-03-21"/>
|
||||
<release version="24.02.0" date="2024-02-28">
|
||||
<url>https://kde.org/announcements/megarelease/6/#neochat</url>
|
||||
|
||||
2200
po/ar/neochat.po
2200
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
1310
po/ast/neochat.po
1310
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
1390
po/az/neochat.po
1390
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -77,7 +77,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
></term>
|
||||
<listitem>
|
||||
<para
|
||||
>L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:example.org o matrix:r/root:example.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para>
|
||||
>L'URI de Matrix per a un usuari o una sala. P. ex. matrix:u/usuari:exemple.org o matrix:r/root:exemple.org. Això farà que el NeoChat intenti obrir la sala o conversa indicada. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
1385
po/ca/neochat.po
1385
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1366
po/cs/neochat.po
1366
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1371
po/da/neochat.po
1371
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1394
po/de/neochat.po
1394
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1391
po/el/neochat.po
1391
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
2273
po/en_GB/neochat.po
2273
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1419
po/eo/neochat.po
1419
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
1339
po/es/neochat.po
1339
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1341
po/eu/neochat.po
1341
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1474
po/fi/neochat.po
1474
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1349
po/fr/neochat.po
1349
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1487
po/hu/neochat.po
1487
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1341
po/ia/neochat.po
1341
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1393
po/id/neochat.po
1393
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1361
po/ie/neochat.po
1361
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1341
po/it/neochat.po
1341
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1310
po/ja/neochat.po
1310
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1339
po/ka/neochat.po
1339
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1361
po/ko/neochat.po
1361
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1310
po/lt/neochat.po
1310
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
1355
po/lv/neochat.po
1355
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
1357
po/nl/neochat.po
1357
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
1367
po/nn/neochat.po
1367
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1392
po/pa/neochat.po
1392
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
1357
po/pl/neochat.po
1357
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1391
po/pt/neochat.po
1391
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
1392
po/pt_BR/neochat.po
1392
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
1478
po/ru/neochat.po
1478
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1391
po/sk/neochat.po
1391
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
1332
po/sl/neochat.po
1332
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
2099
po/sv/neochat.po
2099
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1365
po/ta/neochat.po
1365
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1355
po/tok/neochat.po
1355
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
1400
po/tr/neochat.po
1400
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
1339
po/uk/neochat.po
1339
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
1508
po/zh_CN/neochat.po
1508
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
1407
po/zh_TW/neochat.po
1407
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -174,9 +174,6 @@ add_library(neochat STATIC
|
||||
sharehandler.h
|
||||
models/roomtreeitem.cpp
|
||||
models/roomtreeitem.h
|
||||
foreigntypes.h
|
||||
models/threepidmodel.cpp
|
||||
models/threepidmodel.h
|
||||
)
|
||||
|
||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||
@@ -186,7 +183,7 @@ set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||
qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat
|
||||
QML_FILES
|
||||
qml/Main.qml
|
||||
qml/main.qml
|
||||
qml/AccountMenu.qml
|
||||
qml/ExploreComponent.qml
|
||||
qml/ExploreComponentMobile.qml
|
||||
@@ -203,7 +200,9 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
qml/ExplorerDelegate.qml
|
||||
qml/InviteUserPage.qml
|
||||
qml/ImageEditorPage.qml
|
||||
qml/WelcomePage.qml
|
||||
qml/NeochatMaximizeComponent.qml
|
||||
qml/FancyEffectsContainer.qml
|
||||
qml/TypingPane.qml
|
||||
qml/QuickSwitcher.qml
|
||||
qml/HoverActions.qml
|
||||
@@ -214,6 +213,19 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
qml/PieProgressBar.qml
|
||||
qml/QuickFormatBar.qml
|
||||
qml/EmojiPicker.qml
|
||||
qml/LoginStep.qml
|
||||
qml/Login.qml
|
||||
qml/Homeserver.qml
|
||||
qml/Username.qml
|
||||
qml/RegisterPassword.qml
|
||||
qml/Captcha.qml
|
||||
qml/Terms.qml
|
||||
qml/Email.qml
|
||||
qml/Password.qml
|
||||
qml/LoginRegister.qml
|
||||
qml/Loading.qml
|
||||
qml/LoginMethod.qml
|
||||
qml/Sso.qml
|
||||
qml/UserDetailDialog.qml
|
||||
qml/CreateRoomDialog.qml
|
||||
qml/EmojiDialog.qml
|
||||
@@ -279,13 +291,14 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
|
||||
qml/AccountSwitchDialog.qml
|
||||
qml/ConfirmLeaveDialog.qml
|
||||
qml/CodeMaximizeComponent.qml
|
||||
qml/EditStateDialog.qml
|
||||
RESOURCES
|
||||
qml/confetti.png
|
||||
qml/glowdot.png
|
||||
)
|
||||
|
||||
add_subdirectory(settings)
|
||||
add_subdirectory(timeline)
|
||||
add_subdirectory(devtools)
|
||||
add_subdirectory(login)
|
||||
|
||||
if(UNIX)
|
||||
qt_target_qml_sources(neochat QML_FILES qml/ShareAction.qml)
|
||||
@@ -368,18 +381,16 @@ endif()
|
||||
|
||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_RUNNER)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_X11=1)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_X11)
|
||||
target_sources(neochat PRIVATE runner.cpp)
|
||||
|
||||
if (TARGET KUnifiedPush)
|
||||
target_sources(neochat PRIVATE fakerunner.cpp)
|
||||
endif()
|
||||
else()
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_X11=0)
|
||||
endif()
|
||||
|
||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models ${CMAKE_CURRENT_SOURCE_DIR}/enums)
|
||||
target_link_libraries(neochat PRIVATE settingsplugin timelineplugin devtoolsplugin loginplugin)
|
||||
target_link_libraries(neochat PRIVATE settingsplugin timelineplugin devtoolsplugin)
|
||||
target_link_libraries(neochat PUBLIC
|
||||
Qt::Core
|
||||
Qt::Quick
|
||||
@@ -403,10 +414,6 @@ target_link_libraries(neochat PUBLIC
|
||||
QCoro::Network
|
||||
)
|
||||
|
||||
if (TARGET KF6::Crash)
|
||||
target_link_libraries(neochat PUBLIC KF6::Crash)
|
||||
endif()
|
||||
|
||||
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
||||
|
||||
if(NEOCHAT_FLATPAK)
|
||||
|
||||
@@ -91,7 +91,7 @@ class ChatDocumentHandler : public QObject
|
||||
Q_PROPERTY(CompletionModel *completionModel READ completionModel CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief The current room that the text document is being handled for.
|
||||
* @brief The current room that the the text document is being handled for.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/csapi/logout.h>
|
||||
#include <Quotient/csapi/notifications.h>
|
||||
#include <Quotient/eventstats.h>
|
||||
@@ -156,7 +157,7 @@ void Controller::addConnection(NeoChatConnection *c)
|
||||
});
|
||||
connect(c, &NeoChatConnection::loggedOut, this, [this, c] {
|
||||
if (accounts().count() > 1) {
|
||||
// Only set the connection if the account being logged out is currently active
|
||||
// Only set the connection if the the account being logged out is currently active
|
||||
if (c == activeConnection()) {
|
||||
setActiveConnection(dynamic_cast<NeoChatConnection *>(accounts().accounts()[0]));
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ private:
|
||||
|
||||
Quotient::AccountRegistry m_accountRegistry;
|
||||
QStringList m_accountsLoading;
|
||||
QMap<QString, QPointer<NeoChatConnection>> m_connectionsLoading;
|
||||
QMap<QString, QPointer<Quotient::Connection>> m_connectionsLoading;
|
||||
QString m_endpoint;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
@@ -23,7 +23,7 @@ ColumnLayout {
|
||||
model: root.connection.accountDataEventTypes
|
||||
delegate: FormCard.FormButtonDelegate {
|
||||
text: modelData
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet.qml'), {
|
||||
sourceText: root.connection.accountDataJsonString(modelData)
|
||||
}, {
|
||||
title: i18nc("@title:window", "Event Source"),
|
||||
|
||||
@@ -8,7 +8,6 @@ qt_add_qml_module(devtools
|
||||
QML_FILES
|
||||
DevtoolsPage.qml
|
||||
AccountData.qml
|
||||
DebugOptions.qml
|
||||
FeatureFlagPage.qml
|
||||
RoomData.qml
|
||||
ServerData.qml
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
|
||||
import org.kde.neochat
|
||||
|
||||
FormCard.FormCardPage {
|
||||
id: root
|
||||
|
||||
FormCard.FormCard {
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
|
||||
FormCard.FormCheckDelegate {
|
||||
text: i18nc("@option:check", "Show hidden events in the timeline")
|
||||
checked: Config.showAllEvents
|
||||
|
||||
onToggled: Config.showAllEvents = checked
|
||||
}
|
||||
FormCard.FormCheckDelegate {
|
||||
id: roomAccountDataVisibleCheck
|
||||
text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification")
|
||||
description: i18n("Allow the user to start a verification session with devices that were already verified")
|
||||
checked: Config.alwaysVerifyDevice
|
||||
|
||||
onToggled: Config.alwaysVerifyDevice = checked
|
||||
}
|
||||
FormCard.FormCheckDelegate {
|
||||
text: i18nc("@option:check", "Show focus in window header")
|
||||
checked: Config.windowTitleFocus
|
||||
|
||||
onToggled: {
|
||||
Config.windowTitleFocus = checked;
|
||||
Config.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,6 @@ FormCard.FormCardPage {
|
||||
|
||||
readonly property real tabWidth: tabBar.width / tabBar.count
|
||||
|
||||
QQC2.TabButton {
|
||||
text: i18nc("@title:tab", "Debug Options")
|
||||
|
||||
implicitWidth: tabBar.tabWidth
|
||||
}
|
||||
QQC2.TabButton {
|
||||
text: qsTr("Room Data")
|
||||
|
||||
@@ -57,7 +52,6 @@ FormCard.FormCardPage {
|
||||
|
||||
currentIndex: tabBar.currentIndex
|
||||
|
||||
DebugOptions {}
|
||||
RoomData {
|
||||
room: root.room
|
||||
connection: root.connection
|
||||
|
||||
@@ -7,7 +7,7 @@ import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
|
||||
import org.kde.neochat
|
||||
import org.kde.neochat.config
|
||||
|
||||
FormCard.FormCardPage {
|
||||
id: root
|
||||
|
||||
@@ -25,10 +25,9 @@ ColumnLayout {
|
||||
text: i18n("Room")
|
||||
textRole: "escapedDisplayName"
|
||||
valueRole: "roomId"
|
||||
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.EscapedDisplayNameRole)
|
||||
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.DisplayNameRole)
|
||||
model: RoomManager.roomListModel
|
||||
currentIndex: 0
|
||||
displayMode: FormCard.FormComboBoxDelegate.Page
|
||||
Component.onCompleted: currentIndex = RoomManager.roomListModel.rowForRoom(root.room)
|
||||
onCurrentValueChanged: root.room = RoomManager.roomListModel.roomByAliasOrId(roomComboBox.currentValue)
|
||||
}
|
||||
@@ -47,7 +46,7 @@ ColumnLayout {
|
||||
model: root.room.accountDataEventTypes
|
||||
delegate: FormCard.FormButtonDelegate {
|
||||
text: modelData
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet.qml'), {
|
||||
sourceText: root.room.roomAcountDataJson(text)
|
||||
}, {
|
||||
title: i18n("Event Source"),
|
||||
@@ -75,9 +74,14 @@ ColumnLayout {
|
||||
description: i18ncp("'Event' being some JSON data, not something physically happening.", "%1 event of this type", "%1 events of this type", model.eventCount)
|
||||
onClicked: {
|
||||
if (model.eventCount === 1) {
|
||||
openEventSource(model.type, model.stateKey);
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet.qml'), {
|
||||
sourceText: stateModel.stateEventJson(stateModel.index(model.index, 0))
|
||||
}, {
|
||||
title: i18n("Event Source"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
})
|
||||
} else {
|
||||
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'StateKeys'), {
|
||||
pageStack.pushDialogLayer(stateKeysComponent, {
|
||||
room: root.room,
|
||||
eventType: model.type
|
||||
}, {
|
||||
@@ -87,17 +91,9 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function openEventSource(type: string, stateKey: string): void {
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
model: stateModel,
|
||||
allowEdit: true,
|
||||
room: root.room,
|
||||
type: type,
|
||||
stateKey: stateKey,
|
||||
}, {
|
||||
title: i18n("Event Source"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
});
|
||||
Component {
|
||||
id: stateKeysComponent
|
||||
StateKeys {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,21 +31,13 @@ FormCard.FormCardPage {
|
||||
|
||||
delegate: FormCard.FormButtonDelegate {
|
||||
text: model.stateKey
|
||||
onClicked: openEventSource(model.stateKey)
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet.qml'), {
|
||||
sourceText: stateKeysModel.stateEventJson(stateKeysModel.index(model.index, 0))
|
||||
}, {
|
||||
title: i18nc("@title:window", "Event Source"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function openEventSource(stateKey: string): void {
|
||||
applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||
model: stateKeysModel,
|
||||
allowEdit: true,
|
||||
room: root.room,
|
||||
type: root.eventType,
|
||||
stateKey: stateKey
|
||||
}, {
|
||||
title: i18nc("@title:window", "Event Source"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
* @brief Defines the room list categories a room can be assigned.
|
||||
*/
|
||||
enum Types {
|
||||
Search = 0, /**< So we can show a search delegate if needed, e.g. collapsed mode. */
|
||||
Invited, /**< The user has been invited to the room. */
|
||||
Favorite, /**< The room is set as a favourite. */
|
||||
Direct, /**< The room is a direct chat. */
|
||||
@@ -67,6 +68,8 @@ public:
|
||||
return i18n("Low priority");
|
||||
case NeoChatRoomType::Space:
|
||||
return i18n("Spaces");
|
||||
case NeoChatRoomType::Search:
|
||||
return i18n("Search");
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
@@ -86,6 +89,8 @@ public:
|
||||
return QStringLiteral("object-order-lower");
|
||||
case NeoChatRoomType::Space:
|
||||
return QStringLiteral("group");
|
||||
case NeoChatRoomType::Search:
|
||||
return QStringLiteral("search");
|
||||
default:
|
||||
return QStringLiteral("tools-report-bug");
|
||||
}
|
||||
|
||||
@@ -1038,11 +1038,7 @@ QString EventHandler::getReadMarkersString() const
|
||||
QString readMarkersString = i18np("1 user: ", "%1 users: ", userIds.size());
|
||||
for (const auto &userId : userIds) {
|
||||
auto user = m_room->user(userId);
|
||||
auto displayName = user->displayname(m_room);
|
||||
if (displayName.isEmpty()) {
|
||||
displayName = userId;
|
||||
}
|
||||
readMarkersString += displayName + i18nc("list separator", ", ");
|
||||
readMarkersString += user->displayname(m_room) + i18nc("list separator", ", ");
|
||||
}
|
||||
readMarkersString.chop(2);
|
||||
return readMarkersString;
|
||||
|
||||
@@ -74,9 +74,6 @@ void ImagePackEventContent::fillJson(QJsonObject *o) const
|
||||
}
|
||||
imageJson["usage"_ls] = usageJson;
|
||||
}
|
||||
if (image.info.has_value()) {
|
||||
imageJson["info"_ls] = Quotient::EventContent::toInfoJson(*image.info);
|
||||
}
|
||||
imagesJson[image.shortcode] = imageJson;
|
||||
}
|
||||
(*o)["images"_ls] = imagesJson;
|
||||
|
||||
@@ -89,4 +89,6 @@ public:
|
||||
QUO_EVENT(ImagePackEvent, "im.ponies.room_emotes")
|
||||
using KeyedStateEventBase::KeyedStateEventBase;
|
||||
};
|
||||
|
||||
REGISTER_EVENT_TYPE(ImagePackEvent)
|
||||
}
|
||||
|
||||
@@ -40,4 +40,5 @@ public:
|
||||
*/
|
||||
QJsonArray allow() const;
|
||||
};
|
||||
REGISTER_EVENT_TYPE(JoinRulesEvent)
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/keyverificationsession.h>
|
||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||
#include <Quotient/e2ee/sssshandler.h>
|
||||
#endif
|
||||
|
||||
#include "controller.h"
|
||||
#include "neochatconfig.h"
|
||||
|
||||
struct ForeignConfig {
|
||||
Q_GADGET
|
||||
QML_FOREIGN(NeoChatConfig)
|
||||
QML_NAMED_ELEMENT(Config)
|
||||
QML_SINGLETON
|
||||
public:
|
||||
static NeoChatConfig *create(QQmlEngine *, QJSEngine *)
|
||||
{
|
||||
QQmlEngine::setObjectOwnership(NeoChatConfig::self(), QQmlEngine::CppOwnership);
|
||||
return NeoChatConfig::self();
|
||||
}
|
||||
};
|
||||
|
||||
struct ForeignAccountRegistry {
|
||||
Q_GADGET
|
||||
QML_FOREIGN(Quotient::AccountRegistry)
|
||||
QML_NAMED_ELEMENT(AccountRegistry)
|
||||
QML_SINGLETON
|
||||
public:
|
||||
static Quotient::AccountRegistry *create(QQmlEngine *, QJSEngine *)
|
||||
{
|
||||
QQmlEngine::setObjectOwnership(&Controller::instance().accounts(), QQmlEngine::CppOwnership);
|
||||
return &Controller::instance().accounts();
|
||||
}
|
||||
};
|
||||
|
||||
struct ForeignKeyVerificationSession {
|
||||
Q_GADGET
|
||||
QML_FOREIGN(Quotient::KeyVerificationSession)
|
||||
QML_NAMED_ELEMENT(KeyVerificationSession)
|
||||
QML_UNCREATABLE("")
|
||||
};
|
||||
|
||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||
struct ForeignSSSSHandler {
|
||||
Q_GADGET
|
||||
QML_FOREIGN(Quotient::SSSSHandler)
|
||||
QML_NAMED_ELEMENT(SSSSHandler)
|
||||
};
|
||||
#endif
|
||||
@@ -8,22 +8,34 @@
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatconnection.h"
|
||||
#include "neochatroom.h"
|
||||
#include "utils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
LinkPreviewer::LinkPreviewer(const QUrl &url, QObject *parent)
|
||||
LinkPreviewer::LinkPreviewer(const NeoChatRoom *room, const Quotient::RoomMessageEvent *event, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_currentRoom(room)
|
||||
, m_event(event)
|
||||
, m_loaded(false)
|
||||
, m_url(url)
|
||||
, m_url(linkPreview(event))
|
||||
{
|
||||
Q_ASSERT(dynamic_cast<Connection *>(this->parent()));
|
||||
|
||||
connect(this, &LinkPreviewer::urlChanged, this, &LinkPreviewer::emptyChanged);
|
||||
connect(NeoChatConfig::self(), &NeoChatConfig::ShowLinkPreviewChanged, this, &LinkPreviewer::loadUrlPreview);
|
||||
|
||||
loadUrlPreview();
|
||||
if (m_event != nullptr && m_currentRoom != nullptr) {
|
||||
loadUrlPreview();
|
||||
connect(m_currentRoom, &NeoChatRoom::urlPreviewEnabledChanged, this, &LinkPreviewer::loadUrlPreview);
|
||||
// Make sure that we react to edits
|
||||
connect(m_currentRoom, &NeoChatRoom::replacedEvent, this, [this](const Quotient::RoomEvent *newEvent) {
|
||||
if (m_event->id() == newEvent->id()) {
|
||||
m_event = eventCast<const Quotient::RoomMessageEvent>(newEvent);
|
||||
m_url = linkPreview(m_event);
|
||||
Q_EMIT urlChanged();
|
||||
loadUrlPreview();
|
||||
}
|
||||
});
|
||||
}
|
||||
connect(NeoChatConfig::self(), &NeoChatConfig::ShowLinkPreviewChanged, this, &LinkPreviewer::loadUrlPreview);
|
||||
}
|
||||
|
||||
bool LinkPreviewer::loaded() const
|
||||
@@ -53,14 +65,14 @@ QUrl LinkPreviewer::url() const
|
||||
|
||||
void LinkPreviewer::loadUrlPreview()
|
||||
{
|
||||
if (!m_currentRoom || !NeoChatConfig::showLinkPreview() || !m_currentRoom->urlPreviewEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (m_url.scheme() == QStringLiteral("https")) {
|
||||
m_loaded = false;
|
||||
Q_EMIT loadedChanged();
|
||||
|
||||
auto conn = dynamic_cast<Connection *>(this->parent());
|
||||
if (conn == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto conn = m_currentRoom->connection();
|
||||
GetUrlPreviewJob *job = conn->callApi<GetUrlPreviewJob>(m_url);
|
||||
|
||||
connect(job, &BaseJob::success, this, [this, job, conn]() {
|
||||
|
||||
@@ -53,15 +53,14 @@ class LinkPreviewer : public QObject
|
||||
Q_PROPERTY(QUrl imageSource READ imageSource NOTIFY imageSourceChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether there is a link to preview.
|
||||
* @brief Whether the there is a link to preview.
|
||||
*
|
||||
* A linkPreviwer is empty if the URL is empty.
|
||||
*/
|
||||
Q_PROPERTY(bool empty READ empty NOTIFY emptyChanged)
|
||||
|
||||
public:
|
||||
LinkPreviewer() = default;
|
||||
explicit LinkPreviewer(const QUrl &url, QObject *parent = nullptr);
|
||||
explicit LinkPreviewer(const NeoChatRoom *room = nullptr, const Quotient::RoomMessageEvent *event = nullptr, QObject *parent = nullptr);
|
||||
|
||||
[[nodiscard]] QUrl url() const;
|
||||
[[nodiscard]] bool loaded() const;
|
||||
@@ -77,15 +76,10 @@ public:
|
||||
*/
|
||||
static bool hasPreviewableLinks(const Quotient::RoomMessageEvent *event);
|
||||
|
||||
/**
|
||||
* @brief Return the link to be previewed from the given event.
|
||||
*
|
||||
* This function is designed to give only links that should be previewed so
|
||||
* http, https or something starting with www. The first valid link is returned.
|
||||
*/
|
||||
static QUrl linkPreview(const Quotient::RoomMessageEvent *event);
|
||||
|
||||
private:
|
||||
const NeoChatRoom *m_currentRoom;
|
||||
const Quotient::RoomMessageEvent *m_event;
|
||||
|
||||
bool m_loaded;
|
||||
QString m_title = QString();
|
||||
QString m_description = QString();
|
||||
@@ -94,6 +88,14 @@ private:
|
||||
|
||||
void loadUrlPreview();
|
||||
|
||||
/**
|
||||
* @brief Return the link to be previewed from the given event.
|
||||
*
|
||||
* This function is designed to give only links that should be previewed so
|
||||
* http, https or something starting with www. The first valid link is returned.
|
||||
*/
|
||||
static QUrl linkPreview(const Quotient::RoomMessageEvent *event);
|
||||
|
||||
Q_SIGNALS:
|
||||
void loadedChanged();
|
||||
void titleChanged();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "login.h"
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/qt_connection_util.h>
|
||||
|
||||
#include "controller.h"
|
||||
@@ -53,7 +54,7 @@ void LoginHelper::init()
|
||||
m_connection = new NeoChatConnection();
|
||||
}
|
||||
m_connection->resolveServer(m_matrixId);
|
||||
connectSingleShot(m_connection.get(), &Connection::loginFlowsChanged, this, [this]() {
|
||||
connectSingleShot(m_connection, &Connection::loginFlowsChanged, this, [this]() {
|
||||
setHomeserverReachable(true);
|
||||
m_testing = false;
|
||||
Q_EMIT testingChanged();
|
||||
@@ -99,7 +100,7 @@ void LoginHelper::init()
|
||||
Q_EMIT Controller::instance().errorOccured(i18n("Network Error"), std::move(error));
|
||||
});
|
||||
|
||||
connectSingleShot(m_connection.get(), &Connection::syncDone, this, [this]() {
|
||||
connectSingleShot(m_connection, &Connection::syncDone, this, [this]() {
|
||||
Q_EMIT loaded();
|
||||
});
|
||||
}
|
||||
@@ -181,7 +182,7 @@ QUrl LoginHelper::ssoUrl() const
|
||||
void LoginHelper::loginWithSso()
|
||||
{
|
||||
m_connection->resolveServer(m_matrixId);
|
||||
connectSingleShot(m_connection.get(), &Connection::loginFlowsChanged, this, [this]() {
|
||||
connectSingleShot(m_connection, &Connection::loginFlowsChanged, this, [this]() {
|
||||
SsoSession *session = m_connection->prepareForSso(m_deviceName);
|
||||
m_ssoUrl = session->ssoUrl();
|
||||
Q_EMIT ssoUrlChanged();
|
||||
|
||||
@@ -146,7 +146,7 @@ private:
|
||||
QString m_deviceName;
|
||||
bool m_supportsSso = false;
|
||||
bool m_supportsPassword = false;
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
NeoChatConnection *m_connection = nullptr;
|
||||
QUrl m_ssoUrl;
|
||||
bool m_testing = false;
|
||||
bool m_isLoggingIn = false;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
qt_add_library(login STATIC)
|
||||
qt_add_qml_module(login
|
||||
URI org.kde.neochat.login
|
||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/login
|
||||
QML_FILES
|
||||
WelcomePage.qml
|
||||
LoginStep.qml
|
||||
Captcha.qml
|
||||
Email.qml
|
||||
Homeserver.qml
|
||||
Loading.qml
|
||||
Login.qml
|
||||
LoginMethod.qml
|
||||
LoginRegister.qml
|
||||
Password.qml
|
||||
RegisterPassword.qml
|
||||
Sso.qml
|
||||
Terms.qml
|
||||
Username.qml
|
||||
)
|
||||
24
src/main.cpp
24
src/main.cpp
@@ -30,16 +30,16 @@
|
||||
#ifdef HAVE_WINDOWSYSTEM
|
||||
#include <KWindowSystem>
|
||||
#endif
|
||||
|
||||
#if __has_include("KCrash")
|
||||
#include <KCrash>
|
||||
#endif
|
||||
|
||||
#include <KLocalizedContext>
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "neochat-version.h"
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||
#include <Quotient/e2ee/sssshandler.h>
|
||||
#endif
|
||||
#include <Quotient/keyverificationsession.h>
|
||||
#include <Quotient/networkaccessmanager.h>
|
||||
|
||||
#include "blurhashimageprovider.h"
|
||||
@@ -167,10 +167,6 @@ int main(int argc, char *argv[])
|
||||
KAboutData::setApplicationData(about);
|
||||
QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.neochat")));
|
||||
|
||||
#if __has_include("KCrash")
|
||||
KCrash::initialize();
|
||||
#endif
|
||||
|
||||
initLogging();
|
||||
|
||||
Connection::setEncryptionDefault(true);
|
||||
@@ -235,9 +231,15 @@ int main(int argc, char *argv[])
|
||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_settingsPlugin)
|
||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_timelinePlugin)
|
||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_devtoolsPlugin)
|
||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_loginPlugin)
|
||||
|
||||
qml_register_types_org_kde_neochat();
|
||||
qmlRegisterSingletonInstance("org.kde.neochat.config", 1, 0, "Config", NeoChatConfig::self());
|
||||
qmlRegisterSingletonInstance("org.kde.neochat.accounts", 1, 0, "AccountRegistry", &Controller::instance().accounts());
|
||||
|
||||
qmlRegisterUncreatableType<KeyVerificationSession>("com.github.quotient_im.libquotient", 1, 0, "KeyVerificationSession", {});
|
||||
#if __has_include("Quotient/e2ee/sssshandler.h")
|
||||
qmlRegisterType<SSSSHandler>("com.github.quotient_im.libquotient", 1, 0, "SSSSHandler");
|
||||
#endif
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
@@ -288,7 +290,7 @@ int main(int argc, char *argv[])
|
||||
engine.addImageProvider(QLatin1String("mxc"), MatrixImageProvider::create(&engine, &engine));
|
||||
engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider);
|
||||
|
||||
engine.loadFromModule("org.kde.neochat", "Main");
|
||||
engine.load(QUrl(QStringLiteral("qrc:/qt/qml/org/kde/neochat/qml/main.qml")));
|
||||
if (engine.rootObjects().isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "neochatconnection.h"
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
ThumbnailResponse::ThumbnailResponse(QString id, QSize size, NeoChatConnection *connection)
|
||||
|
||||
@@ -35,7 +35,7 @@ private:
|
||||
QSize requestedSize;
|
||||
const QString localFile;
|
||||
Quotient::MediaThumbnailJob *job = nullptr;
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
NeoChatConnection *m_connection;
|
||||
|
||||
QImage image;
|
||||
QString errorStr;
|
||||
@@ -75,6 +75,6 @@ public:
|
||||
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
|
||||
|
||||
private:
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
NeoChatConnection *m_connection = nullptr;
|
||||
MatrixImageProvider() = default;
|
||||
};
|
||||
|
||||
@@ -7,5 +7,3 @@ void MediaManager::startPlayback()
|
||||
{
|
||||
Q_EMIT playbackStarted();
|
||||
}
|
||||
|
||||
#include "moc_mediamanager.cpp"
|
||||
|
||||
@@ -3,15 +3,9 @@
|
||||
|
||||
#include "accountemoticonmodel.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QMimeDatabase>
|
||||
|
||||
#include <Quotient/csapi/content-repo.h>
|
||||
#include <Quotient/events/eventcontent.h>
|
||||
#include <qcoro/qcorosignal.h>
|
||||
|
||||
#include "neochatconnection.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
AccountEmoticonModel::AccountEmoticonModel(QObject *parent)
|
||||
@@ -79,12 +73,12 @@ QHash<int, QByteArray> AccountEmoticonModel::roleNames() const
|
||||
};
|
||||
}
|
||||
|
||||
NeoChatConnection *AccountEmoticonModel::connection() const
|
||||
Connection *AccountEmoticonModel::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void AccountEmoticonModel::setConnection(NeoChatConnection *connection)
|
||||
void AccountEmoticonModel::setConnection(Connection *connection)
|
||||
{
|
||||
if (m_connection) {
|
||||
disconnect(m_connection, nullptr, this, nullptr);
|
||||
@@ -168,15 +162,7 @@ QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl sourc
|
||||
co_return;
|
||||
}
|
||||
m_images->images[index].url = job->contentUri();
|
||||
auto mime = QMimeDatabase().mimeTypeForUrl(source);
|
||||
source.setScheme("file"_ls);
|
||||
QFileInfo fileInfo(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||
EventContent::ImageInfo info;
|
||||
if (mime.name().startsWith("image/"_ls)) {
|
||||
QImage image(source.toLocalFile());
|
||||
info = EventContent::ImageInfo(source, fileInfo.size(), mime, image.size(), fileInfo.fileName());
|
||||
}
|
||||
m_images->images[index].info = info;
|
||||
m_images->images[index].info = none;
|
||||
QJsonObject data;
|
||||
m_images->fillJson(&data);
|
||||
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
|
||||
@@ -189,21 +175,11 @@ QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString short
|
||||
if (job->error() != BaseJob::NoError) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
auto mime = QMimeDatabase().mimeTypeForUrl(source);
|
||||
source.setScheme("file"_ls);
|
||||
QFileInfo fileInfo(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||
EventContent::ImageInfo info;
|
||||
if (mime.name().startsWith("image/"_ls)) {
|
||||
QImage image(source.toLocalFile());
|
||||
info = EventContent::ImageInfo(source, fileInfo.size(), mime, image.size(), fileInfo.fileName());
|
||||
}
|
||||
|
||||
m_images->images.append(ImagePackEventContent::ImagePackImage{
|
||||
shortcode,
|
||||
job->contentUri(),
|
||||
description,
|
||||
info,
|
||||
none,
|
||||
QStringList{type},
|
||||
});
|
||||
QJsonObject data;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <QPointer>
|
||||
#include <QQmlEngine>
|
||||
|
||||
class NeoChatConnection;
|
||||
#include <Quotient/connection.h>
|
||||
|
||||
/**
|
||||
* @class AccountEmoticonModel
|
||||
@@ -29,7 +29,7 @@ class AccountEmoticonModel : public QAbstractListModel
|
||||
/**
|
||||
* @brief The connection to get emoticons from.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
@@ -63,8 +63,8 @@ public:
|
||||
*/
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
[[nodiscard]] NeoChatConnection *connection() const;
|
||||
void setConnection(NeoChatConnection *connection);
|
||||
[[nodiscard]] Quotient::Connection *connection() const;
|
||||
void setConnection(Quotient::Connection *connection);
|
||||
|
||||
/**
|
||||
* @brief Deletes the emoticon at the given index.
|
||||
@@ -96,7 +96,7 @@ Q_SIGNALS:
|
||||
|
||||
private:
|
||||
std::optional<Quotient::ImagePackEventContent> m_images;
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
QPointer<Quotient::Connection> m_connection;
|
||||
QCoro::Task<void> doSetEmoticonImage(int index, QUrl source);
|
||||
QCoro::Task<void> doAddEmoticon(QUrl source, QString shortcode, QString description, QString type);
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "actionsmodel.h"
|
||||
|
||||
#include "chatbarcache.h"
|
||||
#include "neochatconnection.h"
|
||||
#include "neochatroom.h"
|
||||
#include "roommanager.h"
|
||||
#include <Quotient/events/roommemberevent.h>
|
||||
@@ -261,7 +260,7 @@ QList<ActionsModel::Action> actions{
|
||||
return QString();
|
||||
}
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Knocking room <roomname>.", "Knocking room %1.", text));
|
||||
auto connection = dynamic_cast<NeoChatConnection *>(room->connection());
|
||||
auto connection = room->connection();
|
||||
const auto knownServer = roomName.mid(roomName.indexOf(":"_ls) + 1);
|
||||
if (parts.length() >= 2) {
|
||||
RoomManager::instance().knockRoom(connection, roomName, parts[1], QStringList{knownServer});
|
||||
|
||||
@@ -110,7 +110,7 @@ Q_SIGNALS:
|
||||
private:
|
||||
explicit CustomEmojiModel(QObject *parent = nullptr);
|
||||
QList<CustomEmoji> m_emojis;
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
NeoChatConnection *m_connection = nullptr;
|
||||
|
||||
void fetchEmojis();
|
||||
};
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
#include "customemojimodel.h"
|
||||
#include <QRegularExpression>
|
||||
|
||||
class NeoChatConnection;
|
||||
#include <connection.h>
|
||||
|
||||
struct CustomEmoji {
|
||||
QString name; // with :semicolons:
|
||||
@@ -15,6 +14,6 @@ struct CustomEmoji {
|
||||
};
|
||||
|
||||
struct CustomEmojiModel::Private {
|
||||
QPointer<NeoChatConnection> connection;
|
||||
Quotient::Connection *conn = nullptr;
|
||||
QList<CustomEmoji> emojies;
|
||||
};
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <Quotient/csapi/device_management.h>
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/user.h>
|
||||
|
||||
#include "neochatconnection.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
DevicesModel::DevicesModel(QObject *parent)
|
||||
@@ -153,12 +152,12 @@ void DevicesModel::setName(const QString &deviceId, const QString &name)
|
||||
});
|
||||
}
|
||||
|
||||
NeoChatConnection *DevicesModel::connection() const
|
||||
Connection *DevicesModel::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void DevicesModel::setConnection(NeoChatConnection *connection)
|
||||
void DevicesModel::setConnection(Connection *connection)
|
||||
{
|
||||
if (m_connection) {
|
||||
disconnect(m_connection, nullptr, this, nullptr);
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
|
||||
#include <Quotient/csapi/definitions/client_device.h>
|
||||
|
||||
class NeoChatConnection;
|
||||
namespace Quotient
|
||||
{
|
||||
class Connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class DevicesModel
|
||||
@@ -28,7 +31,7 @@ class DevicesModel : public QAbstractListModel
|
||||
/**
|
||||
* @brief The current connection that the model is getting its devices from.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged REQUIRED)
|
||||
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged REQUIRED)
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -85,8 +88,9 @@ public:
|
||||
|
||||
explicit DevicesModel(QObject *parent = nullptr);
|
||||
|
||||
[[nodiscard]] NeoChatConnection *connection() const;
|
||||
void setConnection(NeoChatConnection *connection);
|
||||
|
||||
[[nodiscard]] Quotient::Connection *connection() const;
|
||||
void setConnection(Quotient::Connection *connection);
|
||||
|
||||
Q_SIGNALS:
|
||||
void connectionChanged();
|
||||
@@ -95,5 +99,5 @@ Q_SIGNALS:
|
||||
private:
|
||||
void fetchDevices();
|
||||
QList<Quotient::Device> m_devices;
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
QPointer<Quotient::Connection> m_connection;
|
||||
};
|
||||
|
||||
@@ -208,5 +208,3 @@ void ItineraryModel::sendToItinerary()
|
||||
job->start();
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "moc_itinerarymodel.cpp"
|
||||
|
||||
@@ -62,5 +62,3 @@ void LineModel::resetModel()
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
#include "moc_linemodel.cpp"
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "messagecontentmodel.h"
|
||||
#include "neochatconfig.h"
|
||||
|
||||
#include <QImageReader>
|
||||
|
||||
#include <Quotient/events/redactionevent.h>
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <Quotient/events/stickerevent.h>
|
||||
#include <Quotient/room.h>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
@@ -23,12 +23,9 @@
|
||||
#include "filetype.h"
|
||||
#include "itinerarymodel.h"
|
||||
#include "linkpreviewer.h"
|
||||
#include "neochatconnection.h"
|
||||
#include "neochatroom.h"
|
||||
#include "texthandler.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
MessageContentModel::MessageContentModel(const Quotient::RoomEvent *event, NeoChatRoom *room)
|
||||
: QAbstractListModel(nullptr)
|
||||
, m_room(room)
|
||||
@@ -79,21 +76,6 @@ MessageContentModel::MessageContentModel(const Quotient::RoomEvent *event, NeoCh
|
||||
if (m_event != nullptr && eventId == m_event->id()) {
|
||||
updateComponents();
|
||||
Q_EMIT dataChanged(index(0), index(rowCount() - 1), {FileTransferInfoRole});
|
||||
|
||||
QString mxcUrl;
|
||||
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
|
||||
if (event->hasFileContent()) {
|
||||
mxcUrl = event->content()->fileInfo()->url().toString();
|
||||
}
|
||||
} else if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) {
|
||||
mxcUrl = event->image().fileInfo()->url().toString();
|
||||
}
|
||||
if (mxcUrl.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
auto localPath = m_room->fileTransferInfo(m_event->id()).localPath.toLocalFile();
|
||||
auto config = KSharedConfig::openStateConfig(QStringLiteral("neochatdownloads"))->group(QStringLiteral("downloads"));
|
||||
config.writePathEntry(mxcUrl.mid(6), localPath);
|
||||
}
|
||||
});
|
||||
connect(m_room, &NeoChatRoom::fileTransferFailed, this, [this](const QString &eventId) {
|
||||
@@ -110,11 +92,23 @@ MessageContentModel::MessageContentModel(const Quotient::RoomEvent *event, NeoCh
|
||||
endResetModel();
|
||||
}
|
||||
});
|
||||
connect(m_room, &NeoChatRoom::urlPreviewEnabledChanged, this, &MessageContentModel::updateLinkPreviewer);
|
||||
connect(NeoChatConfig::self(), &NeoChatConfig::ShowLinkPreviewChanged, this, &MessageContentModel::updateLinkPreviewer);
|
||||
}
|
||||
|
||||
updateLinkPreviewer();
|
||||
if (const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
|
||||
if (LinkPreviewer::hasPreviewableLinks(event)) {
|
||||
m_linkPreviewer = new LinkPreviewer(m_room, event, this);
|
||||
|
||||
connect(m_linkPreviewer, &LinkPreviewer::loadedChanged, [this]() {
|
||||
if (m_linkPreviewer->loaded()) {
|
||||
// HACK: Because DelegateChooser can't switch the delegate on dataChanged it has to think there is a new delegate.
|
||||
beginResetModel();
|
||||
m_components[m_components.size() - 1].type = MessageComponentType::LinkPreview;
|
||||
endResetModel();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateComponents();
|
||||
}
|
||||
|
||||
@@ -161,7 +155,14 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
||||
return eventHandler.getMediaInfo();
|
||||
}
|
||||
if (role == FileTransferInfoRole) {
|
||||
return QVariant::fromValue(fileInfo());
|
||||
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
|
||||
if (event->hasFileContent()) {
|
||||
return QVariant::fromValue(m_room->fileTransferInfo(event->id()));
|
||||
}
|
||||
}
|
||||
if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) {
|
||||
return QVariant::fromValue(m_room->fileTransferInfo(event->id()));
|
||||
}
|
||||
}
|
||||
if (role == ItineraryModelRole) {
|
||||
return QVariant::fromValue<ItineraryModel *>(m_itineraryModel);
|
||||
@@ -246,124 +247,78 @@ void MessageContentModel::updateComponents(bool isEditing)
|
||||
if (eventCast<const Quotient::RoomMessageEvent>(m_event)
|
||||
&& eventCast<const Quotient::RoomMessageEvent>(m_event)->rawMsgtype() == QStringLiteral("m.key.verification.request")) {
|
||||
m_components += MessageComponent{MessageComponentType::Verification, QString(), {}};
|
||||
endResetModel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_event->isRedacted()) {
|
||||
m_components += MessageComponent{MessageComponentType::Text, QString(), {}};
|
||||
endResetModel();
|
||||
return;
|
||||
}
|
||||
|
||||
EventHandler eventHandler(m_room, m_event);
|
||||
if (eventHandler.hasReply()) {
|
||||
if (m_room->findInTimeline(eventHandler.getReplyId()) == m_room->historyEdge()) {
|
||||
m_components += MessageComponent{MessageComponentType::ReplyLoad, QString(), {}};
|
||||
m_room->loadReply(m_event->id(), eventHandler.getReplyId());
|
||||
} else {
|
||||
m_components += MessageComponent{MessageComponentType::Reply, QString(), {}};
|
||||
}
|
||||
}
|
||||
|
||||
if (isEditing) {
|
||||
m_components += MessageComponent{MessageComponentType::Edit, QString(), {}};
|
||||
} else {
|
||||
m_components.append(componentsForType(eventHandler.messageComponentType()));
|
||||
}
|
||||
EventHandler eventHandler(m_room, m_event);
|
||||
if (eventHandler.hasReply()) {
|
||||
if (m_room->findInTimeline(eventHandler.getReplyId()) == m_room->historyEdge()) {
|
||||
m_components += MessageComponent{MessageComponentType::ReplyLoad, QString(), {}};
|
||||
m_room->loadReply(m_event->id(), eventHandler.getReplyId());
|
||||
} else {
|
||||
m_components += MessageComponent{MessageComponentType::Reply, QString(), {}};
|
||||
}
|
||||
}
|
||||
|
||||
if (m_linkPreviewer != nullptr) {
|
||||
if (m_linkPreviewer->loaded()) {
|
||||
m_components += MessageComponent{MessageComponentType::LinkPreview, QString(), {}};
|
||||
if (isEditing) {
|
||||
m_components += MessageComponent{MessageComponentType::Edit, QString(), {}};
|
||||
} else if (m_event->isRedacted()) {
|
||||
m_components += MessageComponent{MessageComponentType::Text, QString(), {}};
|
||||
} else {
|
||||
m_components += MessageComponent{MessageComponentType::LinkPreviewLoad, QString(), {}};
|
||||
if (eventHandler.messageComponentType() == MessageComponentType::Text) {
|
||||
const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event);
|
||||
auto body = EventHandler::rawMessageBody(*event);
|
||||
m_components.append(TextHandler().textComponents(body, EventHandler::messageBodyInputFormat(*event), m_room, event, event->isReplaced()));
|
||||
} else if (eventHandler.messageComponentType() == MessageComponentType::File) {
|
||||
m_components += MessageComponent{MessageComponentType::File, QString(), {}};
|
||||
if (m_emptyItinerary) {
|
||||
Quotient::FileTransferInfo fileTransferInfo;
|
||||
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
|
||||
if (event->hasFileContent()) {
|
||||
fileTransferInfo = m_room->fileTransferInfo(event->id());
|
||||
}
|
||||
}
|
||||
if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) {
|
||||
fileTransferInfo = m_room->fileTransferInfo(event->id());
|
||||
}
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
KSyntaxHighlighting::Repository repository;
|
||||
const auto definitionForFile = repository.definitionForFileName(fileTransferInfo.localPath.toString());
|
||||
if (definitionForFile.isValid() || QFileInfo(fileTransferInfo.localPath.path()).suffix() == QStringLiteral("txt")) {
|
||||
QFile file(fileTransferInfo.localPath.path());
|
||||
file.open(QIODevice::ReadOnly);
|
||||
m_components += MessageComponent{MessageComponentType::Code,
|
||||
QString::fromStdString(file.readAll().toStdString()),
|
||||
{{QStringLiteral("class"), definitionForFile.name()}}};
|
||||
}
|
||||
#endif
|
||||
|
||||
if (FileType::instance().fileHasImage(fileTransferInfo.localPath)) {
|
||||
QImageReader reader(fileTransferInfo.localPath.path());
|
||||
m_components += MessageComponent{MessageComponentType::Pdf, QString(), {{QStringLiteral("size"), reader.size()}}};
|
||||
}
|
||||
} else {
|
||||
updateItineraryModel();
|
||||
if (m_itineraryModel != nullptr) {
|
||||
m_components += MessageComponent{MessageComponentType::Itinerary, QString(), {}};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_components += MessageComponent{eventHandler.messageComponentType(), QString(), {}};
|
||||
}
|
||||
}
|
||||
|
||||
if (m_linkPreviewer != nullptr) {
|
||||
if (m_linkPreviewer->loaded()) {
|
||||
m_components += MessageComponent{MessageComponentType::LinkPreview, QString(), {}};
|
||||
} else {
|
||||
m_components += MessageComponent{MessageComponentType::LinkPreviewLoad, QString(), {}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentType::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case MessageComponentType::Text: {
|
||||
const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event);
|
||||
auto body = EventHandler::rawMessageBody(*event);
|
||||
return TextHandler().textComponents(body, EventHandler::messageBodyInputFormat(*event), m_room, event, event->isReplaced());
|
||||
}
|
||||
case MessageComponentType::File: {
|
||||
QList<MessageComponent> components;
|
||||
components += MessageComponent{MessageComponentType::File, QString(), {}};
|
||||
if (m_emptyItinerary) {
|
||||
auto fileTransferInfo = fileInfo();
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
KSyntaxHighlighting::Repository repository;
|
||||
const auto definitionForFile = repository.definitionForFileName(fileTransferInfo.localPath.toString());
|
||||
if (definitionForFile.isValid() || QFileInfo(fileTransferInfo.localPath.path()).suffix() == QStringLiteral("txt")) {
|
||||
QFile file(fileTransferInfo.localPath.path());
|
||||
file.open(QIODevice::ReadOnly);
|
||||
components += MessageComponent{MessageComponentType::Code,
|
||||
QString::fromStdString(file.readAll().toStdString()),
|
||||
{{QStringLiteral("class"), definitionForFile.name()}}};
|
||||
}
|
||||
#endif
|
||||
|
||||
if (FileType::instance().fileHasImage(fileTransferInfo.localPath)) {
|
||||
QImageReader reader(fileTransferInfo.localPath.path());
|
||||
components += MessageComponent{MessageComponentType::Pdf, QString(), {{QStringLiteral("size"), reader.size()}}};
|
||||
}
|
||||
} else {
|
||||
updateItineraryModel();
|
||||
if (m_itineraryModel != nullptr) {
|
||||
components += MessageComponent{MessageComponentType::Itinerary, QString(), {}};
|
||||
}
|
||||
}
|
||||
return components;
|
||||
}
|
||||
default:
|
||||
return {MessageComponent{type, QString(), {}}};
|
||||
}
|
||||
}
|
||||
|
||||
void MessageContentModel::updateLinkPreviewer()
|
||||
{
|
||||
if (m_room == nullptr || m_event == nullptr) {
|
||||
if (m_linkPreviewer != nullptr) {
|
||||
m_linkPreviewer->disconnect(this);
|
||||
m_linkPreviewer = nullptr;
|
||||
updateComponents();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!m_room->urlPreviewEnabled()) {
|
||||
if (m_linkPreviewer != nullptr) {
|
||||
m_linkPreviewer->disconnect(this);
|
||||
m_linkPreviewer = nullptr;
|
||||
updateComponents();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
|
||||
if (LinkPreviewer::hasPreviewableLinks(event)) {
|
||||
m_linkPreviewer = dynamic_cast<NeoChatConnection *>(m_room->connection())->previewerForLink(LinkPreviewer::linkPreview(event));
|
||||
updateComponents();
|
||||
|
||||
if (m_linkPreviewer != nullptr) {
|
||||
connect(m_linkPreviewer, &LinkPreviewer::loadedChanged, [this]() {
|
||||
if (m_linkPreviewer != nullptr && m_linkPreviewer->loaded()) {
|
||||
// HACK: Because DelegateChooser can't switch the delegate on dataChanged it has to think there is a new delegate.
|
||||
beginResetModel();
|
||||
m_components[m_components.size() - 1].type = MessageComponentType::LinkPreview;
|
||||
endResetModel();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageContentModel::updateItineraryModel()
|
||||
{
|
||||
if (m_room == nullptr || m_event == nullptr) {
|
||||
@@ -372,7 +327,7 @@ void MessageContentModel::updateItineraryModel()
|
||||
|
||||
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
|
||||
if (event->hasFileContent()) {
|
||||
auto filePath = fileInfo().localPath;
|
||||
auto filePath = m_room->fileTransferInfo(event->id()).localPath;
|
||||
if (filePath.isEmpty() && m_itineraryModel != nullptr) {
|
||||
delete m_itineraryModel;
|
||||
m_itineraryModel = nullptr;
|
||||
@@ -399,43 +354,3 @@ void MessageContentModel::updateItineraryModel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileTransferInfo MessageContentModel::fileInfo() const
|
||||
{
|
||||
if (m_room == nullptr || m_event == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QString mxcUrl;
|
||||
int total;
|
||||
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
|
||||
if (event->hasFileContent()) {
|
||||
mxcUrl = event->content()->fileInfo()->url().toString();
|
||||
total = event->content()->fileInfo()->payloadSize;
|
||||
}
|
||||
} else if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) {
|
||||
mxcUrl = event->image().fileInfo()->url().toString();
|
||||
total = event->image().fileInfo()->payloadSize;
|
||||
}
|
||||
auto config = KSharedConfig::openStateConfig(QStringLiteral("neochatdownloads"))->group(QStringLiteral("downloads"));
|
||||
if (!config.hasKey(mxcUrl.mid(6))) {
|
||||
return m_room->fileTransferInfo(m_event->id());
|
||||
}
|
||||
const auto path = config.readPathEntry(mxcUrl.mid(6), QString());
|
||||
QFileInfo info(path);
|
||||
if (!info.isFile()) {
|
||||
config.deleteEntry(mxcUrl);
|
||||
return m_room->fileTransferInfo(m_event->id());
|
||||
}
|
||||
// TODO: we could check the hash here
|
||||
return FileTransferInfo{
|
||||
.status = FileTransferInfo::Completed,
|
||||
.isUpload = false,
|
||||
.progress = total,
|
||||
.total = total,
|
||||
.localDir = QUrl(info.dir().path()),
|
||||
.localPath = QUrl::fromLocalFile(path),
|
||||
};
|
||||
}
|
||||
|
||||
#include "moc_messagecontentmodel.cpp"
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
#include <QAbstractListModel>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include <Quotient/room.h>
|
||||
|
||||
#include "enums/messagecomponenttype.h"
|
||||
#include "eventhandler.h"
|
||||
#include "itinerarymodel.h"
|
||||
@@ -95,14 +93,9 @@ private:
|
||||
QList<MessageComponent> m_components;
|
||||
void updateComponents(bool isEditing = false);
|
||||
|
||||
QPointer<LinkPreviewer> m_linkPreviewer;
|
||||
LinkPreviewer *m_linkPreviewer = nullptr;
|
||||
ItineraryModel *m_itineraryModel = nullptr;
|
||||
|
||||
QList<MessageComponent> componentsForType(MessageComponentType::Type type);
|
||||
|
||||
void updateLinkPreviewer();
|
||||
void updateItineraryModel();
|
||||
bool m_emptyItinerary = false;
|
||||
|
||||
Quotient::FileTransferInfo fileInfo() const;
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "neochatconfig.h"
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/csapi/rooms.h>
|
||||
#include <Quotient/events/redactionevent.h>
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
@@ -116,6 +117,34 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
|
||||
|
||||
if (message != nullptr) {
|
||||
createEventObjects(message);
|
||||
if (NeoChatConfig::self()->showFancyEffects()) {
|
||||
QString planBody = message->plainBody();
|
||||
// snowflake
|
||||
const QString snowlakeEmoji = QString::fromUtf8("\xE2\x9D\x84");
|
||||
if (planBody.contains(snowlakeEmoji)) {
|
||||
Q_EMIT fancyEffectsReasonFound(QStringLiteral("snowflake"));
|
||||
}
|
||||
// fireworks
|
||||
const QString fireworksEmoji = QString::fromUtf8("\xF0\x9F\x8E\x86");
|
||||
if (planBody.contains(fireworksEmoji)) {
|
||||
Q_EMIT fancyEffectsReasonFound(QStringLiteral("fireworks"));
|
||||
}
|
||||
// sparkler
|
||||
const QString sparklerEmoji = QString::fromUtf8("\xF0\x9F\x8E\x87");
|
||||
if (planBody.contains(sparklerEmoji)) {
|
||||
Q_EMIT fancyEffectsReasonFound(QStringLiteral("fireworks"));
|
||||
}
|
||||
// party pooper
|
||||
const QString partyEmoji = QString::fromUtf8("\xF0\x9F\x8E\x89");
|
||||
if (planBody.contains(partyEmoji)) {
|
||||
Q_EMIT fancyEffectsReasonFound(QStringLiteral("confetti"));
|
||||
}
|
||||
// confetti ball
|
||||
const QString confettiEmoji = QString::fromUtf8("\xF0\x9F\x8E\x8A");
|
||||
if (planBody.contains(confettiEmoji)) {
|
||||
Q_EMIT fancyEffectsReasonFound(QStringLiteral("confetti"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event->is<PollStartEvent>()) {
|
||||
m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(event.get()));
|
||||
|
||||
@@ -140,4 +140,5 @@ private:
|
||||
|
||||
Q_SIGNALS:
|
||||
void roomChanged();
|
||||
void fancyEffectsReasonFound(const QString &fancyEffect);
|
||||
};
|
||||
|
||||
@@ -36,14 +36,6 @@ MessageFilterModel::MessageFilterModel(QObject *parent, TimelineModel *sourceMod
|
||||
}
|
||||
|
||||
bool MessageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
if (NeoChatConfig::self()->showAllEvents()) {
|
||||
return true;
|
||||
}
|
||||
return eventIsVisible(sourceRow, sourceParent);
|
||||
}
|
||||
|
||||
bool MessageFilterModel::eventIsVisible(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
|
||||
@@ -67,8 +59,9 @@ bool MessageFilterModel::eventIsVisible(int sourceRow, const QModelIndex &source
|
||||
// Don't show state events that are not the first in a consecutive group on the
|
||||
// same day as they will be grouped as a single delegate.
|
||||
const bool notLastRow = sourceRow < sourceModel()->rowCount() - 1;
|
||||
const bool previousEventIsState =
|
||||
notLastRow ? sourceModel()->data(sourceModel()->index(sourceRow + 1, 0), MessageEventModel::DelegateTypeRole) == DelegateType::State : false;
|
||||
const bool previousEventIsState = notLastRow
|
||||
? sourceModel()->data(sourceModel()->index(sourceRow + 1, 0), MessageEventModel::DelegateTypeRole) == DelegateType::State
|
||||
: false;
|
||||
const bool newDay = sourceModel()->data(sourceModel()->index(sourceRow, 0), MessageEventModel::ShowSectionRole).toBool();
|
||||
if (eventType == DelegateType::State && notLastRow && previousEventIsState && !newDay) {
|
||||
return false;
|
||||
@@ -79,11 +72,7 @@ bool MessageFilterModel::eventIsVisible(int sourceRow, const QModelIndex &source
|
||||
|
||||
QVariant MessageFilterModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == MessageEventModel::DelegateTypeRole && NeoChatConfig::self()->showAllEvents()) {
|
||||
if (!eventIsVisible(index.row(), index.parent())) {
|
||||
return DelegateType::Other;
|
||||
}
|
||||
} else if (role == AggregateDisplayRole) {
|
||||
if (role == AggregateDisplayRole) {
|
||||
return aggregateEventToString(mapToSource(index).row());
|
||||
} else if (role == StateEventsRole) {
|
||||
return stateEventsList(mapToSource(index).row());
|
||||
|
||||
@@ -60,8 +60,6 @@ public:
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
bool eventIsVisible(int sourceRow, const QModelIndex &sourceParent) const;
|
||||
|
||||
/**
|
||||
* @brief Aggregation of the text of consecutive state events starting at row.
|
||||
*
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "notificationsmodel.h"
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/events/event.h>
|
||||
#include <Quotient/uri.h>
|
||||
|
||||
@@ -161,5 +162,3 @@ QString NotificationsModel::nextToken() const
|
||||
{
|
||||
return m_nextToken;
|
||||
}
|
||||
|
||||
#include "moc_notificationsmodel.cpp"
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
#include "publicroomlistmodel.h"
|
||||
|
||||
#include "neochatconnection.h"
|
||||
#include <Quotient/connection.h>
|
||||
|
||||
#include "publicroomlist_logging.h"
|
||||
|
||||
using namespace Quotient;
|
||||
@@ -13,14 +14,14 @@ PublicRoomListModel::PublicRoomListModel(QObject *parent)
|
||||
{
|
||||
}
|
||||
|
||||
NeoChatConnection *PublicRoomListModel::connection() const
|
||||
Quotient::Connection *PublicRoomListModel::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void PublicRoomListModel::setConnection(NeoChatConnection *connection)
|
||||
void PublicRoomListModel::setConnection(Connection *conn)
|
||||
{
|
||||
if (m_connection == connection) {
|
||||
if (m_connection == conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -37,7 +38,7 @@ void PublicRoomListModel::setConnection(NeoChatConnection *connection)
|
||||
|
||||
endResetModel();
|
||||
|
||||
m_connection = connection;
|
||||
m_connection = conn;
|
||||
|
||||
if (job) {
|
||||
job->abandon();
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
|
||||
#include <Quotient/csapi/list_public_rooms.h>
|
||||
|
||||
class NeoChatConnection;
|
||||
namespace Quotient
|
||||
{
|
||||
class Connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class PublicRoomListModel
|
||||
@@ -30,7 +33,7 @@ class PublicRoomListModel : public QAbstractListModel
|
||||
/**
|
||||
* @brief The current connection that the model is getting its rooms from.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
/**
|
||||
* @brief The server to get the public room list from.
|
||||
@@ -92,8 +95,8 @@ public:
|
||||
*/
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
[[nodiscard]] NeoChatConnection *connection() const;
|
||||
void setConnection(NeoChatConnection *connection);
|
||||
[[nodiscard]] Quotient::Connection *connection() const;
|
||||
void setConnection(Quotient::Connection *conn);
|
||||
|
||||
[[nodiscard]] QString server() const;
|
||||
void setServer(const QString &value);
|
||||
@@ -114,7 +117,7 @@ public:
|
||||
Q_INVOKABLE void search(int limit = 50);
|
||||
|
||||
private:
|
||||
QPointer<NeoChatConnection> m_connection = nullptr;
|
||||
QPointer<Quotient::Connection> m_connection = nullptr;
|
||||
QString m_server;
|
||||
QString m_searchText;
|
||||
bool m_showOnlySpaces = false;
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/converters.h>
|
||||
#include <Quotient/csapi/definitions/push_ruleset.h>
|
||||
#include <Quotient/csapi/pushrules.h>
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatconnection.h"
|
||||
|
||||
#include <KLazyLocalizedString>
|
||||
|
||||
@@ -454,7 +454,7 @@ void PushRuleModel::setConnection(NeoChatConnection *connection)
|
||||
Q_EMIT connectionChanged();
|
||||
|
||||
if (m_connection) {
|
||||
connect(m_connection, &NeoChatConnection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
|
||||
connect(m_connection, &Quotient::Connection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
|
||||
updateNotificationRules(QStringLiteral("m.push_rules"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
PushRuleAction::Action m_defaultKeywordAction;
|
||||
QList<Rule> m_rules;
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
NeoChatConnection *m_connection;
|
||||
|
||||
void setRules(QList<Quotient::PushRule> rules, PushRuleKind::Kind kind);
|
||||
|
||||
|
||||
@@ -68,8 +68,7 @@ QVariant ReactionModel::data(const QModelIndex &index, int role) const
|
||||
text += i18nc("Separate the usernames of users", " and ");
|
||||
}
|
||||
}
|
||||
auto displayName = reaction.authors.at(i).toMap()[QStringLiteral("displayName")].toString();
|
||||
text += displayName.isEmpty() ? reaction.authors.at(i).toMap()[QStringLiteral("id")].toString() : displayName;
|
||||
text += reaction.authors.at(i).toMap()[QStringLiteral("displayName")].toString();
|
||||
}
|
||||
|
||||
if (reaction.authors.count() > 3) {
|
||||
|
||||
@@ -25,12 +25,12 @@ RoomListModel::RoomListModel(QObject *parent)
|
||||
|
||||
RoomListModel::~RoomListModel() = default;
|
||||
|
||||
NeoChatConnection *RoomListModel::connection() const
|
||||
Quotient::Connection *RoomListModel::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void RoomListModel::setConnection(NeoChatConnection *connection)
|
||||
void RoomListModel::setConnection(Connection *connection)
|
||||
{
|
||||
if (connection == m_connection) {
|
||||
return;
|
||||
|
||||
@@ -12,11 +12,10 @@ class NeoChatRoom;
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
class Connection;
|
||||
class Room;
|
||||
}
|
||||
|
||||
class NeoChatConnection;
|
||||
|
||||
/**
|
||||
* @class RoomListModel
|
||||
*
|
||||
@@ -30,7 +29,7 @@ class RoomListModel : public QAbstractListModel
|
||||
/**
|
||||
* @brief The current connection that the model is getting its rooms from.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -61,8 +60,8 @@ public:
|
||||
explicit RoomListModel(QObject *parent = nullptr);
|
||||
~RoomListModel() override;
|
||||
|
||||
[[nodiscard]] NeoChatConnection *connection() const;
|
||||
void setConnection(NeoChatConnection *connection);
|
||||
[[nodiscard]] Quotient::Connection *connection() const;
|
||||
void setConnection(Quotient::Connection *connection);
|
||||
|
||||
/**
|
||||
* @brief Get the given role value at the given index.
|
||||
@@ -110,7 +109,7 @@ private Q_SLOTS:
|
||||
void refresh(NeoChatRoom *room, const QList<int> &roles = {});
|
||||
|
||||
private:
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
Quotient::Connection *m_connection = nullptr;
|
||||
QList<NeoChatRoom *> m_rooms;
|
||||
|
||||
QString m_activeSpaceId;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user