Compare commits
84 Commits
v23.08.1
...
work/tobia
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe3516b044 | ||
|
|
794683b5d2 | ||
|
|
9f7f5409bd | ||
|
|
7d7b9d7ae0 | ||
|
|
c7c892c51c | ||
|
|
97903a7cb0 | ||
|
|
0c8f488ac4 | ||
|
|
88368cefaa | ||
|
|
ab4bb41979 | ||
|
|
c2398b19dc | ||
|
|
4b3dac025f | ||
|
|
9eeff06328 | ||
|
|
657a8291d0 | ||
|
|
bc4431462a | ||
|
|
fdd8a62873 | ||
|
|
c164228894 | ||
|
|
7d418f0883 | ||
|
|
e90aecbead | ||
|
|
221c27fbbe | ||
|
|
1907404124 | ||
|
|
81e953dd8c | ||
|
|
9311052e39 | ||
|
|
648fff20f2 | ||
|
|
980211f36a | ||
|
|
25e0e3fa8e | ||
|
|
403c1ed391 | ||
|
|
c2f76612cf | ||
|
|
2a651b8946 | ||
|
|
00c0d1c276 | ||
|
|
0162d91b60 | ||
|
|
5f41b7b4c1 | ||
|
|
d9691bac7c | ||
|
|
719b916837 | ||
|
|
f9514fe925 | ||
|
|
399b9e6944 | ||
|
|
00cf5c8a5b | ||
|
|
02f26424e2 | ||
|
|
3bd639775a | ||
|
|
163c1ef407 | ||
|
|
9997b1074a | ||
|
|
f52a25717b | ||
|
|
5746c24b73 | ||
|
|
dca1b22521 | ||
|
|
b15f1461d8 | ||
|
|
24fd7a0f5b | ||
|
|
0ac3932303 | ||
|
|
807a9ee779 | ||
|
|
4f32a168cd | ||
|
|
45d2da56c7 | ||
|
|
d794e26d62 | ||
|
|
42cc42642d | ||
|
|
ffd6205bd1 | ||
|
|
9ba6b2f0a5 | ||
|
|
f8d3e25f8e | ||
|
|
75cd77facb | ||
|
|
8546d76a54 | ||
|
|
00b7f68a03 | ||
|
|
b486cb905c | ||
|
|
cdd5c9f484 | ||
|
|
3e6c426397 | ||
|
|
847f41e1ad | ||
|
|
ed5bb270ff | ||
|
|
c8b4da2b96 | ||
|
|
ba5445e135 | ||
|
|
1cca39e105 | ||
|
|
dbf67b984e | ||
|
|
c9126cf38e | ||
|
|
13988da4fc | ||
|
|
0847839abc | ||
|
|
6b55e502a0 | ||
|
|
8f81629ac1 | ||
|
|
7f459cb90f | ||
|
|
420e195313 | ||
|
|
3263a69880 | ||
|
|
b060881f06 | ||
|
|
701e786c1f | ||
|
|
646c8ba8fe | ||
|
|
9b31fdea10 | ||
|
|
ce5dfdee16 | ||
|
|
918e805718 | ||
|
|
7debf47833 | ||
|
|
2c142c36e6 | ||
|
|
3279142498 | ||
|
|
0e08a1aa7e |
@@ -58,5 +58,9 @@ Dependencies:
|
||||
'require':
|
||||
'frameworks/kdbusaddons': '@latest-kf6'
|
||||
|
||||
- 'on': ['Linux/Qt6', 'Linux/Qt5']
|
||||
'require':
|
||||
'sdk/selenium-webdriver-at-spi': '@latest-kf6'
|
||||
|
||||
Options:
|
||||
require-passing-tests-on: [ 'Linux/Qt5', 'FreeBSD' ]
|
||||
require-passing-tests-on: [ 'Linux/Qt5', 'FreeBSD', 'Windows' ]
|
||||
|
||||
@@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "23")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "07")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
@@ -93,12 +93,6 @@ set_package_properties(KF${QT_MAJOR_VERSION}Kirigami2 PROPERTIES
|
||||
)
|
||||
find_package(KF${QT_MAJOR_VERSION}KirigamiAddons 0.7.2 REQUIRED)
|
||||
|
||||
find_package(Qt${QT_MAJOR_VERSION}Keychain)
|
||||
set_package_properties(Qt${QT_MAJOR_VERSION}Keychain PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Secure storage of account secrets"
|
||||
)
|
||||
|
||||
if(ANDROID)
|
||||
find_package(OpenSSL)
|
||||
set_package_properties(OpenSSL PROPERTIES
|
||||
@@ -130,6 +124,11 @@ set_package_properties(Quotient${QUOTIENT_SUFFIX} PROPERTIES
|
||||
PURPOSE "Talk with matrix server"
|
||||
)
|
||||
|
||||
if (NOT TARGET Olm::Olm)
|
||||
message(FATAL_ERROR "NeoChat requires Quotient with the E2EE feature enabled")
|
||||
endif()
|
||||
|
||||
|
||||
find_package(cmark)
|
||||
set_package_properties(cmark PROPERTIES
|
||||
TYPE REQUIRED
|
||||
@@ -160,10 +159,6 @@ set_package_properties(KF${QT_MAJOR_VERSION}DocTools PROPERTIES DESCRIPTION
|
||||
TYPE OPTIONAL
|
||||
)
|
||||
|
||||
if(NOT Quotient${QUOTIENT_SUFFIX}_VERSION_MINOR GREATER 6)
|
||||
cmake_policy(SET CMP0063 OLD)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
find_package(Sqlite3)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/android/version.gradle.in ${CMAKE_BINARY_DIR}/version.gradle)
|
||||
@@ -179,9 +174,11 @@ install(FILES org.kde.neochat.tray.svg DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/h
|
||||
add_definitions(-DQT_NO_FOREACH)
|
||||
|
||||
add_subdirectory(src)
|
||||
if (BUILD_TESTING AND Quotient${QUOTIENT_SUFFIX}_VERSION_MINOR GREATER 6)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test)
|
||||
add_subdirectory(autotests)
|
||||
add_subdirectory(appiumtests)
|
||||
endif()
|
||||
|
||||
if(KF${QT_MAJOR_VERSION}DocTools_FOUND)
|
||||
|
||||
23
appiumtests/CMakeLists.txt
Normal file
23
appiumtests/CMakeLists.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
|
||||
|
||||
|
||||
if(NOT BUILD_TESTING OR NOT CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_package(SeleniumWebDriverATSPI)
|
||||
set_package_properties(SeleniumWebDriverATSPI PROPERTIES
|
||||
DESCRIPTION "Server component for selenium tests using Linux accessibility infrastructure"
|
||||
PURPOSE "Needed for GUI tests"
|
||||
URL "https://invent.kde.org/sdk/selenium-webdriver-at-spi"
|
||||
TYPE OPTIONAL
|
||||
)
|
||||
if(NOT SeleniumWebDriverATSPI_FOUND)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_test(
|
||||
NAME logintest
|
||||
COMMAND selenium-webdriver-at-spi-run ${CMAKE_CURRENT_SOURCE_DIR}/logintest.py
|
||||
)
|
||||
42
appiumtests/login-server.py
Normal file
42
appiumtests/login-server.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
||||
|
||||
|
||||
from flask import Flask, request, abort
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/_matrix/client/v3/login", methods=["GET"])
|
||||
def login_get():
|
||||
result = dict()
|
||||
result["flows"] = [dict()]
|
||||
result["flows"][0]["type"] = "m.login.password"
|
||||
return result
|
||||
|
||||
@app.route("/_matrix/client/v3/login", methods=["POST"])
|
||||
def login_post():
|
||||
data = request.get_json()
|
||||
if data["identifier"]["user"] != "user" or data["password"] != "1234":
|
||||
abort(403)
|
||||
print(data)
|
||||
result = dict()
|
||||
result["access_token"] = "token_1234"
|
||||
result["device_id"] = "device_1234"
|
||||
result["user_id"] = "@user:localhost:1234"
|
||||
return result
|
||||
|
||||
@app.route("/_matrix/client/r0/sync")
|
||||
def sync():
|
||||
result = dict()
|
||||
result["next_batch"] = "batch1234"
|
||||
return result
|
||||
|
||||
@app.route("/.well-known/matrix/client")
|
||||
def well_known():
|
||||
reply = dict()
|
||||
reply["m.homeserver"] = dict()
|
||||
reply["m.homeserver"]["base_url"] = "https://localhost:1234"
|
||||
return reply
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(ssl_context='adhoc', port=1234)
|
||||
44
appiumtests/logintest.py
Executable file
44
appiumtests/logintest.py
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: 2021-2022 Harald Sitter <sitter@kde.org>
|
||||
# SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
||||
|
||||
import unittest
|
||||
from appium import webdriver
|
||||
from appium.webdriver.common.appiumby import AppiumBy
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
class LoginTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
desired_caps = {}
|
||||
desired_caps["app"] = "neochat --ignore-ssl-errors"
|
||||
desired_caps["timeouts"] = {'implicit': 10000}
|
||||
self.driver = webdriver.Remote(
|
||||
command_executor='http://127.0.0.1:4723',
|
||||
desired_capabilities=desired_caps)
|
||||
subprocess.Popen(["python","login-server.py"])
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
if not self._outcome.result.wasSuccessful():
|
||||
self.driver.get_screenshot_as_file("failed_test_shot_{}.png".format(self.id()))
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(self):
|
||||
self.driver.quit()
|
||||
|
||||
def test_login(self):
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Matrix ID").send_keys("@user:localhost:1234")
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Continue").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Password").send_keys("1234")
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Login").click()
|
||||
self.driver.find_element(by=AppiumBy.NAME, value="Join some rooms to get started").click()
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <Quotient/syncdata.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
class TestRoom : public NeoChatRoom
|
||||
@@ -555,10 +557,10 @@ void TextHandlerTest::receiveRichPlainUrl()
|
||||
void TextHandlerTest::receiveRichEmote()
|
||||
{
|
||||
auto event = room->messageEvents().at(1).get();
|
||||
auto author = static_cast<NeoChatUser *>(room->user(event->senderId()));
|
||||
auto author = room->user(event->senderId());
|
||||
const QString testInputString = QStringLiteral("This is an emote.");
|
||||
const QString testOutputString = QStringLiteral("* <a href=\"https://matrix.to/#/@example:example.org\" style=\"color:") + author->color().name()
|
||||
+ QStringLiteral("\">@example:example.org</a> This is an emote.");
|
||||
const QString testOutputString = QStringLiteral("* <a href=\"https://matrix.to/#/@example:example.org\" style=\"color:")
|
||||
+ Utils::getUserColor(author->hueF()).name() + QStringLiteral("\">@example:example.org</a> This is an emote.");
|
||||
|
||||
TextHandler testTextHandler;
|
||||
testTextHandler.setData(testInputString);
|
||||
@@ -644,5 +646,5 @@ void TextHandlerTest::linkPreviewsReject()
|
||||
QCOMPARE(testTextHandler.getLinkPreviews(), testOutputLinks);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TextHandlerTest)
|
||||
QTEST_MAIN(TextHandlerTest)
|
||||
#include "texthandlertest.moc"
|
||||
|
||||
@@ -46,43 +46,21 @@
|
||||
<name xml:lang="uk">NeoChat</name>
|
||||
<name xml:lang="x-test">xxNeoChatxx</name>
|
||||
<name xml:lang="zh-CN">NeoChat</name>
|
||||
<summary>A client for matrix, the decentralized communication protocol</summary>
|
||||
<summary xml:lang="ar">عميل لماتركس، ميفاق الاتصال اللامركزي</summary>
|
||||
<summary xml:lang="az">Matrix üçün müştəri, mərkəzləşməmiş kommunikasiya protokolu</summary>
|
||||
<summary xml:lang="ca">Un client de Matrix, el protocol de comunicacions descentralitzat</summary>
|
||||
<summary xml:lang="ca-valencia">Un client de Matrix, el protocol de comunicacions descentralitzat</summary>
|
||||
<summary xml:lang="cs">Klient pro decentralizovaný komunikační protokol matrix</summary>
|
||||
<summary xml:lang="de">Ein Programm für Matrix, das dezentrale Kommunikationsprotokoll</summary>
|
||||
<summary xml:lang="el">Ένας πελάτης για το Matrix, το αποκεντρωμένο πρωτόκολλο επικοινωνίας</summary>
|
||||
<summary xml:lang="en-GB">A client for matrix, the decentralised communication protocol</summary>
|
||||
<summary xml:lang="eo">Kliento por matrix, la malcentra komunikprotokolo</summary>
|
||||
<summary xml:lang="es">Un cliente para Matrix, el protocolo de comunicaciones descentralizado</summary>
|
||||
<summary xml:lang="eu">Matrix, deszentralizatutako komunikazio protokolorako bezero bat</summary>
|
||||
<summary xml:lang="fi">Asiakas Matrixille, hajautetulle viestintäyhteyskäytännölle</summary>
|
||||
<summary xml:lang="fr">Un client pour « Matrix », le protocole décentralisé de communications.</summary>
|
||||
<summary xml:lang="gl">Un cliente para Matrix, o protocolo de comunicación descentralizada</summary>
|
||||
<summary xml:lang="hu">Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz</summary>
|
||||
<summary xml:lang="ia">Un cliente per Matrix, le protocollo de communication decentralisate</summary>
|
||||
<summary xml:lang="id">Klien untuk matrix, protokol komunikasi terdesentralisasi</summary>
|
||||
<summary xml:lang="ie">Un cliente de Matrix, li protocol de communication decentralisat</summary>
|
||||
<summary xml:lang="it">Un client per matrix, il protocollo di comunicazione decentralizzato</summary>
|
||||
<summary xml:lang="ka">კლიენტი Matrix-სთვის, დეცენტრალიზებული კომუნიკაციის პროტოკოლისთვის</summary>
|
||||
<summary xml:lang="ko">Matrix, 분산 대화 프로토콜 클라이언트</summary>
|
||||
<summary xml:lang="nl">Een client voor matrix, het gedecentraliseerde communicatieprotocol</summary>
|
||||
<summary xml:lang="nn">Ein klient for Matrix – protokollen for desentralisert kommunikasjon</summary>
|
||||
<summary xml:lang="pa">ਮੈਟਰਿਕਸ, ਸਰਬ-ਸਾਂਝੇ ਸੰਚਾਰ ਪਰੋਟੋਕਾਲ, ਲਈ ਕਲਾਈਂਟ ਹੈ</summary>
|
||||
<summary xml:lang="pl">Program do obsługi matriksa, rozproszonego protokołu porozumiewania się</summary>
|
||||
<summary xml:lang="pt">Um cliente para o Matrix, o protocolo de comunicação descentralizado</summary>
|
||||
<summary xml:lang="pt-BR">Um cliente do Matrix, o protocolo de comunicação descentralizado</summary>
|
||||
<summary xml:lang="ru">Клиент для Matrix — децентрализованного коммуникационного протокола</summary>
|
||||
<summary xml:lang="sk">Klient pre matrix, decentralizovaný komunikačný protokol</summary>
|
||||
<summary xml:lang="sl">Odjemalec za matrix, decentralizirani komunikacijski protokol</summary>
|
||||
<summary xml:lang="sv">En klient för Matrix, det decentraliserade kommunikationsprotokollet</summary>
|
||||
<summary xml:lang="ta">மையமில்லா தகவல் பரிமாற்ற நெறிமுறையான மேட்ரிக்ஸுக்கான செயலி</summary>
|
||||
<summary xml:lang="tr">Merkezi olmayan iletişim protokolü Matrix için bir istemci</summary>
|
||||
<summary xml:lang="uk">Клієнт matrix, децентралізованого протоколу обміну даними</summary>
|
||||
<summary xml:lang="x-test">xxA client for matrix, the decentralized communication protocolxx</summary>
|
||||
<summary xml:lang="zh-CN">分布式通讯协议 Matrix 的客户端</summary>
|
||||
<summary>Chat with your friends on matrix</summary>
|
||||
<summary xml:lang="ca">Xategeu amb els vostres amics a Matrix</summary>
|
||||
<summary xml:lang="ca-valencia">Xategeu amb els vostres amics a Matrix</summary>
|
||||
<summary xml:lang="eo">Babilu kun viaj amikoj sur matrix</summary>
|
||||
<summary xml:lang="eu">Berriketan jardun zure lagunekin «Matrix»en</summary>
|
||||
<summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary>
|
||||
<summary xml:lang="ka">ესაუბრეთ მეგობრებს Matrix-ზე</summary>
|
||||
<summary xml:lang="nl">Met uw vrienden chatten op matrix</summary>
|
||||
<summary xml:lang="nn">Prat med vennar på Matrix</summary>
|
||||
<summary xml:lang="sl">Klepet z vašimi prijatelji na matrixu</summary>
|
||||
<summary xml:lang="sv">Chatta med dina vänner på Matrix</summary>
|
||||
<summary xml:lang="ta">மேட்ரிக்ஸு மூலம் உங்கள் நண்பர்களிடம் பேசலாம்</summary>
|
||||
<summary xml:lang="tr">Matrix'te arkadaşlarınızla sohbet edin</summary>
|
||||
<summary xml:lang="uk">Спілкуйтеся з вашими друзями у matrix</summary>
|
||||
<summary xml:lang="x-test">xxChat with your friends on matrixxx</summary>
|
||||
<description>
|
||||
<p>NeoChat is a client for Matrix, the decentralized communication protocol for instant messaging. It allows you to send text messages, videos and audio files to your family, colleagues and friends. It uses KDE frameworks and most notably Kirigami
|
||||
to provide a convergent experience across multiple platforms.</p>
|
||||
@@ -92,17 +70,20 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<p xml:lang="en-GB">NeoChat is a client for Matrix, the decentralised communication protocol for instant messaging. It allows you to send text messages, videos and audio files to your family, colleagues and friends. It uses KDE frameworks and most notably Kirigami to provide a convergent experience across multiple platforms.</p>
|
||||
<p xml:lang="eo">NeoChat estas kliento por Matrix, la malcentra komunikoprotokolo por tuja mesaĝado. Ĝi ebligas al vi sendi tekstmesaĝojn, filmetojn kaj sondosierojn al via familio, kolegoj kaj amikoj. Ĝi uzas KDE-framojn kaj precipe Kirigami por disponigi konverĝan sperton tra pluraj platformoj.</p>
|
||||
<p xml:lang="es">NeoChat es un cliente para Matrix, el protocolo de comunicaciones descentralizado para mensajería instantánea. Le permite enviar mensajes de texto, vídeos y archivos de sonido a su familia, compañeros de trabajo y amigos. Usa la infraestructura de KDE y, en particular, Kirigami para proporcionar una experiencia convergente en muchas plataformas.</p>
|
||||
<p xml:lang="eu">NeoChat «Matrix»erako, bat-bateko mezularitzarako komunikazio deszentralizatuko protokolorako, bezero bat da. Zure sendiari, kide eta lagunei testu mezuak, bideo eta audio fitxategiak bidaltzeko aukera ematen dizu. «KDE Frameworks» eta bereziki «Kirigami» erabiltzen ditu plataforma anitzen artean esperientzia konbergente bat eskaintzeko.</p>
|
||||
<p xml:lang="fi">NeoChat on asiakassovellus Matrixille, hajautetulle pikaviestinyhteyskäytännölle. Sillä voi lähettää teksti-, video- ja ääniviestejä perheelle, tutuille ja ystäville. Se käyttää KDE-kehystä ja erityisesti Kirigamia tuottaakseen mukautuvan monialustaisen käyttökokemuksen.</p>
|
||||
<p xml:lang="fr">NeoChat est un client pour le protocole Matrix, un protocole décentralisé de communications pour messagerie instantané. Il vous permet d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos amis. Il utilise les environnements de développement et plus précisément Kirigami pour fournir une expérience convergente sur plusieurs plate-formes. </p>
|
||||
<p xml:lang="gl">NeoChat é un cliente para Matrix, o protocolo de comunicación descentralizada para mensaxería instantánea. Podes enviar mensaxes de texto, vídeos e ficheiros de son á túa familia, colegas e amizades. Usas infraestruturas de KDE e principalmente Kirigami para proporcionar unha experiencia de uso converxente para varias plataformas.</p>
|
||||
<p xml:lang="gl">NeoChat é un cliente para Matrix, o protocolo de comunicación descentralizada para mensaxaría instantánea. Podes enviar mensaxes de texto, vídeos e ficheiros de son á túa familia, colegas e amizades. Usas infraestruturas de KDE e principalmente Kirigami para proporcionar unha experiencia de uso converxente para varias plataformas.</p>
|
||||
<p xml:lang="ia">NeoChat es un cliente per Matrix, le protocollo de communication decentralisate per messager instantanee. Illo te permitte inviar messager de texto, files de video e audio a tu familia, collegas e amicos usante. Illo usa KDE frameworks e super toto Kirigamii forni un experientia convergente trans platteforme multiple.</p>
|
||||
<p xml:lang="it">NeoChat è un client per Matrix, il protocollo di comunicazione decentralizzato per la messaggistica istantanea. Ti consente di inviare messaggi di testo, video e file audio a familiari, colleghi e amici. Utilizza i framework KDE e in particolare Kirigami per fornire un'esperienza convergente su più piattaforme.</p>
|
||||
<p xml:lang="ka">NeoChat არის Matrix კლიენტი. ის საშუალებას გაძლევთ გაგზავნოთ ტექსტური შეტყობინებები, ვიდეოები და აუდიო ფაილები თქვენს ოჯახს, კოლეგებსა და მეგობრებს მატრიქსის პროტოკოლის გამოყენებით.</p>
|
||||
<p xml:lang="ko">NeoChat은 분산형 인스턴트 메시징 통신 프로토콜인 Matrix 클라이언트입니다. 가족, 동료, 친구에게 텍스트 메시지, 동영상, 오디오 파일을 전송할 수 있습니다. KDE 프레임워크와 Kirigami를 사용하여 다양한 플랫폼에서 일관적인 사용자 경험을 제공합니다.</p>
|
||||
<p xml:lang="nl">NeoChat is een client voor Matrix, het gedecentraliseerde communicatieprotocol voor instant messages. Het biedt u het verzenden van tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden. Het gebruik KDE frameworks en het meest opmerkelijk Kirigami om een convergente ervaring te leveren op meerdere platforms.</p>
|
||||
<p xml:lang="nn">NeoChat er ein klient for Matrix, ein protokoll for desentralisert kommunikasjon. Du kan utveksla tekst, lyd og videoar med kollegaar, vennar og familie. Programmet brukar KDE Frameworks og Kirigami for å gje ei brukarflate tilpassa ulike plattformer.</p>
|
||||
<p xml:lang="pl">NeoChat jest programem do Matriksa, protokołu rozproszonego porozumiewania się w czasie rzeczywistym. Umożliwia wysyłanie wiadomości tekstowych, filmów oraz dźwięku do twojej rodziny, znajomych oraz przyjaciół. Używa szkieletów KDE i głównie Kirigami, aby zapewnić spójne wrażenia na wielu platformach</p>
|
||||
<p xml:lang="pt">O NeoChat é um cliente do Matrix. O mesmo permite-lhe enviar mensagens de texto, ficheiros de vídeo e áudio para a sua família, colegas e amigos com o protocolo Matrix. Usa as plataformas do KDE, e principalmente o Kirigami, para oferecer uma experiência convergente entre várias plataformas.</p>
|
||||
<p xml:lang="sl">Neochat je odjemalec za Matrix, decentralizirani komunikacijski protokol za takojšnje sporočanje. Omogoča vam pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek svoji družini, sodelavcem in prijateljem. Uporablja okvire ogrodje KDE frameworks in predvsem Kirigami za zagotavljanje konvergentne izkušnje na več platformah.</p>
|
||||
<p xml:lang="sv">NeoChat är en klient för Matrix, det decentraliserade kommunikationsprotokollet för direktmeddelanden. Den låter dig skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner. Den använder KDE Ramverk, i synnerhet Kirigami, för att tillhandahålla en konvergent upplevelse på flera plattformar.</p>
|
||||
<p xml:lang="tr">NeoChat, anlık iletileşme için merkezi olmayan iletişim protokolü olan Matrix için bir istemcidir. Ailenize, iş arkadaşlarınıza ve arkadaşlarınıza metin iletiler, videolar ve ses dosyaları göndermenize olanak tanır. Birden çok platformda yakınsak bir deneyim sağlamak için KDE Frameworks ve en önemlilerinden Kirigami'yi kullanır.</p>
|
||||
<p xml:lang="uk">NeoChat — клієнт Matrix, децентралізованого протоколу спілкування для миттєвого обміну повідомленнями. За його допомогою ви можете надсилати текстові повідомлення, відео та звукові файли вашій родин, колегами та друзям. У програмі використано бібліотеки KDE, зокрема Kirigami, для надання однорідного середовища на декількох програмних та апаратних платформах.</p>
|
||||
<p xml:lang="x-test">xxNeoChat is a client for Matrix, the decentralized communication protocol for instant messaging. It allows you to send text messages, videos and audio files to your family, colleagues and friends. It uses KDE frameworks and most notably Kirigami to provide a convergent experience across multiple platforms.xx</p>
|
||||
@@ -111,18 +92,22 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<p xml:lang="ca">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de la VoIP, fils i alguns aspectes de l'encriptatge d'extrem a extrem. Hi ha algunes altres omissions més petites a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu segueix sent proporcionar suport eventual per a tota l'especificació.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat pretén ser una aplicació amb totes les característiques per a l'especificació de Matrix. Com a tal, s'ha implementat tota l'especificació actual estable amb les notables excepcions de VoIP, fils i alguns aspectes de l'encriptació d'extrem a extrem. Hi ha algunes altres omissions més xicotetes a causa del fet que l'especificació de Matrix està evolucionant constantment, però l'objectiu seguix sent proporcionar suport eventual per a tota l'especificació.</p>
|
||||
<p xml:lang="en-GB">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.</p>
|
||||
<p xml:lang="eo">NeoChat celas esti plene kapabla aplikaĵo por la Matrix-specifo. Kiel tia, ĉio en la nuna stabila specifo kun la rimarkindaj esceptoj de VoIP, fadenoj kaj kelkaj aspektoj de Fin-al-Fina Ĉifrado estas subtenataj. Estas kelkaj aliaj pli malgrandaj preterlasoj pro la fakto, ke la Matrix-speco konstante evoluas, sed la celo restas provizi finfine subtenon por la tuta specifaĵo.</p>
|
||||
<p xml:lang="es">NeoChat pretende ser una aplicación con todas las funciones para la especificación de Matrix. Como tal, admite todo en la especificación estable actual, con las notables excepciones de VoIP, subprocesos y algunas funciones de cifrado de extremo a extremo. Existen algunas omisiones menos importantes debido al hecho de que la especificación de Matrix está en constante evolución, pero el objetivo sigue siendo brindar compatibilidad final con toda la especificación.</p>
|
||||
<p xml:lang="eu">«NeoChat»ek «Matrix» zehaztapenaren ezaugarri guztiak eskaintzen dituen aplikazio bat izan nahi du. Beraz, egungo zehaztapen egonkorrean dagoen guztiaren euskarria du, VoIP, hariak eta muturren artean zifratzeko salbuespen nabarmenekin. Badira beste ez-betetze txikiago batzuk, «Matrix»en zehaztapena etengabe eboluzioan dagoelako, baina azken helburua zehaztapen osoaren euskarria ematea izaten jarraitzen du.</p>
|
||||
<p xml:lang="fi">NeoChat pyrkii olemaan Matrix-määritelmän täysominaisuuksinen sovellus, joten se tukee kaikkea nykyisessä vakaassa määritelmässä muutamaa huomattavaa poikkeusta lukuun ottamatta (VoIP, säikeet ja jotkin piirteet päästä päähän -salauksessa). Joitakin pienempiäkin puutteita on Matrix-määritelmän jatkuvan kehityksen vuoksi, mutta lopputavoitteena on tarjota määritelmän täysi tuki.</p>
|
||||
<p xml:lang="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="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>
|
||||
<p xml:lang="nl">NeoChat richt zich op het volledig bieden van alle mogelijkheden van de Matrix-specificatie. Alles in de huidige stabiele specificatie met merkbare uitzondering van VoIP, gekoppelde discussies en sommige aspecten van eind-tot-eind versleuteling worden ondersteund. Er zijn een paar andere kleinere omissies vanwege het feit dat de Matrix specificatie constant evolueert maar het doel blijft het eventueel bieden van ondersteuning van de gehele specificatie.</p>
|
||||
<p xml:lang="nn">NeoChat har som mål å støtta all funksjonalitet i Matrix-spesifikasjonen. Førebels er alt i den gjeldande stabile spesifikasjonen støtta, med unntak av VoIP, trådar og nokre delar av ende-til-kryptering. Det finst òg andre småting som ikkje er støtta, sidan Matrix-spesifikasjon er i stadig endring, men målet er altså støtte for alt.</p>
|
||||
<p xml:lang="pl">NeoChat w zamyśle ma być pełnowartościową aplikacją wg wytycznych Matriksa. Z tego powodu, wszystko, co jest obecnie w stabilnych wytycznych z pominięciem VoIP, wątków i niektórych części szyfrowania Użytkownik-do-Użytkownika są obecnie obsługiwane. Pominięto też kilka mniejszych rzeczy ze względu na ciągły rozwój wytycznych Matriksa, lecz celem nadal jest zapewnienie obsługi wszystkich wytycznych.</p>
|
||||
<p xml:lang="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="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>
|
||||
<p xml:lang="uk">Метою створення NeoChat є повноцінна реалізація програми для специфікації Matrix. Як наслідок, реалізовано усе у поточній стабільній специфікації, окрім голосового інтернет-зв'язку, потоків та деяких аспектів міжвузлового шифрування. Є також декілька інших незначних прогалин через те, що специфікація Matrix постійно змінюється, але метою лишається повна підтримка специфікації.</p>
|
||||
<p xml:lang="x-test">xxNeoChat 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.xx</p>
|
||||
@@ -131,18 +116,23 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<p xml:lang="ca">A causa de la naturalesa del desenvolupament de l'especificació de Matrix, el NeoChat també implementa nombroses característiques inestables. Actualment són:</p>
|
||||
<p xml:lang="ca-valencia">A causa de la naturalea del desenvolupament de l'especificació de Matrix, NeoChat també implementa nombroses característiques inestables. Actualment són:</p>
|
||||
<p xml:lang="en-GB">Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:</p>
|
||||
<p xml:lang="eo">Pro la naturo de la Matrix-specifevoluo NeoChat ankaŭ subtenas multajn malstabilajn funkciojn. Nuntempe ĉi tiuj estas:</p>
|
||||
<p xml:lang="es">Debido a la naturaleza del desarrollo de la especificación de Matrix, NeoChat también permite numerosas funciones no estables, como:</p>
|
||||
<p xml:lang="eu">«Matrix» zehaztapenaren garapenaren izaeragatik, «Neo¢hat»ek ezaugarri ezegonkor ugari ere onartzen ditu. Gaur egun hauek:</p>
|
||||
<p xml:lang="fi">Matrix-määritelmän kehittyessä NeoChat tukee myös monia epävakaita ominaisuuksia. Tällä hetkellä näitä ovat:</p>
|
||||
<p xml:lang="fr">En raison de la nature du développement des spécifications du protocole Matrix, NeoChat prend également en charge de nombreuses fonctionnalités instables. Actuellement, ce sont :</p>
|
||||
<p xml:lang="gl">Debido á natureza do desenvolvemento da especificación de Matrix, NeoChat tamén inclúe varias funcionalidades non estábeis:</p>
|
||||
<p xml:lang="ia">Debite al natura del disveloppamento de specification de Matrix NeoChat tamben supporta numerose characteristicas instabile. Currentemente istes es:</p>
|
||||
<p xml:lang="it">A causa della natura dello sviluppo delle specifiche Matrix, NeoChat supporta anche numerose funzionalità instabili. Attualmente queste sono:</p>
|
||||
<p xml:lang="ka">Matrix-ის სპეციფიკაციის განვითარების ბუნების გამო NeoChat-ს ასევე აქვს უამრავი არასტაბილური ფუნქციაც. ახლა ისინია:</p>
|
||||
<p xml:lang="ko">Matrix 표준 개발의 특징으로 인하여 NeoChat은 일부 실험적인 기능을 지원합니다. 현재 지원하는 기능은 다음과 같습니다.</p>
|
||||
<p xml:lang="nl">Vanwege de aard van de ontwikkeling van de Matrix specificatie ondersteunt NeoChat ook talloze onstabiele mogelijkheden. Dit zijn nu:</p>
|
||||
<p xml:lang="nn">På grunn av måten Matrix-spesifikasjonen vert utvikla på, støttar NeoChat òg nokre uferdige funksjonar:</p>
|
||||
<p xml:lang="pl">Ze względu na sposób rozwoju Matriksa, NeoChat obsługuje także kilka niestabilnych możliwości. Obecnie są to:</p>
|
||||
<p xml:lang="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="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>
|
||||
<p xml:lang="tr">NeoChat, Matrix belirtimi geliştirmesinin doğası gereği çok sayıda kararsız özelliği de destekler. Şu anda bunlar:</p>
|
||||
<p xml:lang="uk">Через природу розробки специфікації Matrix, у NeoChat також передбачено підтримку численних нестабільних можливостей. У поточній версії цими можливостями є:</p>
|
||||
<p xml:lang="x-test">xxDue to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:xx</p>
|
||||
@@ -152,17 +142,21 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<li xml:lang="ca">Enquestes - MSC3381</li>
|
||||
<li xml:lang="ca-valencia">Enquestes - MSC3381</li>
|
||||
<li xml:lang="en-GB">Polls - MSC3381</li>
|
||||
<li xml:lang="eo">Enketoj - MSC3381</li>
|
||||
<li xml:lang="es">Encuestas - MSC3381</li>
|
||||
<li xml:lang="eu">Polls - MSC3381</li>
|
||||
<li xml:lang="fi">Kyselyt – MSC3381</li>
|
||||
<li xml:lang="fr">Sondages - MSC3381</li>
|
||||
<li xml:lang="gl">Enquisas - MSC3381</li>
|
||||
<li xml:lang="gl">Enquisas — MSC3381</li>
|
||||
<li xml:lang="ia">Inquestas - MSC3381</li>
|
||||
<li xml:lang="it">Sondaggi - MSC3381</li>
|
||||
<li xml:lang="ka">Polls - MSC3381</li>
|
||||
<li xml:lang="ko">투표 - MSC3381</li>
|
||||
<li xml:lang="nl">Polls - MSC3381</li>
|
||||
<li xml:lang="nn">Avstemmingar – MSC3381</li>
|
||||
<li xml:lang="pt">Inquéritos - MSC3381</li>
|
||||
<li xml:lang="sl">Polls - MSC3381</li>
|
||||
<li xml:lang="sv">Polls - MSC3381</li>
|
||||
<li xml:lang="ta">வாக்கெடுப்புகள் - MSC3381</li>
|
||||
<li xml:lang="tr">Anketler - MSC3381</li>
|
||||
<li xml:lang="uk">Опитування - MSC3381</li>
|
||||
@@ -172,17 +166,21 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<li xml:lang="ca">Paquets d'adhesius - MSC2545</li>
|
||||
<li xml:lang="ca-valencia">Paquets d'adhesius - MSC2545</li>
|
||||
<li xml:lang="en-GB">Sticker Packs - MSC2545</li>
|
||||
<li xml:lang="eo">Glumark-Pakoj - MSC2545</li>
|
||||
<li xml:lang="es">Paquetes de pegatinas - MSC2545</li>
|
||||
<li xml:lang="eu">Eranskailu paketeak - MSC2545</li>
|
||||
<li xml:lang="fi">Tarrapakkaukset – MSC2545</li>
|
||||
<li xml:lang="fr">Paquets d'auto-collants - MSC2545</li>
|
||||
<li xml:lang="gl">Paquetes de adhesivos - MSC2545</li>
|
||||
<li xml:lang="gl">Paquetes de adhesivos — MSC2545</li>
|
||||
<li xml:lang="ia">Etiquetta gummate (sticker) -MSC2545</li>
|
||||
<li xml:lang="it">Pacchetti di adesivi - MSC2545</li>
|
||||
<li xml:lang="ka">სტიკერების პაკეტები - MSC2545</li>
|
||||
<li xml:lang="ko">스티커 팩 - MSC2545</li>
|
||||
<li xml:lang="nl">Sticker Packs - MSC2545</li>
|
||||
<li xml:lang="nn">Klistremerke-pakkar – MSC2545</li>
|
||||
<li xml:lang="pt">Pacotes de Autocolantes - 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">Yapışkan Paketleri - MSC2545</li>
|
||||
<li xml:lang="uk">Пакунки наліпок - MSC2545</li>
|
||||
@@ -192,17 +190,21 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<li xml:lang="ca">Esdeveniments d'ubicació - MSC3488</li>
|
||||
<li xml:lang="ca-valencia">Esdeveniments d'ubicació - MSC3488</li>
|
||||
<li xml:lang="en-GB">Location Events - MSC3488</li>
|
||||
<li xml:lang="eo">Lokaj Eventoj - MSC3488</li>
|
||||
<li xml:lang="es">Eventos de ubicación - MSC3488</li>
|
||||
<li xml:lang="eu">Kokaleku-gertaerak - MSC3488</li>
|
||||
<li xml:lang="fi">Sijaintitapahtumat – MSC3488</li>
|
||||
<li xml:lang="fr">Événements de lieu - MSC3488</li>
|
||||
<li xml:lang="gl">Localización de eventos - MSC3488</li>
|
||||
<li xml:lang="gl">Localización de eventos — MSC3488</li>
|
||||
<li xml:lang="ia">Eventos de Location - MSC3488</li>
|
||||
<li xml:lang="it">Località eventi - MSC3488</li>
|
||||
<li xml:lang="ka">მდებარეობის მოვლენები - MSC3488</li>
|
||||
<li xml:lang="ko">위치 이벤트 - MSC3488</li>
|
||||
<li xml:lang="nl">Locatie gebeurtenissen - MSC3488</li>
|
||||
<li xml:lang="nn">Posisjonshendingar – MSC3488</li>
|
||||
<li xml:lang="pt">Eventos com Localizações - MSC3488</li>
|
||||
<li xml:lang="sl">Location Events - MSC3488</li>
|
||||
<li xml:lang="sv">Location Events - MSC3488</li>
|
||||
<li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li>
|
||||
<li xml:lang="tr">Konum Etkinlikleri - MSC3488</li>
|
||||
<li xml:lang="uk">Місцеві зустрічі - MSC3488</li>
|
||||
@@ -265,12 +267,20 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<value key="KDE::windows_store::screenshots::1::caption">Main view with room list, chat, and room information</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ka">მთავარი ხედი სურათების სიით, ჩატით და ოთახის ინფორმაციით</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ko">대화방 목록, 채팅, 대화방 정보가 표시된 주 보기</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="nl">Hoofdweergave met lijst met rooms, chat en roominformatie</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="tr">Oda listesini, sohbet penceresini ve oda bilgisini gösteren ana görünüm</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</value>
|
||||
<value key="KDE::windows_store::screenshots::1::caption" xml:lang="x-test">xxMain view with room list, chat, and room informationxx</value>
|
||||
@@ -278,12 +288,20 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<value key="KDE::windows_store::screenshots::2::caption">Login screen</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ca">Pantalla d'inici de sessió</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ca-valencia">Pantalla d'inici de sessió</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="eo">Ensaluta ekrano</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="es">Pantalla de inicio de sesión</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="eu">Saio-hasteko pantaila</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="fr">Écran de connexion</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="gl">Pantalla de identificación.</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="it">Schermata di accesso</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ka">შესვლის ეკრანი</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ko">로그인 화면</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="nl">Aanmeldscherm</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="nn">Innloggingsbilete</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="pt">Ecrã de autenticação</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="sl">Prijavni zaslon</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="sv">Inloggningsfönster</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="ta">நுழைவுத் திரை</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="tr">Oturum açma ekranı</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="uk">Вікно входу</value>
|
||||
<value key="KDE::windows_store::screenshots::2::caption" xml:lang="x-test">xxLogin screenxx</value>
|
||||
|
||||
@@ -93,7 +93,7 @@ Comment[es]=Cliente para el protocolo Matrix
|
||||
Comment[eu]=Matrix protokolorako bezeroa
|
||||
Comment[fi]=Asiakas Matrix-yhteyskäytännölle
|
||||
Comment[fr]=Client pour le protocole « Matrix »
|
||||
Comment[gl]=Cliente para o protocolo Matrix
|
||||
Comment[gl]=Cliente para o protocolo Matrix.
|
||||
Comment[hu]=Kliens a Matrix protokollhoz
|
||||
Comment[ia]=Cliente per le protocollo de Matrix
|
||||
Comment[id]=Klien untuk protokol Matrix
|
||||
|
||||
765
po/ar/neochat.po
765
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
770
po/az/neochat.po
770
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
811
po/ca/neochat.po
811
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
769
po/cs/neochat.po
769
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
755
po/da/neochat.po
755
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
765
po/de/neochat.po
765
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
765
po/el/neochat.po
765
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
778
po/es/neochat.po
778
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
993
po/eu/neochat.po
993
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
765
po/fi/neochat.po
765
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
765
po/fr/neochat.po
765
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
767
po/hu/neochat.po
767
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
782
po/ia/neochat.po
782
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
765
po/id/neochat.po
765
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
766
po/ie/neochat.po
766
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
780
po/it/neochat.po
780
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
752
po/ja/neochat.po
752
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
777
po/ka/neochat.po
777
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1072
po/ko/neochat.po
1072
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
752
po/lt/neochat.po
752
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
777
po/nl/neochat.po
777
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
1004
po/nn/neochat.po
1004
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
770
po/pa/neochat.po
770
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
765
po/pl/neochat.po
765
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
765
po/pt/neochat.po
765
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
767
po/ru/neochat.po
767
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
771
po/sk/neochat.po
771
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
781
po/sl/neochat.po
781
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
2177
po/sv/neochat.po
2177
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
777
po/ta/neochat.po
777
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
783
po/tr/neochat.po
783
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
779
po/uk/neochat.po
779
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,6 @@
|
||||
|
||||
configure_file(qml/Page/RoomList/RoomDelegate.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Page/RoomList/RoomDelegate.qml)
|
||||
configure_file(qml/Component/QuickSwitcher.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Component/QuickSwitcher.qml)
|
||||
configure_file(qml/Dialog/UserDetailDialog.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Dialog/UserDetailDialog.qml)
|
||||
configure_file(qml/Dialog/PowerLevelDialog.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Dialog/PowerLevelDialog.qml)
|
||||
configure_file(qml/Component/Timeline/AudioDelegate.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Component/Timeline/AudioDelegate.qml)
|
||||
configure_file(qml/Component/Timeline/VideoDelegate.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Component/Timeline/VideoDelegate.qml)
|
||||
@@ -44,8 +43,6 @@ add_library(neochat STATIC
|
||||
roommanager.h
|
||||
neochatroom.cpp
|
||||
neochatroom.h
|
||||
neochatuser.cpp
|
||||
neochatuser.h
|
||||
models/userlistmodel.cpp
|
||||
models/userlistmodel.h
|
||||
models/userfiltermodel.cpp
|
||||
@@ -127,6 +124,7 @@ add_library(neochat STATIC
|
||||
locationhelper.h
|
||||
events/pollevent.cpp
|
||||
pollhandler.cpp
|
||||
utils.h
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(neochat
|
||||
@@ -175,7 +173,7 @@ else()
|
||||
endif()
|
||||
|
||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR})
|
||||
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF${QT_MAJOR_VERSION}::I18n KF${QT_MAJOR_VERSION}::Kirigami2 KF${QT_MAJOR_VERSION}::Notifications KF${QT_MAJOR_VERSION}::ConfigCore KF${QT_MAJOR_VERSION}::ConfigGui KF${QT_MAJOR_VERSION}::CoreAddons KF${QT_MAJOR_VERSION}::SonnetCore KF${QT_MAJOR_VERSION}::ItemModels Quotient${QUOTIENT_SUFFIX} cmark::cmark ${QTKEYCHAIN_LIBRARIES} QCoro::Core)
|
||||
target_link_libraries(neochat PUBLIC Qt::Core Qt::Quick Qt::Qml Qt::Gui Qt::Multimedia Qt::Network Qt::QuickControls2 KF${QT_MAJOR_VERSION}::I18n KF${QT_MAJOR_VERSION}::Kirigami2 KF${QT_MAJOR_VERSION}::Notifications KF${QT_MAJOR_VERSION}::ConfigCore KF${QT_MAJOR_VERSION}::ConfigGui KF${QT_MAJOR_VERSION}::CoreAddons KF${QT_MAJOR_VERSION}::SonnetCore KF${QT_MAJOR_VERSION}::ItemModels Quotient${QUOTIENT_SUFFIX} cmark::cmark QCoro::Core)
|
||||
kconfig_add_kcfg_files(neochat GENERATE_MOC neochatconfig.kcfgc)
|
||||
|
||||
if(NEOCHAT_FLATPAK)
|
||||
|
||||
@@ -218,8 +218,8 @@ void ChatDocumentHandler::setRoom(NeoChatRoom *room)
|
||||
void ChatDocumentHandler::complete(int index)
|
||||
{
|
||||
if (m_completionModel->autoCompletionType() == CompletionModel::User) {
|
||||
auto name = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Text).toString();
|
||||
auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Subtitle).toString();
|
||||
auto name = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::DisplayNameRole).toString();
|
||||
auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::SubtitleRole).toString();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char('@'), cursorPosition() - 1);
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
@@ -232,7 +232,7 @@ void ChatDocumentHandler::complete(int index)
|
||||
pushMention({cursor, name, 0, 0, id});
|
||||
m_highlighter->rehighlight();
|
||||
} else if (m_completionModel->autoCompletionType() == CompletionModel::Command) {
|
||||
auto command = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedText).toString();
|
||||
auto command = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedTextRole).toString();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char('/'));
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
@@ -240,7 +240,7 @@ void ChatDocumentHandler::complete(int index)
|
||||
cursor.setPosition(cursorPosition(), QTextCursor::KeepAnchor);
|
||||
cursor.insertText(QStringLiteral("/%1 ").arg(command));
|
||||
} else if (m_completionModel->autoCompletionType() == CompletionModel::Room) {
|
||||
auto alias = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Subtitle).toString();
|
||||
auto alias = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::SubtitleRole).toString();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char('#'), cursorPosition() - 1);
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
@@ -253,7 +253,7 @@ void ChatDocumentHandler::complete(int index)
|
||||
pushMention({cursor, alias, 0, 0, alias});
|
||||
m_highlighter->rehighlight();
|
||||
} else if (m_completionModel->autoCompletionType() == CompletionModel::Emoji) {
|
||||
auto shortcode = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedText).toString();
|
||||
auto shortcode = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedTextRole).toString();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char(':'));
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
|
||||
@@ -35,15 +35,15 @@
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/csapi/content-repo.h>
|
||||
#include <Quotient/csapi/logout.h>
|
||||
#include <Quotient/csapi/notifications.h>
|
||||
#include <Quotient/csapi/profile.h>
|
||||
#include <Quotient/eventstats.h>
|
||||
#include <Quotient/jobs/downloadfilejob.h>
|
||||
#include <Quotient/qt_connection_util.h>
|
||||
#include <Quotient/csapi/notifications.h>
|
||||
#include <Quotient/eventstats.h>
|
||||
#include <Quotient/user.h>
|
||||
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatroom.h"
|
||||
#include "neochatuser.h"
|
||||
#include "notificationsmanager.h"
|
||||
#include "roommanager.h"
|
||||
#include "windowcontroller.h"
|
||||
@@ -60,7 +60,6 @@ Controller::Controller(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
Connection::setRoomType<NeoChatRoom>();
|
||||
Connection::setUserType<NeoChatUser>();
|
||||
|
||||
setApplicationProxy();
|
||||
|
||||
@@ -532,7 +531,7 @@ void Controller::joinRoom(const QString &alias)
|
||||
RoomManager::instance().joinRoom(m_connection, alias, QStringList{knownServer});
|
||||
}
|
||||
|
||||
void Controller::openOrCreateDirectChat(NeoChatUser *user)
|
||||
void Controller::openOrCreateDirectChat(User *user)
|
||||
{
|
||||
const auto existing = activeConnection()->directChats();
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <Quotient/settings.h>
|
||||
|
||||
class NeoChatRoom;
|
||||
class NeoChatUser;
|
||||
class TrayIcon;
|
||||
class QWindow;
|
||||
class QQuickTextDocument;
|
||||
@@ -23,6 +22,7 @@ namespace Quotient
|
||||
{
|
||||
class Connection;
|
||||
class Room;
|
||||
class User;
|
||||
}
|
||||
|
||||
namespace QKeychain
|
||||
@@ -183,7 +183,7 @@ public:
|
||||
*
|
||||
* If a direct chat with the user doesn't exist one is created and then joined.
|
||||
*/
|
||||
Q_INVOKABLE void openOrCreateDirectChat(NeoChatUser *user);
|
||||
Q_INVOKABLE void openOrCreateDirectChat(Quotient::User *user);
|
||||
|
||||
[[nodiscard]] bool supportSystemTray() const;
|
||||
|
||||
|
||||
17
src/main.cpp
17
src/main.cpp
@@ -4,6 +4,7 @@
|
||||
#include <QCommandLineParser>
|
||||
#include <QIcon>
|
||||
#include <QNetworkProxyFactory>
|
||||
#include <QObject>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlNetworkAccessManagerFactory>
|
||||
@@ -28,10 +29,11 @@
|
||||
|
||||
#include "neochat-version.h"
|
||||
|
||||
#include <Quotient/keyverificationsession.h>
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/keyverificationsession.h>
|
||||
#include <Quotient/networkaccessmanager.h>
|
||||
#include <Quotient/room.h>
|
||||
#include <Quotient/user.h>
|
||||
#include <Quotient/util.h>
|
||||
|
||||
#include "actionshandler.h"
|
||||
@@ -75,7 +77,6 @@
|
||||
#include "models/webshortcutmodel.h"
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatroom.h"
|
||||
#include "neochatuser.h"
|
||||
#include "notificationsmanager.h"
|
||||
#include "pollhandler.h"
|
||||
#include "roommanager.h"
|
||||
@@ -88,7 +89,6 @@
|
||||
#endif
|
||||
#include "models/completionmodel.h"
|
||||
#include "models/statemodel.h"
|
||||
#include "neochatuser.h"
|
||||
|
||||
#ifdef HAVE_RUNNER
|
||||
#include "runner.h"
|
||||
@@ -259,7 +259,7 @@ int main(int argc, char *argv[])
|
||||
qmlRegisterUncreatableType<PushNotificationState>("org.kde.neochat", 1, 0, "PushNotificationState", "ENUM");
|
||||
qmlRegisterUncreatableType<PushNotificationAction>("org.kde.neochat", 1, 0, "PushNotificationAction", "ENUM");
|
||||
qmlRegisterUncreatableType<NeoChatRoomType>("org.kde.neochat", 1, 0, "NeoChatRoomType", "ENUM");
|
||||
qmlRegisterUncreatableType<NeoChatUser>("org.kde.neochat", 1, 0, "NeoChatUser", {});
|
||||
qmlRegisterUncreatableType<User>("org.kde.neochat", 1, 0, "User", {});
|
||||
qmlRegisterUncreatableType<NeoChatRoom>("org.kde.neochat", 1, 0, "NeoChatRoom", {});
|
||||
|
||||
qRegisterMetaType<User *>("User*");
|
||||
@@ -269,7 +269,7 @@ int main(int argc, char *argv[])
|
||||
qRegisterMetaType<Connection *>("Connection*");
|
||||
qRegisterMetaType<MessageEventType>("MessageEventType");
|
||||
qRegisterMetaType<NeoChatRoom *>("NeoChatRoom*");
|
||||
qRegisterMetaType<NeoChatUser *>("NeoChatUser*");
|
||||
qRegisterMetaType<User *>("User*");
|
||||
qRegisterMetaType<GetRoomEventsJob *>("GetRoomEventsJob*");
|
||||
qRegisterMetaType<QMimeType>("QMimeType");
|
||||
#ifdef Quotient_E2EE_ENABLED
|
||||
@@ -323,11 +323,18 @@ int main(int argc, char *argv[])
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(i18n("Client for the matrix communication protocol"));
|
||||
parser.addPositionalArgument(QStringLiteral("urls"), i18n("Supports matrix: url scheme"));
|
||||
parser.addOption(QCommandLineOption("ignore-ssl-errors", i18n("Ignore all SSL Errors, e.g., unsigned certificates.")));
|
||||
|
||||
about.setupCommandLine(&parser);
|
||||
parser.process(app);
|
||||
about.processCommandLine(&parser);
|
||||
|
||||
if (parser.isSet("ignore-ssl-errors")) {
|
||||
QObject::connect(NetworkAccessManager::instance(), &QNetworkAccessManager::sslErrors, NetworkAccessManager::instance(), [](QNetworkReply *reply) {
|
||||
reply->ignoreSslErrors();
|
||||
});
|
||||
}
|
||||
|
||||
engine.addImageProvider(QLatin1String("mxc"), new MatrixImageProvider);
|
||||
engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider);
|
||||
|
||||
|
||||
@@ -32,11 +32,17 @@ ThumbnailResponse::ThumbnailResponse(QString id, QSize size)
|
||||
requestedSize.setWidth(100);
|
||||
}
|
||||
if (mediaId.count('/') != 1) {
|
||||
errorStr = i18n("Media id '%1' doesn't follow server/mediaId pattern", mediaId);
|
||||
Q_EMIT finished();
|
||||
return;
|
||||
if (mediaId.startsWith(QLatin1Char('/'))) {
|
||||
mediaId = mediaId.mid(1);
|
||||
} else {
|
||||
errorStr = i18n("Media id '%1' doesn't follow server/mediaId pattern", mediaId);
|
||||
Q_EMIT finished();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mediaId = mediaId.split(QLatin1Char('?'))[0];
|
||||
|
||||
QImage cachedImage;
|
||||
if (cachedImage.load(localFile)) {
|
||||
image = cachedImage;
|
||||
|
||||
@@ -34,7 +34,7 @@ private Q_SLOTS:
|
||||
void prepareResult();
|
||||
|
||||
private:
|
||||
const QString mediaId;
|
||||
QString mediaId;
|
||||
QSize requestedSize;
|
||||
const QString localFile;
|
||||
Quotient::MediaThumbnailJob *job = nullptr;
|
||||
|
||||
@@ -81,7 +81,7 @@ QString CollapseStateProxyModel::aggregateEventToString(int sourceRow) const
|
||||
: QStringLiteral("<a href=\"https://matrix.to/#/%1\" style=\"color: %2\">%3</a> ")
|
||||
.arg(uniqueAuthors[0].toMap()["id"].toString(),
|
||||
uniqueAuthors[0].toMap()["color"].toString(),
|
||||
uniqueAuthors[0].toMap()["displayName"].toString());
|
||||
uniqueAuthors[0].toMap()["displayName"].toString().toHtmlEscaped());
|
||||
text += userText;
|
||||
text += chunks.takeFirst();
|
||||
|
||||
|
||||
@@ -53,54 +53,54 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
auto filterIndex = m_filterModel->index(index.row(), 0);
|
||||
if (m_autoCompletionType == User) {
|
||||
if (role == Text) {
|
||||
if (role == DisplayNameRole) {
|
||||
return m_filterModel->data(filterIndex, UserListModel::DisplayNameRole);
|
||||
}
|
||||
if (role == Subtitle) {
|
||||
if (role == SubtitleRole) {
|
||||
return m_filterModel->data(filterIndex, UserListModel::UserIdRole);
|
||||
}
|
||||
if (role == Icon) {
|
||||
if (role == IconNameRole) {
|
||||
return m_filterModel->data(filterIndex, UserListModel::AvatarRole);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_autoCompletionType == Command) {
|
||||
if (role == Text) {
|
||||
if (role == DisplayNameRole) {
|
||||
return m_filterModel->data(filterIndex, ActionsModel::Prefix).toString() + QStringLiteral(" ")
|
||||
+ m_filterModel->data(filterIndex, ActionsModel::Parameters).toString();
|
||||
}
|
||||
if (role == Subtitle) {
|
||||
if (role == SubtitleRole) {
|
||||
return m_filterModel->data(filterIndex, ActionsModel::Description);
|
||||
}
|
||||
if (role == Icon) {
|
||||
if (role == IconNameRole) {
|
||||
return QStringLiteral("invalid");
|
||||
}
|
||||
if (role == ReplacedText) {
|
||||
if (role == ReplacedTextRole) {
|
||||
return m_filterModel->data(filterIndex, ActionsModel::Prefix);
|
||||
}
|
||||
}
|
||||
if (m_autoCompletionType == Room) {
|
||||
if (role == Text) {
|
||||
if (role == DisplayNameRole) {
|
||||
return m_filterModel->data(filterIndex, RoomListModel::DisplayNameRole);
|
||||
}
|
||||
if (role == Subtitle) {
|
||||
if (role == SubtitleRole) {
|
||||
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
|
||||
}
|
||||
if (role == Icon) {
|
||||
if (role == IconNameRole) {
|
||||
return m_filterModel->data(filterIndex, RoomListModel::AvatarRole);
|
||||
}
|
||||
}
|
||||
if (m_autoCompletionType == Emoji) {
|
||||
if (role == Text) {
|
||||
if (role == DisplayNameRole) {
|
||||
return m_filterModel->data(filterIndex, CustomEmojiModel::DisplayRole);
|
||||
}
|
||||
if (role == Icon) {
|
||||
if (role == IconNameRole) {
|
||||
return m_filterModel->data(filterIndex, CustomEmojiModel::MxcUrl);
|
||||
}
|
||||
if (role == ReplacedText) {
|
||||
if (role == ReplacedTextRole) {
|
||||
return m_filterModel->data(filterIndex, CustomEmojiModel::ReplacedTextRole);
|
||||
}
|
||||
if (role == Subtitle) {
|
||||
if (role == SubtitleRole) {
|
||||
return m_filterModel->data(filterIndex, EmojiModel::DescriptionRole);
|
||||
}
|
||||
}
|
||||
@@ -111,10 +111,10 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
|
||||
QHash<int, QByteArray> CompletionModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{Text, "text"},
|
||||
{Subtitle, "subtitle"},
|
||||
{Icon, "icon"},
|
||||
{ReplacedText, "replacedText"},
|
||||
{DisplayNameRole, "displayName"},
|
||||
{SubtitleRole, "subtitle"},
|
||||
{IconNameRole, "iconName"},
|
||||
{ReplacedTextRole, "replacedText"},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -64,10 +64,10 @@ public:
|
||||
* @brief Defines the model roles.
|
||||
*/
|
||||
enum Roles {
|
||||
Text = Qt::DisplayRole, /**< The main text to show. */
|
||||
Subtitle, /**< The subtitle text to show. */
|
||||
Icon, /**< The icon to show. */
|
||||
ReplacedText, /**< The text to replace the input text with for the completion. */
|
||||
DisplayNameRole = Qt::DisplayRole, /**< The main text to show. */
|
||||
SubtitleRole, /**< The subtitle text to show. */
|
||||
IconNameRole, /**< The icon to show. */
|
||||
ReplacedTextRole, /**< The text to replace the input text with for the completion. */
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QLocale>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <Quotient/csapi/device_management.h>
|
||||
@@ -52,6 +55,12 @@ QVariant DevicesModel::data(const QModelIndex &index, int role) const
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case TimestampString:
|
||||
if (device.lastSeenTs) {
|
||||
return QDateTime::fromMSecsSinceEpoch(*device.lastSeenTs).toString(QLocale().dateTimeFormat(QLocale::ShortFormat));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case Type:
|
||||
if (device.deviceId == m_connection->deviceId()) {
|
||||
return This;
|
||||
@@ -81,6 +90,7 @@ QHash<int, QByteArray> DevicesModel::roleNames() const
|
||||
{DisplayName, "displayName"},
|
||||
{LastIp, "lastIp"},
|
||||
{LastTimestamp, "lastTimestamp"},
|
||||
{TimestampString, "timestamp"},
|
||||
{Type, "type"},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
DisplayName, /**< Display name set by the user for this device. */
|
||||
LastIp, /**< The IP address where this device was last seen. */
|
||||
LastTimestamp, /**< The timestamp when this devices was last seen. */
|
||||
TimestampString, /**< String for the timestamp when this devices was last seen. */
|
||||
Type, /**< The category to sort this device into. */
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
bool operator<(const LiveLocationData &lhs, const LiveLocationData &rhs)
|
||||
@@ -88,6 +90,11 @@ QVariant LiveLocationsModel::data(const QModelIndex &index, int roleName) const
|
||||
const auto timeout = data.beaconInfo.value("timeout"_ls).toDouble(600000);
|
||||
return lastTs + timeout >= QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||
}
|
||||
case HeadingRole: {
|
||||
bool success = false;
|
||||
const auto heading = data.beacon["org.matrix.msc3488.location"_ls].toObject()["org.kde.itinerary.heading"_ls].toString().toDouble(&success);
|
||||
return success ? heading : NAN;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -101,6 +108,7 @@ QHash<int, QByteArray> LiveLocationsModel::roleNames() const
|
||||
r.insert(AssetRole, "asset");
|
||||
r.insert(AuthorRole, "author");
|
||||
r.insert(IsLiveRole, "isLive");
|
||||
r.insert(HeadingRole, "heading");
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
AssetRole, /**< Type of location event, e.g. self pin of the user location. */
|
||||
AuthorRole, /**< The author of the event. */
|
||||
IsLiveRole, /**< Boolean that indicates whether a live location beacon is still live. */
|
||||
HeadingRole, /**< Heading in degree (not part of any MSC yet, using an Itinerary extension). */
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "locationsmodel.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
LocationsModel::LocationsModel(QObject *parent)
|
||||
@@ -43,6 +45,10 @@ LocationsModel::LocationsModel(QObject *parent)
|
||||
});
|
||||
|
||||
connect(this, &LocationsModel::rowsInserted, this, &LocationsModel::boundingBoxChanged);
|
||||
|
||||
connect(static_cast<QGuiApplication *>(QGuiApplication::instance()), &QGuiApplication::paletteChanged, this, [this] {
|
||||
Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), {AuthorRole});
|
||||
});
|
||||
}
|
||||
|
||||
void LocationsModel::addLocation(const RoomMessageEvent *event)
|
||||
@@ -61,7 +67,7 @@ void LocationsModel::addLocation(const RoomMessageEvent *event)
|
||||
.latitude = latitude,
|
||||
.longitude = longitude,
|
||||
.content = event->contentJson(),
|
||||
.author = dynamic_cast<NeoChatUser *>(m_room->user(event->senderId())),
|
||||
.author = m_room->user(event->senderId()),
|
||||
};
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "neochatroom.h"
|
||||
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <Quotient/user.h>
|
||||
|
||||
class LocationsModel : public QAbstractListModel
|
||||
{
|
||||
@@ -51,7 +52,7 @@ private:
|
||||
float latitude;
|
||||
float longitude;
|
||||
QJsonObject content;
|
||||
NeoChatUser *author;
|
||||
Quotient::User *author;
|
||||
};
|
||||
QList<LocationData> m_locations;
|
||||
void addLocation(const Quotient::RoomMessageEvent *event);
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "models/reactionmodel.h"
|
||||
#include "neochatuser.h"
|
||||
#include "texthandler.h"
|
||||
|
||||
using namespace Quotient;
|
||||
@@ -78,7 +77,7 @@ MessageEventModel::MessageEventModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
connect(static_cast<QGuiApplication *>(QGuiApplication::instance()), &QGuiApplication::paletteChanged, this, [this] {
|
||||
Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), {AuthorRole, ReplyRole});
|
||||
Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), {AuthorRole, ReplyAuthor, ReadMarkersRole});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -531,7 +530,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
}
|
||||
|
||||
if (role == AuthorRole) {
|
||||
auto author = static_cast<NeoChatUser *>(isPending ? m_currentRoom->localUser() : m_currentRoom->user(evt.senderId()));
|
||||
auto author = isPending ? m_currentRoom->localUser() : m_currentRoom->user(evt.senderId());
|
||||
return m_currentRoom->getUser(author);
|
||||
}
|
||||
|
||||
@@ -679,7 +678,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
auto replyPtr = m_currentRoom->getReplyForEvent(evt);
|
||||
|
||||
if (replyPtr) {
|
||||
auto replyUser = static_cast<NeoChatUser *>(m_currentRoom->user(replyPtr->senderId()));
|
||||
auto replyUser = m_currentRoom->user(replyPtr->senderId());
|
||||
return m_currentRoom->getUser(replyUser);
|
||||
} else {
|
||||
return m_currentRoom->getUser(nullptr);
|
||||
@@ -808,7 +807,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
QVariantList users;
|
||||
users.reserve(userIds.size());
|
||||
for (const auto &userId : userIds) {
|
||||
auto user = static_cast<NeoChatUser *>(m_currentRoom->user(userId));
|
||||
auto user = m_currentRoom->user(userId);
|
||||
users += m_currentRoom->getUser(user);
|
||||
}
|
||||
|
||||
@@ -836,7 +835,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
*/
|
||||
QString readMarkersString = i18np("1 user: ", "%1 users: ", userIds.size());
|
||||
for (const auto &userId : userIds) {
|
||||
auto user = static_cast<NeoChatUser *>(m_currentRoom->user(userId));
|
||||
auto user = m_currentRoom->user(userId);
|
||||
readMarkersString += user->displayname(m_currentRoom) + i18nc("list separator", ", ");
|
||||
}
|
||||
readMarkersString.chop(2);
|
||||
@@ -877,7 +876,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
}
|
||||
|
||||
if (role == DisplayNameForInitialsRole) {
|
||||
auto user = static_cast<NeoChatUser *>(isPending ? m_currentRoom->localUser() : m_currentRoom->user(evt.senderId()));
|
||||
auto user = isPending ? m_currentRoom->localUser() : m_currentRoom->user(evt.senderId());
|
||||
return user->displayname(m_currentRoom).remove(QStringLiteral(" (%1)").arg(user->id()));
|
||||
}
|
||||
|
||||
@@ -889,7 +888,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
||||
}
|
||||
return previousDisplayName;
|
||||
} else {
|
||||
auto author = static_cast<NeoChatUser *>(isPending ? m_currentRoom->localUser() : m_currentRoom->user(evt.senderId()));
|
||||
auto author = isPending ? m_currentRoom->localUser() : m_currentRoom->user(evt.senderId());
|
||||
return m_currentRoom->htmlSafeMemberName(author->id());
|
||||
}
|
||||
}
|
||||
@@ -1062,13 +1061,13 @@ void MessageEventModel::createReactionModelForEvent(const Quotient::RoomMessageE
|
||||
return;
|
||||
};
|
||||
|
||||
QMap<QString, QList<NeoChatUser *>> reactions = {};
|
||||
QMap<QString, QList<Quotient::User *>> reactions = {};
|
||||
for (const auto &a : annotations) {
|
||||
if (a->isRedacted()) { // Just in case?
|
||||
continue;
|
||||
}
|
||||
if (const auto &e = eventCast<const ReactionEvent>(a)) {
|
||||
reactions[e->key()].append(static_cast<NeoChatUser *>(m_currentRoom->user(e->senderId())));
|
||||
reactions[e->key()].append(m_currentRoom->user(e->senderId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1095,7 +1094,7 @@ void MessageEventModel::createReactionModelForEvent(const Quotient::RoomMessageE
|
||||
if (m_reactionModels.contains(eventId)) {
|
||||
m_reactionModels[eventId]->setReactions(res);
|
||||
} else if (res.size() > 0) {
|
||||
m_reactionModels[eventId] = new ReactionModel(this, res, static_cast<NeoChatUser *>(m_currentRoom->localUser()));
|
||||
m_reactionModels[eventId] = new ReactionModel(this, res, m_currentRoom->localUser());
|
||||
} else {
|
||||
if (m_reactionModels.contains(eventId)) {
|
||||
delete m_reactionModels[eventId];
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "neochatuser.h"
|
||||
#include <Quotient/user.h>
|
||||
|
||||
ReactionModel::ReactionModel(QObject *parent, QList<Reaction> reactions, NeoChatUser *localUser)
|
||||
ReactionModel::ReactionModel(QObject *parent, QList<Reaction> reactions, Quotient::User *localUser)
|
||||
: QAbstractListModel(parent)
|
||||
, m_localUser(localUser)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class NeoChatUser;
|
||||
namespace Quotient
|
||||
{
|
||||
class User;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class ReactionModel
|
||||
@@ -36,7 +39,7 @@ public:
|
||||
HasLocalUser, /**< Whether the local user is in the list of authors. */
|
||||
};
|
||||
|
||||
explicit ReactionModel(QObject *parent = nullptr, QList<Reaction> reactions = {}, NeoChatUser *localUser = nullptr);
|
||||
explicit ReactionModel(QObject *parent = nullptr, QList<Reaction> reactions = {}, Quotient::User *localUser = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Get the given role value at the given index.
|
||||
@@ -67,6 +70,6 @@ public:
|
||||
private:
|
||||
QList<Reaction> m_reactions;
|
||||
|
||||
NeoChatUser *m_localUser;
|
||||
Quotient::User *m_localUser;
|
||||
};
|
||||
Q_DECLARE_METATYPE(ReactionModel *)
|
||||
|
||||
@@ -338,7 +338,7 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
|
||||
if (role == AvatarImageRole) {
|
||||
return room->avatar(128);
|
||||
}
|
||||
if (role == IdRole) {
|
||||
if (role == RoomIdRole) {
|
||||
return room->id();
|
||||
}
|
||||
if (role == IsSpaceRole) {
|
||||
@@ -379,7 +379,7 @@ QHash<int, QByteArray> RoomListModel::roleNames() const
|
||||
roles[CategoryVisibleRole] = "categoryVisible";
|
||||
roles[SubtitleTextRole] = "subtitleText";
|
||||
roles[IsSpaceRole] = "isSpace";
|
||||
roles[IdRole] = "id";
|
||||
roles[RoomIdRole] = "roomId";
|
||||
roles[IsChildSpaceRole] = "isChildSpace";
|
||||
return roles;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
CategoryVisibleRole, /**< If the room's category is visible. */
|
||||
SubtitleTextRole, /**< The text to show as the room subtitle. */
|
||||
AvatarImageRole, /**< The room avatar as an image. */
|
||||
IdRole, /**< The room matrix ID. */
|
||||
RoomIdRole, /**< The room matrix ID. */
|
||||
IsSpaceRole, /**< Whether the room is a space. */
|
||||
IsChildSpaceRole, /**< Whether this space is a child of a different space. */
|
||||
};
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
|
||||
#include "messageeventmodel.h"
|
||||
#include "neochatroom.h"
|
||||
#include "neochatuser.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/events/stickerevent.h>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
// TODO search only in the current room
|
||||
@@ -19,6 +20,9 @@ using namespace Quotient;
|
||||
SearchModel::SearchModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
connect(static_cast<QGuiApplication *>(QGuiApplication::instance()), &QGuiApplication::paletteChanged, this, [this] {
|
||||
Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), {AuthorRole, ReadMarkersRole});
|
||||
});
|
||||
}
|
||||
|
||||
QString SearchModel::searchText() const
|
||||
@@ -109,7 +113,7 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const
|
||||
return false;
|
||||
case ReplyAuthorRole:
|
||||
if (const auto &replyPtr = m_room->getReplyForEvent(event)) {
|
||||
return m_room->getUser(static_cast<NeoChatUser *>(m_room->user(replyPtr->senderId())));
|
||||
return m_room->getUser(m_room->user(replyPtr->senderId()));
|
||||
} else {
|
||||
return m_room->getUser(nullptr);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,8 @@ bool SortFilterRoomListModel::filterAcceptsRow(int source_row, const QModelIndex
|
||||
return acceptRoom;
|
||||
} else {
|
||||
const auto &rooms = SpaceHierarchyCache::instance().getRoomListForSpace(m_activeSpaceId, false);
|
||||
return std::find(rooms.begin(), rooms.end(), sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::IdRole).toString()) != rooms.end()
|
||||
return std::find(rooms.begin(), rooms.end(), sourceModel()->data(sourceModel()->index(source_row, 0), RoomListModel::RoomIdRole).toString())
|
||||
!= rooms.end()
|
||||
&& acceptRoom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
SortFilterSpaceListModel::SortFilterSpaceListModel(QObject *parent)
|
||||
: QSortFilterProxyModel{parent}
|
||||
{
|
||||
setSortRole(RoomListModel::IdRole);
|
||||
setSortRole(RoomListModel::RoomIdRole);
|
||||
sort(0);
|
||||
invalidateFilter();
|
||||
connect(this, &QAbstractProxyModel::sourceModelChanged, this, [this]() {
|
||||
@@ -33,8 +33,8 @@ bool SortFilterSpaceListModel::filterAcceptsRow(int source_row, const QModelInde
|
||||
|
||||
bool SortFilterSpaceListModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
const auto idLeft = sourceModel()->data(source_left, RoomListModel::IdRole).toString();
|
||||
const auto idRight = sourceModel()->data(source_right, RoomListModel::IdRole).toString();
|
||||
const auto idLeft = sourceModel()->data(source_left, RoomListModel::RoomIdRole).toString();
|
||||
const auto idRight = sourceModel()->data(source_right, RoomListModel::RoomIdRole).toString();
|
||||
return idLeft < idRight;
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const
|
||||
auto avatarUrl = user.avatarUrl;
|
||||
|
||||
if (avatarUrl.isEmpty()) {
|
||||
return "";
|
||||
return QString();
|
||||
}
|
||||
return avatarUrl.url().remove(0, 6);
|
||||
}
|
||||
@@ -153,7 +153,7 @@ QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
if (role == DirectChatsRole) {
|
||||
if (!m_connection) {
|
||||
return {};
|
||||
return QStringList();
|
||||
};
|
||||
|
||||
auto userObj = m_connection->user(user.userId);
|
||||
@@ -165,6 +165,8 @@ QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const
|
||||
return QVariant::fromValue(directChatsForUser);
|
||||
}
|
||||
}
|
||||
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "userlistmodel.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/events/roompowerlevelsevent.h>
|
||||
|
||||
@@ -14,6 +16,9 @@ UserListModel::UserListModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_currentRoom(nullptr)
|
||||
{
|
||||
connect(static_cast<QGuiApplication *>(QGuiApplication::instance()), &QGuiApplication::paletteChanged, this, [this]() {
|
||||
refreshAllUsers();
|
||||
});
|
||||
}
|
||||
|
||||
void UserListModel::setRoom(NeoChatRoom *room)
|
||||
@@ -71,8 +76,7 @@ QVariant UserListModel::data(const QModelIndex &index, int role) const
|
||||
return user->id();
|
||||
}
|
||||
if (role == AvatarRole) {
|
||||
auto neoChatUser = static_cast<NeoChatUser *>(user);
|
||||
return m_currentRoom->avatarForMember(neoChatUser);
|
||||
return m_currentRoom->avatarForMember(user);
|
||||
}
|
||||
if (role == ObjectRole) {
|
||||
return QVariant::fromValue(user);
|
||||
|
||||
@@ -54,7 +54,7 @@ Comment[es]=Un cliente para Matrix, el protocolo de comunicaciones descentraliza
|
||||
Comment[eu]=Matrix, deszentralizatutako komunikazio protokolorako, bezero bat
|
||||
Comment[fi]=Hajautetun Matrix-viestintäyhteyskäytännön asiakasohjelma
|
||||
Comment[fr]=Un client pour « Matrix », le protocole décentralisé de communications.
|
||||
Comment[gl]=Un cliente para Matrix, o protocolo de comunicación descentralizada
|
||||
Comment[gl]=Un cliente para Matrix, o protocolo de comunicación descentralizada.
|
||||
Comment[hu]=Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz
|
||||
Comment[ia]=Un cliente per Matrix, le protocollo de communication decentralisate
|
||||
Comment[id]=Sebuah klien untuk matrix, protokol komunikasi terdecentralisasi
|
||||
@@ -133,7 +133,7 @@ Comment[es]=Hay un mensaje nuevo
|
||||
Comment[eu]=Mezu berri bat dago
|
||||
Comment[fi]=Saapui uusi viesti
|
||||
Comment[fr]=Il y a un nouveau message
|
||||
Comment[gl]=Hai unha nova mensaxe
|
||||
Comment[gl]=Hai unha nova mensaxe.
|
||||
Comment[hu]=Új üzenet érkezett
|
||||
Comment[ia]=Il ha un nove message
|
||||
Comment[id]=Ada pesan baru
|
||||
@@ -209,7 +209,7 @@ Comment[es]=Hay una nueva invitación a una sala
|
||||
Comment[eu]=Gela baterako gonbidapen berri bat dago
|
||||
Comment[fi]=Uusi kutsu huoneeseen
|
||||
Comment[fr]=Il y a une nouvelle invitation dans un salon.
|
||||
Comment[gl]=Tes un novo convite para unha sala
|
||||
Comment[gl]=Tes un novo convite para unha sala.
|
||||
Comment[ia]=Il ha un nove invitation a un sala
|
||||
Comment[id]=Ada undangan baru ke sebuah ruangan
|
||||
Comment[ie]=Vu have un nov invitation a un chambre
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
#include "neochatroom.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QGuiApplication>
|
||||
#include <QMetaObject>
|
||||
#include <QMimeDatabase>
|
||||
#include <QPalette>
|
||||
#include <QTemporaryFile>
|
||||
#include <QTextDocument>
|
||||
|
||||
@@ -13,6 +15,7 @@
|
||||
#include <QMediaPlayer>
|
||||
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/user.h>
|
||||
#include <qcoro/qcorosignal.h>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
@@ -43,6 +46,7 @@
|
||||
#include "neochatconfig.h"
|
||||
#include "notificationsmanager.h"
|
||||
#include "texthandler.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
@@ -412,11 +416,11 @@ QVariantList NeoChatRoom::getUsers(const QString &keyword, int limit) const
|
||||
int count = 0;
|
||||
for (const auto u : userList) {
|
||||
if (u->displayname(this).contains(keyword, Qt::CaseInsensitive)) {
|
||||
NeoChatUser user(u->id(), u->connection());
|
||||
Quotient::User user(u->id(), u->connection());
|
||||
QVariantMap userVariant{{QStringLiteral("id"), user.id()},
|
||||
{QStringLiteral("displayName"), user.displayname(this)},
|
||||
{QStringLiteral("avatarMediaId"), user.avatarMediaId(this)},
|
||||
{QStringLiteral("color"), user.color()}};
|
||||
{QStringLiteral("color"), Utils::getUserColor(user.hueF())}};
|
||||
|
||||
matchedList.append(QVariant::fromValue(userVariant));
|
||||
count++;
|
||||
@@ -442,11 +446,10 @@ static const QVariantMap emptyUser = {
|
||||
|
||||
QVariantMap NeoChatRoom::getUser(const QString &userID) const
|
||||
{
|
||||
NeoChatUser *userObject = static_cast<NeoChatUser *>(user(userID));
|
||||
return getUser(userObject);
|
||||
return getUser(user(userID));
|
||||
}
|
||||
|
||||
QVariantMap NeoChatRoom::getUser(NeoChatUser *user) const
|
||||
QVariantMap NeoChatRoom::getUser(User *user) const
|
||||
{
|
||||
if (user == nullptr) {
|
||||
return emptyUser;
|
||||
@@ -458,7 +461,7 @@ QVariantMap NeoChatRoom::getUser(NeoChatUser *user) const
|
||||
{QStringLiteral("displayName"), user->displayname(this)},
|
||||
{QStringLiteral("avatarSource"), avatarForMember(user)},
|
||||
{QStringLiteral("avatarMediaId"), user->avatarMediaId(this)},
|
||||
{QStringLiteral("color"), user->color()},
|
||||
{QStringLiteral("color"), Utils::getUserColor(user->hueF())},
|
||||
{QStringLiteral("object"), QVariant::fromValue(user)},
|
||||
};
|
||||
}
|
||||
@@ -539,7 +542,7 @@ QString NeoChatRoom::eventToString(const RoomEvent &evt, Qt::TextFormat format,
|
||||
|
||||
if (prettyPrint) {
|
||||
subjectName = QStringLiteral("<a href=\"https://matrix.to/#/%1\" style=\"color: %2\">%3</a>")
|
||||
.arg(e.userId(), static_cast<NeoChatUser *>(user(e.userId()))->color().name(), subjectName);
|
||||
.arg(e.userId(), Utils::getUserColor(user(e.userId())->hueF()).name(), subjectName);
|
||||
}
|
||||
|
||||
// The below code assumes senderName output in AuthorRole
|
||||
@@ -993,7 +996,7 @@ void NeoChatRoom::deleteMessagesByUser(const QString &user, const QString &reaso
|
||||
QString NeoChatRoom::joinRule() const
|
||||
{
|
||||
auto joinRulesEvent = currentState().get<JoinRulesEvent>();
|
||||
if (joinRulesEvent) {
|
||||
if (!joinRulesEvent) {
|
||||
return {};
|
||||
}
|
||||
return joinRulesEvent->joinRule();
|
||||
@@ -1682,7 +1685,7 @@ QVariantMap NeoChatRoom::chatBoxReplyUser() const
|
||||
if (m_chatBoxReplyId.isEmpty()) {
|
||||
return emptyUser;
|
||||
}
|
||||
return getUser(static_cast<NeoChatUser *>(user((*findInTimeline(m_chatBoxReplyId))->senderId())));
|
||||
return getUser(user((*findInTimeline(m_chatBoxReplyId))->senderId()));
|
||||
}
|
||||
|
||||
QString NeoChatRoom::chatBoxReplyMessage() const
|
||||
@@ -1698,7 +1701,7 @@ QVariantMap NeoChatRoom::chatBoxEditUser() const
|
||||
if (m_chatBoxEditId.isEmpty()) {
|
||||
return emptyUser;
|
||||
}
|
||||
return getUser(static_cast<NeoChatUser *>(user((*findInTimeline(m_chatBoxEditId))->senderId())));
|
||||
return getUser(user((*findInTimeline(m_chatBoxEditId))->senderId()));
|
||||
}
|
||||
|
||||
QString NeoChatRoom::chatBoxEditMessage() const
|
||||
@@ -1904,9 +1907,10 @@ int NeoChatRoom::maxRoomVersion() const
|
||||
}
|
||||
return maxVersion;
|
||||
}
|
||||
NeoChatUser *NeoChatRoom::directChatRemoteUser() const
|
||||
|
||||
Quotient::User *NeoChatRoom::directChatRemoteUser() const
|
||||
{
|
||||
return dynamic_cast<NeoChatUser *>(connection()->directChatUsers(this)[0]);
|
||||
return connection()->directChatUsers(this)[0];
|
||||
}
|
||||
|
||||
void NeoChatRoom::sendLocation(float lat, float lon, const QString &description)
|
||||
@@ -1938,10 +1942,10 @@ QByteArray NeoChatRoom::roomAcountDataJson(const QString &eventType)
|
||||
return QJsonDocument(accountData(eventType)->fullJson()).toJson();
|
||||
}
|
||||
|
||||
QUrl NeoChatRoom::avatarForMember(NeoChatUser *user) const
|
||||
QUrl NeoChatRoom::avatarForMember(Quotient::User *user) const
|
||||
{
|
||||
const auto &url = memberAvatarUrl(user->id());
|
||||
if (url.isEmpty()) {
|
||||
if (url.isEmpty() || url.scheme() != "mxc"_ls) {
|
||||
return {};
|
||||
}
|
||||
auto avatar = connection()->makeMediaUrl(url);
|
||||
|
||||
@@ -10,10 +10,15 @@
|
||||
#include <QTextCursor>
|
||||
|
||||
#include <QCoroTask>
|
||||
#include <Quotient/user.h>
|
||||
|
||||
#include "neochatuser.h"
|
||||
#include "pollhandler.h"
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
class User;
|
||||
}
|
||||
|
||||
class PushNotificationState : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -64,7 +69,7 @@ class NeoChatRoom : public Quotient::Room
|
||||
*
|
||||
* The list does not include the local user.
|
||||
*
|
||||
* This is different to getting a list of NeoChatUser objects or Quotient::User objects
|
||||
* This is different to getting a list of Quotient::User objects
|
||||
* as neither of those can provide details like the displayName or avatarMediaId
|
||||
* without the room context as these can vary from room to room. This function
|
||||
* provides the room context and puts the result as a list of QVariantMap objects.
|
||||
@@ -76,7 +81,7 @@ class NeoChatRoom : public Quotient::Room
|
||||
* - displayName - Display name in the context of this room.
|
||||
* - display - Name in the context of this room.
|
||||
*
|
||||
* @sa Quotient::User, NeoChatUser
|
||||
* @sa Quotient::User
|
||||
*/
|
||||
Q_PROPERTY(QVariantList usersTyping READ getUsersTyping NOTIFY typingChanged)
|
||||
|
||||
@@ -119,7 +124,7 @@ class NeoChatRoom : public Quotient::Room
|
||||
/**
|
||||
* @brief Get a user object for the other person in a direct chat.
|
||||
*/
|
||||
Q_PROPERTY(NeoChatUser *directChatRemoteUser READ directChatRemoteUser CONSTANT)
|
||||
Q_PROPERTY(Quotient::User *directChatRemoteUser READ directChatRemoteUser CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief If the room is a space.
|
||||
@@ -316,7 +321,7 @@ class NeoChatRoom : public Quotient::Room
|
||||
/**
|
||||
* @brief Get the user for the message being replied to.
|
||||
*
|
||||
* This is different to getting a NeoChatUser object or Quotient::User object
|
||||
* This is different to getting a Quotient::User object
|
||||
* as neither of those can provide details like the displayName or avatarMediaId
|
||||
* without the room context as these can vary from room to room.
|
||||
*
|
||||
@@ -329,9 +334,9 @@ class NeoChatRoom : public Quotient::Room
|
||||
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
||||
* - avatarMediaId - Avatar id in the context of this room.
|
||||
* - color - Color for the user.
|
||||
* - object - The NeoChatUser object for the user.
|
||||
* - object - The Quotient::User object for the user.
|
||||
*
|
||||
* @sa getUser, Quotient::User, NeoChatUser
|
||||
* @sa getUser, Quotient::User
|
||||
*/
|
||||
Q_PROPERTY(QVariantMap chatBoxReplyUser READ chatBoxReplyUser NOTIFY chatBoxReplyIdChanged)
|
||||
|
||||
@@ -345,7 +350,7 @@ class NeoChatRoom : public Quotient::Room
|
||||
/**
|
||||
* @brief Get the user for the message being edited.
|
||||
*
|
||||
* This is different to getting a NeoChatUser object or Quotient::User object
|
||||
* This is different to getting a Quotient::User object
|
||||
* as neither of those can provide details like the displayName or avatarMediaId
|
||||
* without the room context as these can vary from room to room.
|
||||
*
|
||||
@@ -358,9 +363,9 @@ class NeoChatRoom : public Quotient::Room
|
||||
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
||||
* - avatarMediaId - Avatar id in the context of this room.
|
||||
* - color - Color for the user.
|
||||
* - object - The NeoChatUser object for the user.
|
||||
* - object - The Quotient::User object for the user.
|
||||
*
|
||||
* @sa getUser, Quotient::User, NeoChatUser
|
||||
* @sa getUser, Quotient::User
|
||||
*/
|
||||
Q_PROPERTY(QVariantMap chatBoxEditUser READ chatBoxEditUser NOTIFY chatBoxEditIdChanged)
|
||||
|
||||
@@ -392,7 +397,7 @@ public:
|
||||
/**
|
||||
* @brief Get a list of users in the context of this room.
|
||||
*
|
||||
* This is different to getting a list of NeoChatUser objects or Quotient::User objects
|
||||
* This is different to getting a list of Quotient::User objects
|
||||
* as neither of those can provide details like the displayName or avatarMediaId
|
||||
* without the room context as these can vary from room to room. This function
|
||||
* provides the room context and returns the result as a list of QVariantMap objects.
|
||||
@@ -407,14 +412,14 @@ public:
|
||||
* - avatarMediaId - Avatar id in the context of this room.
|
||||
* - color - Color for the user.
|
||||
*
|
||||
* @sa Quotient::User, NeoChatUser
|
||||
* @sa Quotient::User
|
||||
*/
|
||||
Q_INVOKABLE [[nodiscard]] QVariantList getUsers(const QString &keyword, int limit = -1) const;
|
||||
|
||||
/**
|
||||
* @brief Get a user in the context of this room.
|
||||
*
|
||||
* This is different to getting a NeoChatUser object or Quotient::User object
|
||||
* This is different to getting a Quotient::User object
|
||||
* as neither of those can provide details like the displayName or avatarMediaId
|
||||
* without the room context as these can vary from room to room. This function
|
||||
* provides the room context and outputs the result as QVariantMap.
|
||||
@@ -431,16 +436,16 @@ public:
|
||||
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
||||
* - avatarMediaId - Avatar id in the context of this room.
|
||||
* - color - Color for the user.
|
||||
* - object - The NeoChatUser object for the user.
|
||||
* - object - The Quotient::User object for the user.
|
||||
*
|
||||
* @sa Quotient::User, NeoChatUser
|
||||
* @sa Quotient::User
|
||||
*/
|
||||
Q_INVOKABLE [[nodiscard]] QVariantMap getUser(const QString &userID) const;
|
||||
|
||||
/**
|
||||
* @brief Get a user in the context of this room.
|
||||
*
|
||||
* This is different to getting a NeoChatUser object or Quotient::User object
|
||||
* This is different to getting a Quotient::User object
|
||||
* as neither of those can provide details like the displayName or avatarMediaId
|
||||
* without the room context as these can vary from room to room. This function
|
||||
* provides the room context and outputs the result as QVariantMap.
|
||||
@@ -457,11 +462,11 @@ public:
|
||||
* - avatarSource - The mxc URL for the user's avatar in the current room.
|
||||
* - avatarMediaId - Avatar id in the context of this room.
|
||||
* - color - Color for the user.
|
||||
* - object - The NeoChatUser object for the user.
|
||||
* - object - The Quotient::User object for the user.
|
||||
*
|
||||
* @sa Quotient::User, NeoChatUser
|
||||
* @sa Quotient::User
|
||||
*/
|
||||
Q_INVOKABLE [[nodiscard]] QVariantMap getUser(NeoChatUser *user) const;
|
||||
Q_INVOKABLE [[nodiscard]] QVariantMap getUser(Quotient::User *user) const;
|
||||
|
||||
[[nodiscard]] QVariantList getUsersTyping() const;
|
||||
|
||||
@@ -602,7 +607,7 @@ public:
|
||||
|
||||
[[nodiscard]] QString avatarMediaId() const;
|
||||
|
||||
NeoChatUser *directChatRemoteUser() const;
|
||||
Quotient::User *directChatRemoteUser() const;
|
||||
|
||||
[[nodiscard]] bool isSpace();
|
||||
|
||||
@@ -818,7 +823,7 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE QByteArray roomAcountDataJson(const QString &eventType);
|
||||
|
||||
Q_INVOKABLE [[nodiscard]] QUrl avatarForMember(NeoChatUser *user) const;
|
||||
Q_INVOKABLE [[nodiscard]] QUrl avatarForMember(Quotient::User *user) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the event that is being replied to. This includes events that were manually loaded using NeoChatRoom::loadReply.
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#include "neochatuser.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QJsonObject>
|
||||
#include <QPalette>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
NeoChatUser::NeoChatUser(QString userId, Connection *connection)
|
||||
: User(std::move(userId), connection)
|
||||
{
|
||||
connect(static_cast<QGuiApplication *>(QGuiApplication::instance()), &QGuiApplication::paletteChanged, this, &NeoChatUser::polishColor);
|
||||
polishColor();
|
||||
}
|
||||
|
||||
QColor NeoChatUser::color()
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
|
||||
void NeoChatUser::setColor(const QColor &color)
|
||||
{
|
||||
if (m_color == color) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_color = color;
|
||||
Q_EMIT colorChanged(m_color);
|
||||
}
|
||||
|
||||
void NeoChatUser::polishColor()
|
||||
{
|
||||
const auto lightness = static_cast<QGuiApplication *>(QGuiApplication::instance())->palette().color(QPalette::Active, QPalette::Window).lightnessF();
|
||||
// https://github.com/quotient-im/libQuotient/wiki/User-color-coding-standard-draft-proposal
|
||||
setColor(QColor::fromHslF(hueF(), 1, -0.7 * lightness + 0.9, 1));
|
||||
}
|
||||
|
||||
#include "moc_neochatuser.cpp"
|
||||
@@ -1,39 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <Quotient/user.h>
|
||||
|
||||
/**
|
||||
* @class NeoChatUser
|
||||
*
|
||||
* A class inherited from Quotient::User to add a user color function.
|
||||
*
|
||||
* @sa Quotient::User
|
||||
*/
|
||||
class NeoChatUser : public Quotient::User
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* @brief The color to use for the user.
|
||||
*/
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
|
||||
public:
|
||||
explicit NeoChatUser(QString userId, Quotient::Connection *connection);
|
||||
|
||||
public Q_SLOTS:
|
||||
QColor color();
|
||||
void setColor(const QColor &color);
|
||||
|
||||
Q_SIGNALS:
|
||||
void colorChanged(QColor _t1);
|
||||
|
||||
private:
|
||||
QColor m_color;
|
||||
|
||||
void polishColor();
|
||||
};
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <KNotification>
|
||||
#include <KNotificationReplyAction>
|
||||
|
||||
#include <QPainter>
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/csapi/pushrules.h>
|
||||
@@ -203,7 +204,7 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
|
||||
}
|
||||
|
||||
notification->setText(notification->text() + '\n' + entry);
|
||||
notification->setPixmap(QPixmap::fromImage(icon));
|
||||
notification->setPixmap(createNotificationImage(icon, room));
|
||||
|
||||
notification->setDefaultAction(i18n("Open NeoChat in this room"));
|
||||
connect(notification, &KNotification::defaultActivated, this, [notification, room]() {
|
||||
@@ -239,7 +240,7 @@ void NotificationsManager::postInviteNotification(NeoChatRoom *room, const QStri
|
||||
KNotification *notification = new KNotification("invite");
|
||||
notification->setText(i18n("%1 invited you to a room", sender));
|
||||
notification->setTitle(title);
|
||||
notification->setPixmap(img);
|
||||
notification->setPixmap(createNotificationImage(icon, nullptr));
|
||||
notification->setFlags(KNotification::Persistent);
|
||||
notification->setDefaultAction(i18n("Open this invitation in NeoChat"));
|
||||
connect(notification, &KNotification::defaultActivated, this, [notification, room]() {
|
||||
@@ -282,4 +283,33 @@ void NotificationsManager::clearInvitationNotification(const QString &roomId)
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap NotificationsManager::createNotificationImage(const QImage &icon, NeoChatRoom *room)
|
||||
{
|
||||
// Handle avatars that are lopsided in one dimension
|
||||
const int biggestDimension = std::max(icon.width(), icon.height());
|
||||
const QRect imageRect{0, 0, biggestDimension, biggestDimension};
|
||||
|
||||
QImage roundedImage(imageRect.size(), QImage::Format_ARGB32);
|
||||
roundedImage.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&roundedImage);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
QBrush brush(icon.scaledToHeight(biggestDimension));
|
||||
painter.setBrush(brush);
|
||||
painter.drawRoundedRect(imageRect, imageRect.width(), imageRect.height());
|
||||
|
||||
if (room != nullptr) {
|
||||
const QImage roomAvatar = room->avatar(imageRect.width(), imageRect.height());
|
||||
if (icon != roomAvatar) {
|
||||
const QRect lowerQuarter{imageRect.center(), imageRect.size() / 2};
|
||||
|
||||
painter.setBrush(roomAvatar.scaled(lowerQuarter.size()));
|
||||
painter.drawRoundedRect(lowerQuarter, lowerQuarter.width(), lowerQuarter.height());
|
||||
}
|
||||
}
|
||||
|
||||
return QPixmap::fromImage(roundedImage);
|
||||
}
|
||||
|
||||
#include "moc_notificationsmanager.cpp"
|
||||
|
||||
@@ -97,4 +97,7 @@ private:
|
||||
|
||||
private Q_SLOTS:
|
||||
void processNotificationJob(QPointer<Quotient::Connection> connection, Quotient::GetNotificationsJob *job, bool initialization);
|
||||
|
||||
private:
|
||||
QPixmap createNotificationImage(const QImage &icon, NeoChatRoom *room);
|
||||
};
|
||||
|
||||
@@ -53,7 +53,7 @@ Comment[es]=Buscar salas en NeoChat
|
||||
Comment[eu]=Bilatu gelak NeoChat-en
|
||||
Comment[fi]=Etsi huoneita NeoChatissä
|
||||
Comment[fr]=Trouver des salons dans NeoChat
|
||||
Comment[gl]=Atopa salas en NeoChat
|
||||
Comment[gl]=Atopa salas en NeoChat.
|
||||
Comment[ia]=Trova salas in NeoChat
|
||||
Comment[id]=Cari ruangan di NeoChat
|
||||
Comment[ie]=Trovar chambres in NeoChat
|
||||
|
||||
@@ -6,185 +6,33 @@ import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Templates 2.15 as T
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
|
||||
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
|
||||
|
||||
T.TabButton {
|
||||
id: control
|
||||
Delegates.RoundedItemDelegate {
|
||||
id: root
|
||||
|
||||
/**
|
||||
* @brief This property specifies the index of this tab within the tab bar.
|
||||
*/
|
||||
readonly property int tabIndex: {
|
||||
let tabIdx = 0
|
||||
for (let i = 0; i < parent.children.length; ++i) {
|
||||
if (parent.children[i] === this) {
|
||||
return tabIdx
|
||||
}
|
||||
// Checking for AbstractButtons because any AbstractButton can act as a tab
|
||||
if (parent.children[i] instanceof T.AbstractButton) {
|
||||
++tabIdx
|
||||
}
|
||||
}
|
||||
return -1
|
||||
required property url source
|
||||
|
||||
signal contextMenuRequested()
|
||||
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.text: text
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
|
||||
onPressAndHold: root.contextMenuRequested()
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.RightButton
|
||||
acceptedDevices: PointerDevice.Mouse
|
||||
onTapped: root.contextMenuRequested()
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This property sets whether the icon colors should be masked with a single color.
|
||||
*
|
||||
* default: ``true``
|
||||
*
|
||||
* @since KDE Frameworks 5.96
|
||||
*/
|
||||
property bool recolorIcon: true
|
||||
|
||||
property color foregroundColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.85)
|
||||
property color highlightForegroundColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.85)
|
||||
property color highlightBarColor: Kirigami.Theme.highlightColor
|
||||
|
||||
property color pressedColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.3)
|
||||
property color hoverSelectColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.2)
|
||||
property color checkedBorderColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.7)
|
||||
property color pressedBorderColor: Qt.rgba(highlightBarColor.r, highlightBarColor.g, highlightBarColor.b, 0.9)
|
||||
|
||||
property url source
|
||||
property string name
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding)
|
||||
|
||||
display: T.AbstractButton.TextUnderIcon
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
Kirigami.Theme.inherit: false
|
||||
|
||||
// not using the hover handler built into control, since it seems to misbehave and
|
||||
// permanently report hovered after a touch event
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
}
|
||||
|
||||
padding: Kirigami.Units.smallSpacing
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
icon.height: control.display === T.AbstractButton.TextBesideIcon ? Kirigami.Units.iconSizes.small : Kirigami.Units.iconSizes.smallMedium
|
||||
icon.width: control.display === T.AbstractButton.TextBesideIcon ? Kirigami.Units.iconSizes.small : Kirigami.Units.iconSizes.smallMedium
|
||||
icon.color: control.checked ? control.highlightForegroundColor : control.foregroundColor
|
||||
|
||||
background: Rectangle {
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
||||
Kirigami.Theme.inherit: false
|
||||
|
||||
implicitHeight: (control.display === T.AbstractButton.TextBesideIcon) ? 0 : (Kirigami.Units.gridUnit * 3 + Kirigami.Units.smallSpacing * 2)
|
||||
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
width: parent.width - Kirigami.Units.largeSpacing
|
||||
height: parent.height - Kirigami.Units.largeSpacing
|
||||
anchors.centerIn: parent
|
||||
|
||||
radius: Kirigami.Units.smallSpacing
|
||||
color: control.down ? pressedColor : (control.checked || hoverHandler.hovered ? hoverSelectColor : "transparent")
|
||||
|
||||
border.color: control.checked ? checkedBorderColor : (control.down ? pressedBorderColor : color)
|
||||
border.width: 1
|
||||
|
||||
Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration } }
|
||||
Behavior on border.color { ColorAnimation { duration: Kirigami.Units.shortDuration } }
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: GridLayout {
|
||||
id: gridLayout
|
||||
columnSpacing: 0
|
||||
rowSpacing: (label.visible && label.lineCount > 1) ? 0 : control.spacing
|
||||
|
||||
// if this is a row or a column
|
||||
columns: control.display !== T.AbstractButton.TextBesideIcon ? 1 : 2
|
||||
|
||||
property real verticalMargins: (control.display === T.AbstractButton.TextBesideIcon) ? Kirigami.Units.largeSpacing : 0
|
||||
|
||||
Kirigami.Avatar {
|
||||
id: icon
|
||||
source: control.source
|
||||
name: control.name
|
||||
Layout.topMargin: gridLayout.verticalMargins
|
||||
Layout.bottomMargin: gridLayout.verticalMargins
|
||||
Layout.leftMargin: (control.display === T.AbstractButton.TextBesideIcon) ? Kirigami.Units.gridUnit : 0
|
||||
Layout.rightMargin: (control.display === T.AbstractButton.TextBesideIcon) ? Kirigami.Units.gridUnit : 0
|
||||
|
||||
Layout.alignment: {
|
||||
if (control.display === T.AbstractButton.TextBesideIcon) {
|
||||
// row layout
|
||||
return Qt.AlignVCenter | Qt.AlignRight;
|
||||
} else {
|
||||
// column layout
|
||||
return Qt.AlignHCenter | ((!label.visible || label.lineCount > 1) ? Qt.AlignVCenter : Qt.AlignBottom);
|
||||
}
|
||||
}
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
|
||||
}
|
||||
QQC2.Label {
|
||||
id: label
|
||||
Kirigami.MnemonicData.enabled: control.enabled && control.visible
|
||||
Kirigami.MnemonicData.controlType: Kirigami.MnemonicData.MenuItem
|
||||
Kirigami.MnemonicData.label: control.text
|
||||
|
||||
text: Kirigami.MnemonicData.richTextLabel
|
||||
horizontalAlignment: (control.display === T.AbstractButton.TextBesideIcon) ? Text.AlignLeft : Text.AlignHCenter
|
||||
|
||||
visible: control.display !== T.AbstractButton.IconOnly
|
||||
wrapMode: Text.Wrap
|
||||
elide: Text.ElideMiddle
|
||||
color: control.checked ? control.highlightForegroundColor : control.foregroundColor
|
||||
|
||||
font.bold: control.checked
|
||||
font.family: Kirigami.Theme.smallFont.family
|
||||
font.pointSize: {
|
||||
if (control.display === T.AbstractButton.TextBesideIcon) {
|
||||
// row layout
|
||||
return Kirigami.Theme.defaultFont.pointSize;
|
||||
} else {
|
||||
// column layout
|
||||
return icon.visible ? Kirigami.Theme.smallFont.pointSize : Kirigami.Theme.defaultFont.pointSize * 1.20; // 1.20 is equivalent to level 2 heading
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color { ColorAnimation {} }
|
||||
Behavior on opacity { NumberAnimation {} }
|
||||
|
||||
Layout.topMargin: gridLayout.verticalMargins
|
||||
Layout.bottomMargin: gridLayout.verticalMargins
|
||||
|
||||
Layout.alignment: {
|
||||
if (control.display === T.AbstractButton.TextBesideIcon) {
|
||||
// row layout
|
||||
return Qt.AlignVCenter | Qt.AlignLeft;
|
||||
} else {
|
||||
// column layout
|
||||
return icon.visible ? Qt.AlignHCenter | Qt.AlignTop : Qt.AlignCenter;
|
||||
}
|
||||
}
|
||||
|
||||
// Work around bold text changing implicit size
|
||||
Layout.preferredWidth: boldMetrics.implicitWidth
|
||||
Layout.preferredHeight: boldMetrics.implicitHeight * label.lineCount
|
||||
Layout.fillWidth: true
|
||||
|
||||
QQC2.Label {
|
||||
id: boldMetrics
|
||||
visible: false
|
||||
text: parent.text
|
||||
font.bold: true
|
||||
font.family: Kirigami.Theme.smallFont.family
|
||||
font.pointSize: Kirigami.Theme.smallFont.pointSize
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: QQC2.Label.Wrap
|
||||
elide: Text.ElideMiddle
|
||||
}
|
||||
}
|
||||
contentItem: KirigamiComponents.Avatar {
|
||||
source: root.source
|
||||
name: root.text
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ QQC2.Control {
|
||||
/**
|
||||
* @brief The current room that user is viewing.
|
||||
*/
|
||||
property NeoChatRoom currentRoom
|
||||
required property NeoChatRoom currentRoom
|
||||
|
||||
/**
|
||||
* @brief The QQC2.TextArea object.
|
||||
@@ -55,10 +55,10 @@ QQC2.Control {
|
||||
Kirigami.Action {
|
||||
id: attachmentAction
|
||||
|
||||
property bool isBusy: currentRoom && currentRoom.hasFileUploading
|
||||
property bool isBusy: root.currentRoom && root.currentRoom.hasFileUploading
|
||||
|
||||
// Matrix does not allow sending attachments in replies
|
||||
visible: currentRoom.chatBoxReplyId.length === 0 && currentRoom.chatBoxAttachmentPath.length === 0
|
||||
visible: root.currentRoom.chatBoxReplyId.length === 0 && root.currentRoom.chatBoxAttachmentPath.length === 0
|
||||
icon.name: "mail-attachment"
|
||||
text: i18n("Attach an image or file")
|
||||
displayHint: Kirigami.DisplayHint.IconOnly
|
||||
@@ -72,7 +72,7 @@ QQC2.Control {
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
currentRoom.chatBoxAttachmentPath = path;
|
||||
root.currentRoom.chatBoxAttachmentPath = path;
|
||||
})
|
||||
fileDialog.open()
|
||||
}
|
||||
@@ -106,7 +106,7 @@ QQC2.Control {
|
||||
displayHint: QQC2.AbstractButton.IconOnly
|
||||
|
||||
onTriggered: {
|
||||
locationChooserComponent.createObject(QQC2.ApplicationWindow.overlay, {room: currentRoom}).open()
|
||||
locationChooserComponent.createObject(QQC2.ApplicationWindow.overlay, {room: root.currentRoom}).open()
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
@@ -162,10 +162,12 @@ QQC2.Control {
|
||||
leftPadding: LayoutMirroring.enabled ? actionsRow.width : Kirigami.Units.largeSpacing
|
||||
rightPadding: LayoutMirroring.enabled ? Kirigami.Units.largeSpacing : actionsRow.width + x * 2 + Kirigami.Units.largeSpacing * 2
|
||||
|
||||
placeholderText: readOnly ? i18n("This room is encrypted. Build libQuotient with encryption enabled to send encrypted messages.") : currentRoom.usesEncryption ? i18n("Send an encrypted message…") : currentRoom.chatBoxAttachmentPath.length > 0 ? i18n("Set an attachment caption...") : i18n("Send a message…")
|
||||
placeholderText: readOnly ? i18n("This room is encrypted. Build libQuotient with encryption enabled to send encrypted messages.") : root.currentRoom.usesEncryption ? i18n("Send an encrypted message…") : root.currentRoom.chatBoxAttachmentPath.length > 0 ? i18n("Set an attachment caption...") : i18n("Send a message…")
|
||||
verticalAlignment: TextEdit.AlignVCenter
|
||||
wrapMode: Text.Wrap
|
||||
readOnly: (currentRoom.usesEncryption && !Controller.encryptionSupported)
|
||||
readOnly: (root.currentRoom.usesEncryption && !Controller.encryptionSupported)
|
||||
|
||||
Accessible.description: placeholderText
|
||||
|
||||
Timer {
|
||||
id: repeatTimer
|
||||
@@ -175,10 +177,10 @@ QQC2.Control {
|
||||
onTextChanged: {
|
||||
if (!repeatTimer.running && Config.typingNotifications) {
|
||||
var textExists = text.length > 0
|
||||
currentRoom.sendTypingNotification(textExists)
|
||||
root.currentRoom.sendTypingNotification(textExists)
|
||||
textExists ? repeatTimer.start() : repeatTimer.stop()
|
||||
}
|
||||
currentRoom.chatBoxText = text
|
||||
root.currentRoom.chatBoxText = text
|
||||
}
|
||||
onCursorRectangleChanged: chatBarScrollView.ensureVisible(cursorRectangle)
|
||||
onSelectedTextChanged: {
|
||||
@@ -205,7 +207,7 @@ QQC2.Control {
|
||||
remove(cursorPosition, cursorPosition + 1)
|
||||
}
|
||||
if (textField.text == selectedText || textField.text.length <= 1) {
|
||||
currentRoom.sendTypingNotification(false)
|
||||
root.currentRoom.sendTypingNotification(false)
|
||||
repeatTimer.stop()
|
||||
}
|
||||
if (quickFormatBar.visible) {
|
||||
@@ -239,16 +241,16 @@ QQC2.Control {
|
||||
if (event.key === Qt.Key_V && event.modifiers & Qt.ControlModifier) {
|
||||
root.pasteImage();
|
||||
} else if (event.key === Qt.Key_Up && event.modifiers & Qt.ControlModifier) {
|
||||
currentRoom.replyLastMessage();
|
||||
root.currentRoom.replyLastMessage();
|
||||
} else if (event.key === Qt.Key_Up && textField.text.length === 0) {
|
||||
currentRoom.editLastMessage();
|
||||
root.currentRoom.editLastMessage();
|
||||
} else if (event.key === Qt.Key_Up && completionMenu.visible) {
|
||||
completionMenu.decrementIndex()
|
||||
} else if (event.key === Qt.Key_Down && completionMenu.visible) {
|
||||
completionMenu.incrementIndex()
|
||||
} else if (event.key === Qt.Key_Backspace) {
|
||||
if (textField.text == selectedText || textField.text.length <= 1) {
|
||||
currentRoom.sendTypingNotification(false)
|
||||
root.currentRoom.sendTypingNotification(false)
|
||||
repeatTimer.stop()
|
||||
}
|
||||
if (quickFormatBar.visible && selectedText.length > 0) {
|
||||
@@ -280,19 +282,19 @@ QQC2.Control {
|
||||
Component {
|
||||
id: replyPane
|
||||
ReplyPane {
|
||||
userName: currentRoom.chatBoxReplyUser.displayName
|
||||
userColor: currentRoom.chatBoxReplyUser.color
|
||||
userAvatar: currentRoom.chatBoxReplyUser.avatarSource
|
||||
text: currentRoom.chatBoxReplyMessage
|
||||
userName: root.currentRoom.chatBoxReplyUser.displayName
|
||||
userColor: root.currentRoom.chatBoxReplyUser.color
|
||||
userAvatar: root.currentRoom.chatBoxReplyUser.avatarSource
|
||||
text: root.currentRoom.chatBoxReplyMessage
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: attachmentPane
|
||||
AttachmentPane {
|
||||
attachmentPath: currentRoom.chatBoxAttachmentPath
|
||||
attachmentPath: root.currentRoom.chatBoxAttachmentPath
|
||||
|
||||
onAttachmentCancelled: {
|
||||
currentRoom.chatBoxAttachmentPath = "";
|
||||
root.currentRoom.chatBoxAttachmentPath = "";
|
||||
root.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
@@ -344,8 +346,8 @@ QQC2.Control {
|
||||
text: i18nc("@action:button", "Cancel reply")
|
||||
icon.name: "dialog-close"
|
||||
onTriggered: {
|
||||
currentRoom.chatBoxReplyId = "";
|
||||
currentRoom.chatBoxAttachmentPath = "";
|
||||
root.currentRoom.chatBoxReplyId = "";
|
||||
root.currentRoom.chatBoxAttachmentPath = "";
|
||||
root.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
@@ -386,7 +388,7 @@ QQC2.Control {
|
||||
|
||||
PieProgressBar {
|
||||
visible: modelData.isBusy
|
||||
progress: currentRoom.fileUploadingProgress
|
||||
progress: root.currentRoom.fileUploadingProgress
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,6 +403,8 @@ QQC2.Control {
|
||||
includeCustom: true
|
||||
closeOnChosen: false
|
||||
|
||||
currentRoom: root.currentRoom
|
||||
|
||||
onChosen: insertText(emoji)
|
||||
onClosed: if (emojiButton.checked) emojiButton.checked = false
|
||||
}
|
||||
@@ -466,15 +470,15 @@ QQC2.Control {
|
||||
if (localPath.length === 0) {
|
||||
return;
|
||||
}
|
||||
currentRoom.chatBoxAttachmentPath = localPath
|
||||
root.currentRoom.chatBoxAttachmentPath = localPath
|
||||
}
|
||||
|
||||
function postMessage() {
|
||||
actionsHandler.handleNewMessage();
|
||||
repeatTimer.stop()
|
||||
currentRoom.markAllMessagesAsRead();
|
||||
root.currentRoom.markAllMessagesAsRead();
|
||||
textField.clear();
|
||||
currentRoom.chatBoxReplyId = "";
|
||||
root.currentRoom.chatBoxReplyId = "";
|
||||
messageSent()
|
||||
}
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@ import org.kde.neochat 1.0
|
||||
* @sa ChatBar
|
||||
*/
|
||||
ColumnLayout {
|
||||
id: chatBox
|
||||
id: root
|
||||
|
||||
/**
|
||||
* @brief The current room that user is viewing.
|
||||
*/
|
||||
property NeoChatRoom currentRoom
|
||||
required property NeoChatRoom currentRoom
|
||||
|
||||
/**
|
||||
* @brief A message has been sent from the chat bar.
|
||||
@@ -56,15 +56,6 @@ ColumnLayout {
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||
Kirigami.Theme.inherit: false
|
||||
|
||||
Kirigami.InlineMessage {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 1 // So we can see the border
|
||||
Layout.rightMargin: 1 // So we can see the border
|
||||
|
||||
text: i18n("NeoChat is offline. Please check your network connection.")
|
||||
visible: !Controller.isOnline
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
@@ -72,7 +63,7 @@ ColumnLayout {
|
||||
ChatBar {
|
||||
id: chatBar
|
||||
|
||||
visible: currentRoom.canSendEvent("m.room.message")
|
||||
visible: root.currentRoom.canSendEvent("m.room.message")
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: Math.max(Kirigami.Units.gridUnit * 2, implicitHeight + Kirigami.Units.largeSpacing)
|
||||
@@ -87,7 +78,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
onMessageSent: {
|
||||
chatBox.messageSent();
|
||||
root.messageSent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import QtQuick.Controls 2.15 as QQC2
|
||||
import Qt.labs.qmlmodels 1.0
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
|
||||
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
@@ -43,6 +45,7 @@ QQC2.Popup {
|
||||
rightPadding: 0
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
|
||||
implicitHeight: Math.min(completions.contentHeight, Kirigami.Units.gridUnit * 10)
|
||||
|
||||
contentItem: ListView {
|
||||
@@ -53,23 +56,35 @@ QQC2.Popup {
|
||||
currentIndex: 0
|
||||
keyNavigationWraps: true
|
||||
highlightMoveDuration: 100
|
||||
delegate: Kirigami.BasicListItem {
|
||||
text: model.text
|
||||
subtitle: model.subtitle ?? ""
|
||||
labelItem.textFormat: Text.PlainText
|
||||
subtitleItem.textFormat: Text.PlainText
|
||||
leading: RowLayout {
|
||||
Kirigami.Avatar {
|
||||
visible: model.icon !== "invalid"
|
||||
Layout.preferredWidth: height
|
||||
Layout.fillHeight: true
|
||||
source: model.icon === "invalid" ? "" : ("image://mxc/" + model.icon)
|
||||
name: model.text
|
||||
delegate: Delegates.RoundedItemDelegate {
|
||||
id: completionDelegate
|
||||
|
||||
required property int index
|
||||
required property string displayName
|
||||
required property string subtitle
|
||||
required property string iconName
|
||||
|
||||
text: displayName
|
||||
|
||||
contentItem: RowLayout {
|
||||
KirigamiComponents.Avatar {
|
||||
visible: completionDelegate.iconName !== "invalid"
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
|
||||
source: completionDelegate.iconName === "invalid" ? "" : ("image://" + completionDelegate.iconName)
|
||||
name: completionDelegate.text
|
||||
}
|
||||
Delegates.SubtitleContentItem {
|
||||
itemDelegate: completionDelegate
|
||||
labelItem.textFormat: Text.PlainText
|
||||
subtitle: completionDelegate.subtitle ?? ""
|
||||
subtitleItem.textFormat: Text.PlainText
|
||||
}
|
||||
}
|
||||
onClicked: completionMenu.chatDocumentHandler.complete(model.index)
|
||||
onClicked: completionMenu.chatDocumentHandler.complete(completionDelegate.index)
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
|
||||
import org.kde.kirigami 2.14 as Kirigami
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
@@ -40,7 +41,7 @@ GridLayout {
|
||||
implicitWidth: Kirigami.Units.smallSpacing
|
||||
color: userColor
|
||||
}
|
||||
Kirigami.Avatar {
|
||||
KirigamiComponents.Avatar {
|
||||
id: replyAvatar
|
||||
|
||||
implicitWidth: Kirigami.Units.iconSizes.small
|
||||
|
||||
@@ -10,8 +10,14 @@ import org.kde.neochat 1.0
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
/**
|
||||
* @brief The current room that user is viewing.
|
||||
*/
|
||||
property NeoChatRoom currentRoom
|
||||
|
||||
property bool includeCustom: false
|
||||
property bool showQuickReaction: false
|
||||
property NeoChatRoom currentRoom
|
||||
|
||||
readonly property var currentEmojiModel: {
|
||||
if (includeCustom) {
|
||||
@@ -151,7 +157,7 @@ ColumnLayout {
|
||||
|
||||
ImagePacksModel {
|
||||
id: stickerPackModel
|
||||
room: currentRoom
|
||||
room: root.currentRoom
|
||||
showStickers: true
|
||||
showEmoticons: false
|
||||
}
|
||||
@@ -160,7 +166,7 @@ ColumnLayout {
|
||||
id: stickerModel
|
||||
model: stickerPackModel
|
||||
packIndex: 0
|
||||
room: currentRoom
|
||||
room: root.currentRoom
|
||||
}
|
||||
|
||||
EmoticonFilterModel {
|
||||
|
||||
@@ -46,6 +46,7 @@ ApplicationWindow {
|
||||
asset: root.asset
|
||||
author: root.author
|
||||
isLive: true
|
||||
heading: NaN
|
||||
visible: !isNaN(root.latitude) && !isNaN(root.longitude)
|
||||
}
|
||||
MapItemView {
|
||||
|
||||
@@ -6,6 +6,7 @@ import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
/**
|
||||
* @brief A component that provides a set of actions when a message is hovered in the timeline.
|
||||
@@ -16,6 +17,11 @@ import org.kde.kirigami 2.15 as Kirigami
|
||||
QQC2.Control {
|
||||
id: root
|
||||
|
||||
/**
|
||||
* @brief The current room that user is viewing.
|
||||
*/
|
||||
required property NeoChatRoom currentRoom
|
||||
|
||||
/**
|
||||
* @brief Whether the actions should be shown.
|
||||
*/
|
||||
@@ -108,6 +114,7 @@ QQC2.Control {
|
||||
|
||||
EmojiDialog {
|
||||
id: emojiDialog
|
||||
currentRoom: root.currentRoom
|
||||
showQuickReaction: true
|
||||
onChosen: (emoji) => root.reactClicked(emoji)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import QtLocation 5.15
|
||||
import QtPositioning 5.15
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
@@ -23,11 +24,14 @@ MapQuickItem {
|
||||
|
||||
required property bool isLive
|
||||
|
||||
required property real heading
|
||||
|
||||
anchorPoint.x: sourceItem.width / 2
|
||||
anchorPoint.y: sourceItem.height
|
||||
coordinate: QtPositioning.coordinate(root.latitude, root.longitude)
|
||||
autoFadeIn: false
|
||||
sourceItem: Kirigami.Icon {
|
||||
id: mainIcon
|
||||
width: height
|
||||
height: Kirigami.Units.iconSizes.huge
|
||||
source: "gps"
|
||||
@@ -44,7 +48,7 @@ MapQuickItem {
|
||||
isMask: true
|
||||
color: parent.color
|
||||
}
|
||||
Kirigami.Avatar {
|
||||
KirigamiComponents.Avatar {
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: -parent.height / 8
|
||||
visible: root.asset === "m.self"
|
||||
@@ -54,5 +58,19 @@ MapQuickItem {
|
||||
source: root.author.avatarSource
|
||||
color: root.author.color
|
||||
}
|
||||
|
||||
Kirigami.Icon {
|
||||
id: headingIcon
|
||||
source: "go-up-symbolic"
|
||||
color: parent.color
|
||||
visible: !isNaN(root.heading) && root.isLive
|
||||
anchors.bottom: mainIcon.top
|
||||
anchors.horizontalCenter: mainIcon.horizontalCenter
|
||||
transform: Rotation {
|
||||
origin.x: headingIcon.width/2
|
||||
origin.y: headingIcon.height + mainIcon.height/2
|
||||
angle: root.heading
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ Kirigami.Page {
|
||||
}
|
||||
delegate: LocationMapItem {
|
||||
isLive: true
|
||||
heading: NaN
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ LoginStep {
|
||||
id: matrixIdField
|
||||
Kirigami.FormData.label: i18n("Matrix ID:")
|
||||
placeholderText: "@user:matrix.org"
|
||||
Accessible.name: i18n("Matrix ID")
|
||||
onTextChanged: {
|
||||
LoginHelper.matrixId = text
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ LoginStep {
|
||||
id: passwordField
|
||||
onTextChanged: LoginHelper.password = text
|
||||
enabled: !LoginHelper.isLoggingIn
|
||||
Accessible.name: i18n("Password")
|
||||
|
||||
Component.onCompleted: {
|
||||
passwordField.forceActiveFocus()
|
||||
|
||||
@@ -56,7 +56,7 @@ Components.AlbumMaximizeComponent {
|
||||
}
|
||||
|
||||
leading: RowLayout {
|
||||
Kirigami.Avatar {
|
||||
Components.Avatar {
|
||||
id: userAvatar
|
||||
implicitWidth: Kirigami.Units.iconSizes.medium
|
||||
implicitHeight: Kirigami.Units.iconSizes.medium
|
||||
|
||||
@@ -6,9 +6,11 @@ import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.kirigamiaddons.delegates 1.0 as Delegates
|
||||
import org.kde.kitemmodels 1.0
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
import './RoomList' as RoomList
|
||||
|
||||
QQC2.Dialog {
|
||||
id: root
|
||||
@@ -86,48 +88,23 @@ QQC2.Dialog {
|
||||
connection: Controller.activeConnection
|
||||
}
|
||||
}
|
||||
delegate: Kirigami.BasicListItem {
|
||||
id: roomListItem
|
||||
|
||||
required property NeoChatRoom currentRoom
|
||||
required property string displayName
|
||||
required property int index
|
||||
required property int notificationCount
|
||||
required property string subtitleText
|
||||
required property string avatar
|
||||
delegate: RoomList.RoomDelegate {
|
||||
filterText: searchField.text
|
||||
|
||||
topPadding: Kirigami.Units.largeSpacing
|
||||
bottomPadding: Kirigami.Units.largeSpacing
|
||||
highlighted: roomList.currentIndex === roomListItem.index
|
||||
focus: true
|
||||
icon: undefined
|
||||
onClicked: {
|
||||
RoomManager.enterRoom(roomListItem.currentRoom);
|
||||
RoomManager.enterRoom(currentRoom);
|
||||
root.close()
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
RoomManager.enterRoom(roomListItem.currentRoom);
|
||||
RoomManager.enterRoom(currentRoom);
|
||||
root.close();
|
||||
}
|
||||
Keys.onReturnPressed: {
|
||||
RoomManager.enterRoom(roomListItem.currentRoom);
|
||||
root.close();
|
||||
}
|
||||
@BASICLISTITEM_BOLD@: roomListItem.notificationCount > 0
|
||||
label: roomListItem.displayName ?? ""
|
||||
labelItem.textFormat: Text.PlainText
|
||||
subtitle: roomListItem.subtitleText
|
||||
subtitleItem.textFormat: Text.PlainText
|
||||
onPressAndHold: {
|
||||
createRoomListContextMenu()
|
||||
}
|
||||
|
||||
leading: Kirigami.Avatar {
|
||||
source: roomListItem.avatar ? "image://mxc/" + roomListItem.avatar : ""
|
||||
name: roomListItem.displayName
|
||||
implicitWidth: height
|
||||
sourceSize.width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||
sourceSize.height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||
Keys.onReturnPressed: {
|
||||
RoomManager.enterRoom(currentRoom);
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
|
||||
|
||||
Flow {
|
||||
id: root
|
||||
@@ -17,11 +18,11 @@ Flow {
|
||||
spacing: -avatarSize / 2
|
||||
Repeater {
|
||||
id: avatarFlowRepeater
|
||||
delegate: Kirigami.Avatar {
|
||||
topInset: Kirigami.Units.smallSpacing / 2
|
||||
topPadding: Kirigami.Units.smallSpacing / 2
|
||||
implicitWidth: avatarSize
|
||||
implicitHeight: avatarSize + Kirigami.Units.smallSpacing / 2
|
||||
delegate: KirigamiComponents.Avatar {
|
||||
required property var modelData
|
||||
|
||||
implicitWidth: root.avatarSize
|
||||
implicitHeight: root.avatarSize
|
||||
|
||||
name: modelData.displayName
|
||||
source: modelData.avatarSource
|
||||
|
||||
@@ -57,6 +57,7 @@ TimelineContainer {
|
||||
asset: root.asset
|
||||
author: root.author
|
||||
isLive: true
|
||||
heading: NaN
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
|
||||
@@ -50,6 +50,12 @@ TimelineContainer {
|
||||
isReply: root.isReply
|
||||
|
||||
textMessage: root.display
|
||||
|
||||
TapHandler {
|
||||
enabled: !label.hoveredLink
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onLongPressed: root.openContextMenu()
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -50,10 +50,10 @@ Flow {
|
||||
Kirigami.Theme.inherit: false
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||
radius: height / 2
|
||||
shadow.size: Kirigami.Units.smallSpacing
|
||||
shadow.color: !model.hasLocalUser ? Qt.rgba(0.0, 0.0, 0.0, 0.10) : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
|
||||
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
|
||||
border.width: 1
|
||||
shadow {
|
||||
size: Kirigami.Units.smallSpacing
|
||||
color: !model.hasLocalUser ? Qt.rgba(0.0, 0.0, 0.0, 0.10) : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: reactionClicked(model.reaction)
|
||||
|
||||
@@ -7,6 +7,7 @@ import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
@@ -33,9 +34,9 @@ Item {
|
||||
* - displayName - The display name of the reply author.
|
||||
* - display - The name of the reply author.
|
||||
* - color - The color for the reply author.
|
||||
* - object - The NeoChatUser object for the reply author.
|
||||
* - object - The Quotient::User object for the reply author.
|
||||
*
|
||||
* @sa NeoChatUser
|
||||
* @sa Quotient::User
|
||||
*/
|
||||
required property var author
|
||||
|
||||
@@ -93,7 +94,7 @@ Item {
|
||||
implicitWidth: Kirigami.Units.smallSpacing
|
||||
color: root.author.color
|
||||
}
|
||||
Kirigami.Avatar {
|
||||
KirigamiComponents.Avatar {
|
||||
id: replyAvatar
|
||||
|
||||
implicitWidth: Kirigami.Units.iconSizes.small
|
||||
|
||||
@@ -6,6 +6,7 @@ import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
@@ -21,14 +22,23 @@ RowLayout {
|
||||
|
||||
implicitHeight: Math.max(label.contentHeight, stateAvatar.implicitHeight)
|
||||
|
||||
Kirigami.Avatar {
|
||||
KirigamiComponents.Avatar {
|
||||
id: stateAvatar
|
||||
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
|
||||
name: root.name
|
||||
color: root.color
|
||||
|
||||
Rectangle {
|
||||
radius: height
|
||||
height: 4
|
||||
width: 4
|
||||
color: root.color
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user