Compare commits
1 Commits
release/23
...
work/tobia
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6eb91a80dd |
@@ -1,5 +0,0 @@
|
||||
; SPDX-FileCopyrightText: None
|
||||
; SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
[BlueprintSettings]
|
||||
kde/applications/neochat.packageAppx = True
|
||||
@@ -26,7 +26,7 @@
|
||||
"name": "kirigamiaddons",
|
||||
"config-opts": [ "-DBUILD_TESTING=OFF" ],
|
||||
"buildsystem": "cmake-ninja",
|
||||
"sources": [ { "type": "git", "url": "https://invent.kde.org/libraries/kirigami-addons.git", "branch": "kf5" } ]
|
||||
"sources": [ { "type": "git", "url": "https://invent.kde.org/libraries/kirigami-addons.git" } ]
|
||||
},
|
||||
{
|
||||
"name": "kquickimageeditor",
|
||||
@@ -103,6 +103,7 @@
|
||||
{
|
||||
"name": "libQuotient",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"config-opts": [ "-DBUILD_TESTING=OFF" ],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
@@ -112,8 +113,7 @@
|
||||
}
|
||||
],
|
||||
"config-opts": [
|
||||
"-DQuotient_ENABLE_E2EE=ON",
|
||||
"-DBUILD_TESTING=OFF"
|
||||
"-DQuotient_ENABLE_E2EE=ON"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
build*
|
||||
build
|
||||
.clang-format
|
||||
.DS_Store
|
||||
.kdev4/
|
||||
@@ -11,4 +11,3 @@ kate.project.ctags.*
|
||||
.flatpak-builder/
|
||||
.idea/
|
||||
cmake-build-*
|
||||
src/res.generated.qrc
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
include:
|
||||
- project: sysadmin/ci-utilities
|
||||
file:
|
||||
- /gitlab-templates/reuse-lint.yml
|
||||
- /gitlab-templates/android.yml
|
||||
# - /gitlab-templates/linux.yml
|
||||
- /gitlab-templates/linux-qt6.yml
|
||||
- /gitlab-templates/windows.yml
|
||||
# - /gitlab-templates/freebsd.yml
|
||||
- /gitlab-templates/flatpak.yml
|
||||
- /gitlab-templates/craft-android-apks.yml
|
||||
- /gitlab-templates/craft-windows-x86-64.yml
|
||||
- /gitlab-templates/craft-windows-appx-qt5.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/reuse-lint.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
|
||||
# - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/flatpak.yml
|
||||
|
||||
@@ -59,4 +59,4 @@ Dependencies:
|
||||
'frameworks/kdbusaddons': '@latest-kf6'
|
||||
|
||||
Options:
|
||||
require-passing-tests-on: [ 'Linux/Qt5', 'FreeBSD' ]
|
||||
require-passing-tests-on: [ 'Linux/Qt5', 'FreeBSD', 'Windows/Qt5' ]
|
||||
|
||||
@@ -8,8 +8,8 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "23")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "08")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "5")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "07")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
@@ -17,7 +17,7 @@ project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
set(KF_MIN_VERSION "5.105.0")
|
||||
set(QT_MIN_VERSION "5.15.2")
|
||||
if (ANDROID)
|
||||
set(QT_MIN_VERSION "5.15.10")
|
||||
set(QT_MIN_VERSION "5.15.8")
|
||||
endif()
|
||||
|
||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
@@ -48,30 +48,6 @@ if(NEOCHAT_FLATPAK)
|
||||
include(cmake/Flatpak.cmake)
|
||||
endif()
|
||||
|
||||
if(QT_MAJOR_VERSION STREQUAL "6")
|
||||
set(BASICLISTITEM_BOLD "font.bold")
|
||||
set(OVERLAYSHEET_OPEN "onOpened")
|
||||
set(QTQUICK_MODULE_QML_VERSION "")
|
||||
set(QTLOCATION_MODULE_QML_VERSION "")
|
||||
set(QTMULTIMEDIA_MODULE_QML_VERSION "")
|
||||
set(QTMULTIMEDIA_AUDIO "MediaPlayer")
|
||||
# in Audio qt6 we don't have it but we disable it in qt5 => it seems ok
|
||||
set(QTMULTIMEDIA_AUDIO_AUTOLOAD "")
|
||||
# In Video qml qt6 we don't have it.
|
||||
set(QTMULTIMEDIA_VIDEO_FLUSHMODE "")
|
||||
else()
|
||||
set(BASICLISTITEM_BOLD "bold")
|
||||
set(OVERLAYSHEET_OPEN "onSheetOpenChanged")
|
||||
set(QTQUICK_MODULE_QML_VERSION "2.15")
|
||||
set(QTLOCATION_MODULE_QML_VERSION "5.15")
|
||||
set(QTMULTIMEDIA_MODULE_QML_VERSION "5.15")
|
||||
set(QTMULTIMEDIA_AUDIO "Audio")
|
||||
set(QTMULTIMEDIA_AUDIO_AUTOLOAD "autoLoad: false")
|
||||
set(QTMULTIMEDIA_VIDEO_FLUSHMODE "flushMode: VideoOutput.FirstFrame")
|
||||
endif()
|
||||
|
||||
set(QUOTIENT_FORCE_NAMESPACED_INCLUDES TRUE)
|
||||
|
||||
ecm_setup_version(${PROJECT_VERSION}
|
||||
VARIABLE_PREFIX NEOCHAT
|
||||
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
|
||||
@@ -122,7 +98,7 @@ if(QT_MAJOR_VERSION STREQUAL "6" AND NOT ANDROID AND NOT WIN32)
|
||||
set(QUOTIENT_SUFFIX "Qt6")
|
||||
endif()
|
||||
|
||||
find_package(Quotient${QUOTIENT_SUFFIX} 0.7)
|
||||
find_package(Quotient${QUOTIENT_SUFFIX} 0.6)
|
||||
set_package_properties(Quotient${QUOTIENT_SUFFIX} PROPERTIES
|
||||
TYPE REQUIRED
|
||||
DESCRIPTION "Qt wrapper around Matrix API"
|
||||
@@ -141,7 +117,6 @@ set_package_properties(cmark PROPERTIES
|
||||
ecm_find_qmlmodule(org.kde.kquickimageeditor 1.0)
|
||||
ecm_find_qmlmodule(org.kde.kitemmodels 1.0)
|
||||
ecm_find_qmlmodule(org.kde.quickcharts 1.0)
|
||||
ecm_find_qmlmodule(QtLocation ${QTLOCATION_MODULE_QML_VERSION})
|
||||
|
||||
find_package(KQuickImageEditor COMPONENTS)
|
||||
set_package_properties(KQuickImageEditor PROPERTIES
|
||||
@@ -203,9 +178,3 @@ file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h *.qml)
|
||||
# Fixes the test by excluding this directory
|
||||
list(FILTER ALL_SOURCE_FILES EXCLUDE REGEX [[_(install|build)/.*]])
|
||||
ecm_check_outbound_license(LICENSES GPL-3.0-only FILES ${ALL_SOURCE_FILES})
|
||||
|
||||
ecm_qt_install_logging_categories(
|
||||
EXPORT NEOCHAT
|
||||
FILE neochat.categories
|
||||
DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
|
||||
)
|
||||
|
||||
@@ -47,7 +47,6 @@ android {
|
||||
compileSdkVersion androidCompileSdkVersion.toInteger()
|
||||
|
||||
buildToolsVersion androidBuildToolsVersion
|
||||
ndkVersion androidNdkVersion
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
|
||||
@@ -14,9 +14,3 @@ ecm_add_test(
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME texthandlertest
|
||||
)
|
||||
|
||||
ecm_add_test(
|
||||
delegatesizehelpertest.cpp
|
||||
LINK_LIBRARIES neochat Qt::Test
|
||||
TEST_NAME delegatesizehelpertest
|
||||
)
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include <QObject>
|
||||
#include <QTest>
|
||||
|
||||
#include "delegatesizehelper.h"
|
||||
|
||||
class DelegateSizeHelperTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void risingPercentage_data();
|
||||
void risingPercentage();
|
||||
|
||||
void fallingPercentage_data();
|
||||
void fallingPercentage();
|
||||
|
||||
void equalPercentage_data();
|
||||
void equalPercentage();
|
||||
|
||||
void equalBreakpoint_data();
|
||||
void equalBreakpoint();
|
||||
};
|
||||
|
||||
void DelegateSizeHelperTest::risingPercentage_data()
|
||||
{
|
||||
QTest::addColumn<qreal>("parentWidth");
|
||||
QTest::addColumn<int>("currentPercentageWidth");
|
||||
QTest::addColumn<qreal>("currentWidth");
|
||||
|
||||
QTest::newRow("zero") << qreal(0) << int(0) << qreal(0);
|
||||
QTest::newRow("one hundred") << qreal(100) << int(0) << qreal(0);
|
||||
QTest::newRow("one fifty") << qreal(150) << int(50) << qreal(75);
|
||||
QTest::newRow("two hundred") << qreal(200) << int(100) << qreal(200);
|
||||
QTest::newRow("three hundred") << qreal(300) << int(100) << qreal(300);
|
||||
}
|
||||
|
||||
void DelegateSizeHelperTest::risingPercentage()
|
||||
{
|
||||
QFETCH(qreal, parentWidth);
|
||||
QFETCH(int, currentPercentageWidth);
|
||||
QFETCH(qreal, currentWidth);
|
||||
|
||||
DelegateSizeHelper delegateSizeHelper;
|
||||
delegateSizeHelper.setStartBreakpoint(100);
|
||||
delegateSizeHelper.setEndBreakpoint(200);
|
||||
delegateSizeHelper.setStartPercentWidth(0);
|
||||
delegateSizeHelper.setEndPercentWidth(100);
|
||||
|
||||
delegateSizeHelper.setParentWidth(parentWidth);
|
||||
|
||||
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||
}
|
||||
|
||||
void DelegateSizeHelperTest::fallingPercentage_data()
|
||||
{
|
||||
QTest::addColumn<qreal>("parentWidth");
|
||||
QTest::addColumn<int>("currentPercentageWidth");
|
||||
QTest::addColumn<qreal>("currentWidth");
|
||||
|
||||
QTest::newRow("zero") << qreal(0) << int(100) << qreal(0);
|
||||
QTest::newRow("one hundred") << qreal(100) << int(100) << qreal(100);
|
||||
QTest::newRow("one fifty") << qreal(150) << int(50) << qreal(75);
|
||||
QTest::newRow("two hundred") << qreal(200) << int(0) << qreal(0);
|
||||
QTest::newRow("three hundred") << qreal(300) << int(0) << qreal(0);
|
||||
}
|
||||
|
||||
void DelegateSizeHelperTest::fallingPercentage()
|
||||
{
|
||||
QFETCH(qreal, parentWidth);
|
||||
QFETCH(int, currentPercentageWidth);
|
||||
QFETCH(qreal, currentWidth);
|
||||
|
||||
DelegateSizeHelper delegateSizeHelper;
|
||||
delegateSizeHelper.setStartBreakpoint(100);
|
||||
delegateSizeHelper.setEndBreakpoint(200);
|
||||
delegateSizeHelper.setStartPercentWidth(100);
|
||||
delegateSizeHelper.setEndPercentWidth(0);
|
||||
|
||||
delegateSizeHelper.setParentWidth(parentWidth);
|
||||
|
||||
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||
}
|
||||
|
||||
void DelegateSizeHelperTest::equalPercentage_data()
|
||||
{
|
||||
QTest::addColumn<qreal>("parentWidth");
|
||||
QTest::addColumn<int>("currentPercentageWidth");
|
||||
QTest::addColumn<qreal>("currentWidth");
|
||||
|
||||
QTest::newRow("zero") << qreal(0) << int(50) << qreal(0);
|
||||
QTest::newRow("one hundred") << qreal(100) << int(50) << qreal(50);
|
||||
QTest::newRow("one fifty") << qreal(150) << int(50) << qreal(75);
|
||||
QTest::newRow("two hundred") << qreal(200) << int(50) << qreal(100);
|
||||
QTest::newRow("three hundred") << qreal(300) << int(50) << qreal(150);
|
||||
}
|
||||
|
||||
void DelegateSizeHelperTest::equalPercentage()
|
||||
{
|
||||
QFETCH(qreal, parentWidth);
|
||||
QFETCH(int, currentPercentageWidth);
|
||||
QFETCH(qreal, currentWidth);
|
||||
|
||||
DelegateSizeHelper delegateSizeHelper;
|
||||
delegateSizeHelper.setStartBreakpoint(100);
|
||||
delegateSizeHelper.setEndBreakpoint(200);
|
||||
delegateSizeHelper.setStartPercentWidth(50);
|
||||
delegateSizeHelper.setEndPercentWidth(50);
|
||||
|
||||
delegateSizeHelper.setParentWidth(parentWidth);
|
||||
|
||||
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||
}
|
||||
|
||||
void DelegateSizeHelperTest::equalBreakpoint_data()
|
||||
{
|
||||
QTest::addColumn<int>("startPercentageWidth");
|
||||
QTest::addColumn<int>("endPercentageWidth");
|
||||
QTest::addColumn<int>("currentPercentageWidth");
|
||||
QTest::addColumn<qreal>("currentWidth");
|
||||
|
||||
QTest::newRow("start higher") << int(100) << int(0) << int(-1) << qreal(0);
|
||||
QTest::newRow("equal") << int(50) << int(50) << int(50) << qreal(500);
|
||||
QTest::newRow("end higher") << int(0) << int(100) << int(-1) << qreal(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* We expect a default return except in the case where the the two percentages are
|
||||
* equal as that case can be calculated without dividing by zero.
|
||||
*/
|
||||
void DelegateSizeHelperTest::equalBreakpoint()
|
||||
{
|
||||
QFETCH(int, startPercentageWidth);
|
||||
QFETCH(int, endPercentageWidth);
|
||||
QFETCH(int, currentPercentageWidth);
|
||||
QFETCH(qreal, currentWidth);
|
||||
|
||||
DelegateSizeHelper delegateSizeHelper;
|
||||
delegateSizeHelper.setStartBreakpoint(100);
|
||||
delegateSizeHelper.setEndBreakpoint(100);
|
||||
delegateSizeHelper.setStartPercentWidth(startPercentageWidth);
|
||||
delegateSizeHelper.setEndPercentWidth(endPercentageWidth);
|
||||
|
||||
delegateSizeHelper.setParentWidth(1000);
|
||||
|
||||
QCOMPARE(delegateSizeHelper.currentPercentageWidth(), currentPercentageWidth);
|
||||
QCOMPARE(delegateSizeHelper.currentWidth(), currentWidth);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(DelegateSizeHelperTest)
|
||||
#include "delegatesizehelpertest.moc"
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include "neochatroom.h"
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/quotient_common.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
#include <connection.h>
|
||||
#include <quotient_common.h>
|
||||
#include <syncdata.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
#include "texthandler.h"
|
||||
|
||||
#include <Quotient/quotient_common.h>
|
||||
#include <Quotient/syncdata.h>
|
||||
#include <qnamespace.h>
|
||||
#include <quotient_common.h>
|
||||
#include <syncdata.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
@@ -71,6 +71,7 @@ private Q_SLOTS:
|
||||
void linkPreviewsReject();
|
||||
};
|
||||
|
||||
#ifdef QUOTIENT_07
|
||||
void TextHandlerTest::initTestCase()
|
||||
{
|
||||
connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
|
||||
@@ -203,6 +204,7 @@ void TextHandlerTest::initTestCase()
|
||||
SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, json.object());
|
||||
room->update(std::move(roomData));
|
||||
}
|
||||
#endif
|
||||
|
||||
void TextHandlerTest::allowedAttributes()
|
||||
{
|
||||
@@ -477,6 +479,7 @@ void TextHandlerTest::receiveRichtextIn()
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString);
|
||||
}
|
||||
|
||||
#ifdef QUOTIENT_07
|
||||
void TextHandlerTest::receiveRichMxcUrl()
|
||||
{
|
||||
const QString testInputString = QStringLiteral(
|
||||
@@ -494,6 +497,7 @@ void TextHandlerTest::receiveRichMxcUrl()
|
||||
|
||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(0).get()), testOutputString);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* For when your rich input string has a plain text url left in.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 67 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB |
@@ -18,12 +18,10 @@
|
||||
<name xml:lang="de">NeoChat</name>
|
||||
<name xml:lang="el">NeoChat</name>
|
||||
<name xml:lang="en-GB">NeoChat</name>
|
||||
<name xml:lang="eo">NeoChat</name>
|
||||
<name xml:lang="es">NeoChat</name>
|
||||
<name xml:lang="eu">NeoChat</name>
|
||||
<name xml:lang="fi">NeoChat</name>
|
||||
<name xml:lang="fr">NeoChat</name>
|
||||
<name xml:lang="gl">NeoChat</name>
|
||||
<name xml:lang="hu">NeoChat</name>
|
||||
<name xml:lang="ia">Neochat</name>
|
||||
<name xml:lang="id">NeoChat</name>
|
||||
@@ -46,7 +44,6 @@
|
||||
<name xml:lang="uk">NeoChat</name>
|
||||
<name xml:lang="x-test">xxNeoChatxx</name>
|
||||
<name xml:lang="zh-CN">NeoChat</name>
|
||||
<name xml:lang="zh-TW">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>
|
||||
@@ -56,12 +53,10 @@
|
||||
<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>
|
||||
@@ -70,7 +65,7 @@
|
||||
<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="nn">Ein klient for Matrix, den desentraliserte lynmeldingsprotokollen</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>
|
||||
@@ -79,175 +74,89 @@
|
||||
<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 xml:lang="zh-TW">去中心化通訊協定 Matrix 的用戶端</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>
|
||||
<p xml:lang="ar">نيوتشات هو عميل ماتركس Matrix، (ميفاق الاتصال اللامركزي للمراسلة الفورية). يتيح لك نيوتشات إرسال رسائل نصية ومقاطع فيديو وملفات صوتية إلى عائلتك وزملائك وأصدقائك. يستخدم أطر عمل كيدي وأبرزها Kirigami لتوفير تجربة متقاربة عبر منصات متعددة.</p>
|
||||
<p xml:lang="ca">El NeoChat és un client de Matrix, el protocol descentralitzat de comunicacions de missatgeria instantània. Permet enviar missatges de text, fitxers de vídeo i d'àudio a la família, col·legues i amics. Fa servir els Frameworks de KDE i, sobretot, el Kirigami per a proporcionar una experiència convergent a través de diverses plataformes.</p>
|
||||
<p xml:lang="ca-valencia">NeoChat és un client de Matrix, el protocol descentralitzat de comunicacions de missatgeria instantània. Permet enviar missatges de text, fitxers de vídeo i d'àudio a la família, col·legues i amics. Utilitza els Frameworks de KDE i, sobretot, Kirigami per a proporcionar una experiència convergent a través de diverses plataformes.</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 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="ru">NeoChat — клиент для Matrix, децентрализованного коммуникационного протокола для мгновенного обмена сообщениями. С его помощью возможно отправлять текстовые сообщения, видео- и звуковые файлы родственникам, коллегам и друзьям. В программе использованы библиотеки KDE, в частности Kirigami, для обеспечения единообразной работы на различных платформах.</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>
|
||||
<p xml:lang="zh-TW">NeoChat 是去中心化即時通訊協定 Matrix 的一個用戶端。它讓您可以傳送文字訊息、影片、音訊檔案給您的家人、同事或朋友。NeoChat 使用 KDE frameworks,尤其是 Kirigami,來提供跨平台的響應式體驗。</p>
|
||||
<p>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="ar">يهدف نيوتشات إلى أن يكون تطبيقًا كامل الميزات لمواصفات ماتركس. على هذا النحو يتم دعم كل شيء في المواصفات المستقرة الحالية مع الاستثناءات الملحوظة لـ VoIP والخيوط وبعض جوانب التشفير من طرف إلى طرف. هناك عدد قليل من الإغفالات الصغيرة الأخرى بسبب حقيقة أن مواصفات ماتركس تتطور باستمرار ، ولكن يبقى الهدف توفير الدعم النهائي للمواصفات بأكملها.</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 la 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="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="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="ru">Целью создания NeoChat является полноценная реализация программы для спецификации Matrix. Как следствие, реализовано всё в текущей стабильной спецификации (за исключением голосовой интернет-связи, потоков и некоторых аспектов сквозного шифрования). Есть также несколько других незначительных пробелов, обусловленных постоянными изменениями спецификации Matrix. Тем не менее, стоит задача в итоге предоставить полную поддержку спецификации.</p>
|
||||
<p xml:lang="sl">Neochat cilja, da bi bila popolna aplikacija po specifikaciji Matrixa. Kot takšna vsebuje vse v trenutni stabilni specifikaciji z pomembnimi izjemami pri VoIP, nitih in nekaterih vidikov šifriranja od konca do konca. Obstaja nekaj drugih manjših opustitev zaradi dejstva, da se specifikacija Matrix nenehno razvija, vendar cilj ostaja zagotoviti morebitno podporo celotni specifikaciji.</p>
|
||||
<p xml:lang="sv">NeoChat har som mål att vara ett fullständigt program enligt Matrix-specifikationen. Som sådant stöds allt i den nuvarande stabila specifikationen, med de nämnvärda undantagen VoIP, trådar och några aspekter av kryptering hela vägen. Det finns några ytterligare utelämnanden på grund av att Matrix-specifikationen hela tiden utvecklas, men målet förblir att till slut erbjuda stöd för hela specifikationen.</p>
|
||||
<p xml:lang="tr">NeoChat, Matrix belirtimi için tam özellikli bir uygulama olmayı hedefler. Bu nedenle; VoIP, ileti zincirleri ve Uçtan Uca Şifreleme'nin bazı yönleri gibi dikkate değer istisnalar dışında var olan kararlı belirtimdeki her şey desteklenir. Matrix belirtiminin sürekli gelişmesi nedeniyle birkaç küçük eksiklik daha var; ancak amaç tüm belirtim için nihai destek sağlamak olmayı sürdürüyor.</p>
|
||||
<p xml:lang="tr">NeoChat, Matrix spesifikasyonu için tam özellikli bir uygulama olmayı hedefler. Bu nedenle; VoIP, ileti zincirleri ve Uçtan Uca Şifrelemenin 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>
|
||||
<p xml:lang="zh-TW">NeoChat 以完整支援 Matrix 標準為目標,因此目前穩定版標準除了 VoIP、對話串與端對端加密的某些部分以外的所有部分都有支援。其他部分還有一些較小的不支援的部分,這是因為 Matrix 標準隨時都在改進,但目標仍然時最終提供整個標準的完整支援。</p>
|
||||
<p>Due to the nature of the Matrix specification development NeoChat also supports numerous unstable features. Currently these are:</p>
|
||||
<p xml:lang="ar">نظرًا لطبيعة تطوير مواصفات ماتركس، يدعم نيوتشات أيضًا العديد من الميزات غير المستقرة وهي:</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="ru">В силу природы разработки спецификации Matrix в NeoChat тоже предусмотрена поддержка многочисленных нестабильных возможностей. В текущей версии это следующие возможности:</p>
|
||||
<p xml:lang="sl">Zaradi narave razvoja specifikacije Matrixa NeoChat podpira tudi številne nestabilne zmožnosti. Trenutno so to:</p>
|
||||
<p xml:lang="sv">På grund av sättet Matrix-specifikationens utvecklas, stöder NeoChat också ett stor antal instabila funktioner. För närvarande är de:</p>
|
||||
<p xml:lang="ta">மேட்ரிக்ஸு நெறிமுறை வரையறுக்கப்படும் விதத்தின் காரணமாக, பல நிலையற்ற அம்சங்களையும் நியோச்சாட் ஆதரிக்கிறது. தற்போது ஆதரிக்கப்படுபவை:</p>
|
||||
<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="tr">NeoChat, Matrix belirtim 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>
|
||||
<p xml:lang="zh-TW">由於 Matrix 標準的開發流程的緣故,NeoChat 也支援數個非穩定版的功能。目前這些功能是:</p>
|
||||
<ul>
|
||||
<li>Polls - MSC3381</li>
|
||||
<li xml:lang="ar">التصويت - MSC3381</li>
|
||||
<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="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="pl">Ankiety - MSC3381</li>
|
||||
<li xml:lang="pt">Inquéritos - MSC3381</li>
|
||||
<li xml:lang="ru">Голосования — MSC3381</li>
|
||||
<li xml:lang="sl">Polls - MSC3381</li>
|
||||
<li xml:lang="sv">Polls - MSC3381</li>
|
||||
<li xml:lang="ta">வாக்கெடுப்புகள் - MSC3381</li>
|
||||
<li xml:lang="tr">Anketler - MSC3381</li>
|
||||
<li xml:lang="uk">Опитування - MSC3381</li>
|
||||
<li xml:lang="x-test">xxPolls - MSC3381xx</li>
|
||||
<li xml:lang="zh-TW">投票 - MSC3381</li>
|
||||
<li>Sticker Packs - MSC2545</li>
|
||||
<li xml:lang="ar">حزم الملصقات - MSC2545</li>
|
||||
<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="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="pl">Paczki naklejek - MSC2545</li>
|
||||
<li xml:lang="pt">Pacotes de Autocolantes - MSC2545</li>
|
||||
<li xml:lang="ru">Наборы наклеек — MSC2545</li>
|
||||
<li xml:lang="sl">Sticker Packs - MSC2545</li>
|
||||
<li xml:lang="sv">Sticker Packs - MSC2545</li>
|
||||
<li xml:lang="ta">ஒட்டி தொகுப்புகள் - MSC2545</li>
|
||||
<li xml:lang="tr">Yapışkan Paketleri - MSC2545</li>
|
||||
<li xml:lang="uk">Пакунки наліпок - MSC2545</li>
|
||||
<li xml:lang="x-test">xxSticker Packs - MSC2545xx</li>
|
||||
<li xml:lang="zh-TW">貼圖包 - MSC2545</li>
|
||||
<li>Location Events - MSC3488</li>
|
||||
<li xml:lang="ar">موقع الأحداث - MSC3488</li>
|
||||
<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="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="pl">Wydarzenia w miejscach - MSC3488</li>
|
||||
<li xml:lang="pt">Eventos com Localizações - MSC3488</li>
|
||||
<li xml:lang="ru">События местоположения — MSC3488</li>
|
||||
<li xml:lang="sl">Location Events - MSC3488</li>
|
||||
<li xml:lang="sv">Location Events - MSC3488</li>
|
||||
<li xml:lang="ta">இட நிகழ்வுகள் - MSC3488</li>
|
||||
<li xml:lang="tr">Konum Etkinlikleri - MSC3488</li>
|
||||
<li xml:lang="uk">Місцеві зустрічі - MSC3488</li>
|
||||
<li xml:lang="x-test">xxLocation Events - MSC3488xx</li>
|
||||
<li xml:lang="zh-TW">位置事件 - MSC3488</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url type="homepage">https://apps.kde.org/neochat/</url>
|
||||
@@ -264,12 +173,10 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<developer_name xml:lang="de">Die KDE-Gemeinschaft</developer_name>
|
||||
<developer_name xml:lang="el">Η Κοινότητα του KDE</developer_name>
|
||||
<developer_name xml:lang="en-GB">The KDE Community</developer_name>
|
||||
<developer_name xml:lang="eo">La KDE-Komunumo</developer_name>
|
||||
<developer_name xml:lang="es">La comunidad KDE</developer_name>
|
||||
<developer_name xml:lang="eu">KDE komunitatea</developer_name>
|
||||
<developer_name xml:lang="fi">KDE-yhteisö</developer_name>
|
||||
<developer_name xml:lang="fr">La communauté de KDE</developer_name>
|
||||
<developer_name xml:lang="gl">A comunidade KDE</developer_name>
|
||||
<developer_name xml:lang="hu">A KDE Közösség</developer_name>
|
||||
<developer_name xml:lang="ia">Le communitate de KDE</developer_name>
|
||||
<developer_name xml:lang="id">Komunitas KDE</developer_name>
|
||||
@@ -287,22 +194,15 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<developer_name xml:lang="sk">KDE Komunita</developer_name>
|
||||
<developer_name xml:lang="sl">Skupnost KDE</developer_name>
|
||||
<developer_name xml:lang="sv">KDE-gemenskapen</developer_name>
|
||||
<developer_name xml:lang="ta">கே.டீ.யீ. சமூகம்</developer_name>
|
||||
<developer_name xml:lang="tr">KDE Topluluğu</developer_name>
|
||||
<developer_name xml:lang="uk">Спільнота KDE</developer_name>
|
||||
<developer_name xml:lang="x-test">xxThe KDE Communityxx</developer_name>
|
||||
<developer_name xml:lang="zh-CN">KDE 社区</developer_name>
|
||||
<developer_name xml:lang="zh-TW">KDE 社群</developer_name>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0</project_license>
|
||||
<custom>
|
||||
<value key="KDE::matrix">#neochat:kde.org</value>
|
||||
<value key="KDE::windows_store">https://www.microsoft.com/store/apps/9PNXWVNRC29H</value>
|
||||
<value key="KDE::mastodon">https://kde.social/@neochat</value>
|
||||
<value key="KDE::windows_store::StoreLogo9x16">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/storelogo-720x1080.png</value>
|
||||
<value key="KDE::windows_store::StoreLogoSquare">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/storelogo-1080x1080.png</value>
|
||||
<value key="KDE::windows_store::Icon">https://invent.kde.org/network/neochat/-/raw/master/icons/300-apps-neochat.png</value>
|
||||
<value key="KDE::windows_store::PromotionalArt16x9">https://invent.kde.org/network/neochat/-/raw/master/icons/windows/promoimage-1920x1080.png</value>
|
||||
</custom>
|
||||
<launchable type="desktop-id">org.kde.neochat.desktop</launchable>
|
||||
<screenshots>
|
||||
@@ -312,90 +212,13 @@ to provide a convergent experience across multiple platforms.</p>
|
||||
<screenshot type="default">
|
||||
<image>https://cdn.kde.org/screenshots/neochat/application.png</image>
|
||||
</screenshot>
|
||||
<screenshot x-kde-os="windows">
|
||||
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Timeline.png</image>
|
||||
<caption>Main view with room list, chat, and room information</caption>
|
||||
<caption xml:lang="ar">العرض الرئيسة مع قائمة الغرف والدردشات و معلومات الغرفة</caption>
|
||||
<caption xml:lang="ca">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="ca-valencia">Vista principal amb la llista de sales, xats i informació de les sales</caption>
|
||||
<caption xml:lang="eo">Ĉefa vido kun ĉambra listo, babilejo kaj ĉambra informo</caption>
|
||||
<caption xml:lang="es">Vista principal con la lista de salas, chat e información de la sala</caption>
|
||||
<caption xml:lang="eu">Ikuspegi nagusia gela-zerrenda, berriketa, eta gelako informazioarekin</caption>
|
||||
<caption xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</caption>
|
||||
<caption xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</caption>
|
||||
<caption xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</caption>
|
||||
<caption xml:lang="ia">Vista principal con lista de sala, chat e information de sala</caption>
|
||||
<caption xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</caption>
|
||||
<caption xml:lang="ka">მთავარი ხედი სურათების სიით, ჩატით და ოთახის ინფორმაციით</caption>
|
||||
<caption xml:lang="ko">대화방 목록, 채팅, 대화방 정보가 표시된 주 보기</caption>
|
||||
<caption xml:lang="nl">Hoofdweergave met lijst met rooms, chat en roominformatie</caption>
|
||||
<caption xml:lang="nn">Hovudvising med romliste, pratevindauge og rominformasjon</caption>
|
||||
<caption xml:lang="pl">Główny widok z wykazem pokojów, rozmowami i szczegółami pokojów</caption>
|
||||
<caption xml:lang="pt">A área principal com a lista de salas e com informações sobre a conversa e a sala</caption>
|
||||
<caption xml:lang="ru">Главное окно со списком комнат, чатом и информацией о комнате</caption>
|
||||
<caption xml:lang="sl">Glavni pogled s seznamom sob, klepetom in informacijami o sobah</caption>
|
||||
<caption xml:lang="sv">Huvudvy med rumslista, chatt, och rumsinformation</caption>
|
||||
<caption xml:lang="ta">அரங்குப்பட்டியல், உரையாடல், மற்றும் அரங்குவிவரங்களைக் கொண்டுள்ள பிரதான காட்சி</caption>
|
||||
<caption xml:lang="tr">Oda listesini, sohbet penceresini ve oda bilgisini gösteren ana görünüm</caption>
|
||||
<caption xml:lang="uk">Головна панель із списком кімнат, спілкуванням та даними щодо кімнати</caption>
|
||||
<caption xml:lang="x-test">xxMain view with room list, chat, and room informationxx</caption>
|
||||
<caption xml:lang="zh-TW">主頁面,包含聊天室列表、聊天內容,與聊天室資訊</caption>
|
||||
</screenshot>
|
||||
<screenshot x-kde-os="windows">
|
||||
<image>https://cdn.kde.org/screenshots/neochat/NeoChat-Windows-Login.png</image>
|
||||
<caption>Login screen</caption>
|
||||
<caption xml:lang="ar">شاشة الدخول</caption>
|
||||
<caption xml:lang="ca">Pantalla d'inici de sessió</caption>
|
||||
<caption xml:lang="ca-valencia">Pantalla d'inici de sessió</caption>
|
||||
<caption xml:lang="cs">Přihlašovací obrazovka</caption>
|
||||
<caption xml:lang="eo">Ensaluta ekrano</caption>
|
||||
<caption xml:lang="es">Pantalla de inicio de sesión</caption>
|
||||
<caption xml:lang="eu">Saio-hasteko pantaila</caption>
|
||||
<caption xml:lang="fi">Kirjautumisnäkymä</caption>
|
||||
<caption xml:lang="fr">Écran de connexion</caption>
|
||||
<caption xml:lang="gl">Pantalla de identificación.</caption>
|
||||
<caption xml:lang="ia">Schermo de accesso</caption>
|
||||
<caption xml:lang="it">Schermata di accesso</caption>
|
||||
<caption xml:lang="ka">შესვლის ეკრანი</caption>
|
||||
<caption xml:lang="ko">로그인 화면</caption>
|
||||
<caption xml:lang="nl">Aanmeldscherm</caption>
|
||||
<caption xml:lang="nn">Innloggingsbilete</caption>
|
||||
<caption xml:lang="pl">Ekran logowania</caption>
|
||||
<caption xml:lang="pt">Ecrã de autenticação</caption>
|
||||
<caption xml:lang="ru">Окно входа</caption>
|
||||
<caption xml:lang="sl">Prijavni zaslon</caption>
|
||||
<caption xml:lang="sv">Inloggningsfönster</caption>
|
||||
<caption xml:lang="ta">நுழைவுத் திரை</caption>
|
||||
<caption xml:lang="tr">Oturum açma ekranı</caption>
|
||||
<caption xml:lang="uk">Вікно входу</caption>
|
||||
<caption xml:lang="x-test">xxLogin screenxx</caption>
|
||||
<caption xml:lang="zh-TW">登入畫面</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1">
|
||||
<content_attribute id="social-chat">intense</content_attribute>
|
||||
</content_rating>
|
||||
<releases>
|
||||
<release version="23.08.5" date="2024-02-15"/>
|
||||
<release version="23.08.4" date="2023-12-07"/>
|
||||
<release version="23.08.3" date="2023-11-09"/>
|
||||
<release version="23.08.2" date="2023-10-12"/>
|
||||
<release version="23.08.0" date="2023-08-24">
|
||||
<url>https://kde.org/announcements/gear/23.08.0/#neochathttpsappskdeorgneochat</url>
|
||||
<description>
|
||||
<p>Apart from a visual overhaul, NeoChat can now display location events and also a map with the location of all the users currently broadcasting their location using Itineray's Matrix integration. Great for locating where your friends are.</p>
|
||||
</description>
|
||||
</release>
|
||||
<release version="23.04.3" date="2023-07-06"/>
|
||||
<release version="23.04.2" date="2023-06-08"/>
|
||||
<release version="23.04.1" date="2023-05-11"/>
|
||||
<release version="23.04.0" date="2023-04-20">
|
||||
<url>https://kde.org/announcements/gear/23.04.0/#neochathttpsappskdeorgneochat</url>
|
||||
<description>
|
||||
<p>NeoChat improves its design with tweaks that provide a more compact layout and a simpler menu which works better for the collapsed room list.</p>
|
||||
<p>We have also improved the video controls, added a new command /knock <room-id> to send a knock event to a room, and you can now edit a prior message inline, within the chat pane.</p>
|
||||
<p>Other usability improvements include an overhaul of the keyboard navigation and shortcuts like Ctrl+PgUp/PgDn that allow you to skip from room to room.</p>
|
||||
</description>
|
||||
<artifacts>
|
||||
<artifact type="binary" platform="x86_64-windows-msvc">
|
||||
<location>https://download.kde.org/stable/release-service/23.04.0/windows/neochat-23.04.0-512-windows-cl-msvc2019-x86_64.exe</location>
|
||||
|
||||
@@ -11,12 +11,10 @@ Name[cs]=NeoChat
|
||||
Name[de]=NeoChat
|
||||
Name[el]=NeoChat
|
||||
Name[en_GB]=NeoChat
|
||||
Name[eo]=NeoChat
|
||||
Name[es]=NeoChat
|
||||
Name[eu]=NeoChat
|
||||
Name[fi]=NeoChat
|
||||
Name[fr]=NeoChat
|
||||
Name[gl]=NeoChat
|
||||
Name[hu]=NeoChat
|
||||
Name[ia]=Neochat
|
||||
Name[id]=NeoChat
|
||||
@@ -41,7 +39,6 @@ Name[tr]=NeoChat
|
||||
Name[uk]=NeoChat
|
||||
Name[x-test]=xxNeoChatxx
|
||||
Name[zh_CN]=NeoChat
|
||||
Name[zh_TW]=NeoChat
|
||||
GenericName=Matrix Client
|
||||
GenericName[ar]=عميل ماتركس
|
||||
GenericName[az]=Matrix Müştərisi
|
||||
@@ -51,12 +48,10 @@ GenericName[cs]=Klient protokolu Matrix
|
||||
GenericName[de]=Matrix-Programm
|
||||
GenericName[el]=Εφαρμογή του Matrix
|
||||
GenericName[en_GB]=Matrix Client
|
||||
GenericName[eo]=Matrix-Kliento
|
||||
GenericName[es]=Cliente para Matrix
|
||||
GenericName[eu]=Matrix bezeroa
|
||||
GenericName[fi]=Matrix-asiakas
|
||||
GenericName[fr]=Client « Matrix »
|
||||
GenericName[gl]=Cliente de Matrix
|
||||
GenericName[hu]=Matrix kliens
|
||||
GenericName[ia]=Cliente de Matrice
|
||||
GenericName[id]=Klien Matrix
|
||||
@@ -81,7 +76,6 @@ GenericName[tr]=Matrix İstemcisi
|
||||
GenericName[uk]=Клієнт Matrix
|
||||
GenericName[x-test]=xxMatrix Clientxx
|
||||
GenericName[zh_CN]=Matrix 客户端
|
||||
GenericName[zh_TW]=Matrix 用戶端
|
||||
Comment=Client for the Matrix protocol
|
||||
Comment[ar]=عميل لميفاق ماتركس
|
||||
Comment[az]=Matrix protokolu üçün müştəri
|
||||
@@ -90,12 +84,10 @@ Comment[ca@valencia]=Client per al protocol Matrix
|
||||
Comment[de]=Programm für das Matrix-Protokoll
|
||||
Comment[el]=Πελάτης για το πρωτόκολλο Matrix
|
||||
Comment[en_GB]=Client for the Matrix protocol
|
||||
Comment[eo]=Kliento por la Matrix-protokolo
|
||||
Comment[es]=Cliente para el protocolo Matrix
|
||||
Comment[eu]=Matrix protokolorako bezeroa
|
||||
Comment[fi]=Asiakas Matrix-yhteyskäytännölle
|
||||
Comment[fr]=Client pour le protocole « Matrix »
|
||||
Comment[gl]=Cliente para o protocolo Matrix.
|
||||
Comment[hu]=Kliens a Matrix protokollhoz
|
||||
Comment[ia]=Cliente per le protocollo de Matrix
|
||||
Comment[id]=Klien untuk protokol Matrix
|
||||
@@ -105,7 +97,7 @@ Comment[ka]=კლიენტი Matrix-ის პროტოკოლის
|
||||
Comment[ko]=Matrix 프로토콜용 클라이언트
|
||||
Comment[lt]=Matrix protokolo kliento programa
|
||||
Comment[nl]=Client voor het Matrix-protocol
|
||||
Comment[nn]=Klient for Matrix-protokollen
|
||||
Comment[nn]=Lynmeldingsklient for Matrix-protokollen
|
||||
Comment[pa]=ਮੈਟਰਿਕਸ ਪਰੋਟੋਕਾਲ ਲਈ ਕਲਾਈਂਟ ਹੈ
|
||||
Comment[pl]=Program obsługi protokołu Matriksa
|
||||
Comment[pt]=Cliente para o protocolo Matrix
|
||||
@@ -120,7 +112,6 @@ Comment[tr]=Matrix protokolü için istemci
|
||||
Comment[uk]=Клієнт протоколу Matrix
|
||||
Comment[x-test]=xxClient for the Matrix protocolxx
|
||||
Comment[zh_CN]=为 Matrix 协议打造的客户端
|
||||
Comment[zh_TW]=Matrix 通訊協定的用戶端
|
||||
MimeType=x-scheme-handler/matrix;
|
||||
Exec=neochat %u
|
||||
Terminal=false
|
||||
|
||||
1623
po/ar/neochat.po
1623
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
1651
po/az/neochat.po
1651
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1562
po/ca/neochat.po
1562
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1664
po/cs/neochat.po
1664
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1556
po/da/neochat.po
1556
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1675
po/de/neochat.po
1675
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1650
po/el/neochat.po
1650
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1621
po/en_GB/neochat.po
1621
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1609
po/es/neochat.po
1609
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1732
po/eu/neochat.po
1732
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1690
po/fi/neochat.po
1690
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1647
po/fr/neochat.po
1647
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1653
po/hu/neochat.po
1653
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1828
po/ia/neochat.po
1828
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1928
po/id/neochat.po
1928
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1630
po/ie/neochat.po
1630
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1621
po/it/neochat.po
1621
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1534
po/ja/neochat.po
1534
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1605
po/ka/neochat.po
1605
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
3106
po/ko/neochat.po
3106
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1532
po/lt/neochat.po
1532
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
1611
po/nl/neochat.po
1611
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
2670
po/nn/neochat.po
2670
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1626
po/pa/neochat.po
1626
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
1683
po/pl/neochat.po
1683
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1586
po/pt/neochat.po
1586
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
1734
po/pt_BR/neochat.po
1734
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
1742
po/ru/neochat.po
1742
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1625
po/sk/neochat.po
1625
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
1615
po/sl/neochat.po
1615
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -1,122 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
|
||||
<!ENTITY % Swedish "INCLUDE">
|
||||
]>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
-->
|
||||
|
||||
<refentry lang="&language;">
|
||||
<refentryinfo>
|
||||
<title
|
||||
>NeoChat användarmanual</title>
|
||||
<author
|
||||
><firstname
|
||||
>Carl</firstname
|
||||
><surname
|
||||
>Schwan</surname
|
||||
> <contrib
|
||||
>NeoChat manualsida.</contrib
|
||||
> <email
|
||||
>carl@carlschwan.eu</email
|
||||
></author>
|
||||
<date
|
||||
>2022-11-01</date>
|
||||
<releaseinfo
|
||||
>22.09</releaseinfo>
|
||||
<productname
|
||||
>NeoChat</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>
|
||||
<command
|
||||
>neochat</command>
|
||||
</refentrytitle>
|
||||
<manvolnum
|
||||
>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname
|
||||
>neochat</refname>
|
||||
<refpurpose
|
||||
>Klient för att interagera med meddelandeprotokollet matrix</refpurpose>
|
||||
</refnamediv>
|
||||
<!-- body begins here -->
|
||||
<refsynopsisdiv id='synopsis'>
|
||||
<cmdsynopsis
|
||||
><command
|
||||
>neochat</command
|
||||
> <arg choice="opt"
|
||||
><replaceable
|
||||
>URI</replaceable
|
||||
></arg
|
||||
> </cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsect1 id="description">
|
||||
<title
|
||||
>Beskrivning</title>
|
||||
<para
|
||||
><command
|
||||
>neochat</command
|
||||
> är ett chattprogram för protokollet matrix som fungerar både på skrivbord och mobil. </para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="options"
|
||||
><title
|
||||
>Väljare</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term
|
||||
><option
|
||||
>URI</option
|
||||
></term>
|
||||
<listitem>
|
||||
<para
|
||||
>Matrix webbadress för en användare eller ett rum, t.ex. matrix:u/användare:exempel.org. Det gör att NeoChat försöker öppna det angivna rummet eller konversationen. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="bug">
|
||||
<title
|
||||
>Rapportera fel</title>
|
||||
<para
|
||||
>Rapportera fel och funktionsönskemål på <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General"
|
||||
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General</ulink
|
||||
></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title
|
||||
>Se också</title>
|
||||
<simplelist>
|
||||
<member
|
||||
>En lista över vanliga frågor om Matrix <ulink url="https://matrix.org/faq/"
|
||||
>https://matrix.org/faq/</ulink
|
||||
> </member>
|
||||
<member
|
||||
>kf5options(7)</member>
|
||||
<member
|
||||
>qt5options(7)</member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="copyright"
|
||||
><title
|
||||
>Copyright</title>
|
||||
<para
|
||||
>Copyright © 2020-2022 Tobias Fella </para>
|
||||
<para
|
||||
>Copyright © 2020-2022 Carl Schwan </para>
|
||||
<para
|
||||
>Licens: GNU General Public Version 3 eller senare <<ulink url="https://wwwgnuorg/licenses/gpl-html"
|
||||
>http://www.gnu.org/licenses/gpl-3.0.html</ulink
|
||||
>></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
2963
po/sv/neochat.po
2963
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1621
po/ta/neochat.po
1621
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1570
po/tok/neochat.po
1570
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
1699
po/tr/neochat.po
1699
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
1617
po/uk/neochat.po
1617
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
2218
po/zh_CN/neochat.po
2218
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
2964
po/zh_TW/neochat.po
2964
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
225
snapcraft.yaml
225
snapcraft.yaml
@@ -1,225 +0,0 @@
|
||||
|
||||
# SPDX-FileCopyrightText: 2023 Scarlett Moore <sgmoore@kde.org>
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
---
|
||||
name: neochat
|
||||
base: core22
|
||||
adopt-info: neochat
|
||||
grade: stable
|
||||
confinement: strict
|
||||
apps:
|
||||
neochat:
|
||||
# extensions:
|
||||
# - kde-neon
|
||||
command: usr/bin/neochat
|
||||
common-id: org.kde.neochat
|
||||
desktop: usr/share/applications/org.kde.neochat.desktop
|
||||
plugs:
|
||||
- home
|
||||
- removable-media
|
||||
- desktop
|
||||
- desktop-legacy
|
||||
- opengl
|
||||
- wayland
|
||||
- x11
|
||||
- audio-playback
|
||||
- unity7
|
||||
- network
|
||||
- network-bind
|
||||
- network-manager-observe
|
||||
- password-manager-service
|
||||
- accounts-service
|
||||
command-chain:
|
||||
- snap/command-chain/desktop-launch
|
||||
assumes:
|
||||
- snapd2.58.3
|
||||
compression: lzo
|
||||
plugs:
|
||||
desktop:
|
||||
mount-host-font-cache: false
|
||||
icon-themes:
|
||||
interface: content
|
||||
target: $SNAP/data-dir/icons
|
||||
default-provider: gtk-common-themes
|
||||
sound-themes:
|
||||
interface: content
|
||||
target: $SNAP/data-dir/sounds
|
||||
default-provider: gtk-common-themes
|
||||
kf5-5-111-qt-5-15-11-core22:
|
||||
content: kf5-5-111-qt-5-15-11-core22-all
|
||||
interface: content
|
||||
default-provider: kf5-5-111-qt-5-15-11-core22
|
||||
target: $SNAP/kf5
|
||||
environment:
|
||||
SNAP_DESKTOP_RUNTIME: $SNAP/kf5
|
||||
QML2_IMPORT_PATH: "$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/qt5/qml:$SNAP/kf5/usr/lib/$CRAFT_ARCH_TRIPLET/qt5/qml:$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/qml"
|
||||
QT_QUICK_CONTROLS_STYLE: org.kde.desktop
|
||||
XDG_DATA_DIRS: "$SNAP/.local"
|
||||
XDG_CONFIG_DIRS: "$SNAP/etc/xdg"
|
||||
hooks:
|
||||
configure:
|
||||
plugs:
|
||||
- desktop
|
||||
command-chain:
|
||||
- snap/command-chain/hooks-configure-desktop
|
||||
layout:
|
||||
/usr/share/X11:
|
||||
symlink: $SNAP/kf5/usr/share/X11
|
||||
slots:
|
||||
session-dbus-interface:
|
||||
interface: dbus
|
||||
name: org.kde.neochat
|
||||
bus: session
|
||||
package-repositories:
|
||||
- type: apt
|
||||
components:
|
||||
- main
|
||||
suites:
|
||||
- jammy
|
||||
key-id: 444DABCF3667D0283F894EDDE6D4736255751E5D
|
||||
url: http://origin.archive.neon.kde.org/user
|
||||
key-server: keyserver.ubuntu.com
|
||||
parts:
|
||||
kde-neon:
|
||||
source: /snap/snapcraft/current/share/snapcraft/extensions/desktop/kde-neon
|
||||
source-type: local
|
||||
plugin: make
|
||||
make-parameters:
|
||||
- PLATFORM_PLUG=kf5-5-111-qt-5-15-11-core22
|
||||
build-snaps:
|
||||
- kf5-5-111-qt-5-15-11-core22-sdk
|
||||
build-environment:
|
||||
- &id001
|
||||
PATH: /snap/kf5-5-111-qt-5-15-11-core22-sdk/current/usr/bin${PATH:+:$PATH}
|
||||
- &id002
|
||||
XDG_DATA_DIRS: $CRAFT_STAGE/usr/share:/snap/kf5-5-111-qt-5-15-11-core22-sdk/current/usr/share:/usr/share${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}
|
||||
- &id003
|
||||
XDG_CONFIG_HOME: $CRAFT_STAGE/etc/xdg:/snap/kf5-5-111-qt-5-15-11-core22-sdk/current/etc/xdg:/etc/xdg${XDG_CONFIG_HOME:+:$XDG_CONFIG_HOME}
|
||||
- &id004
|
||||
CRAFT_CMAKE_ARGS: -DCMAKE_FIND_ROOT_PATH=/snap/kf5-5-111-qt-5-15-11-core22-sdk/current${CRAFT_CMAKE_ARGS:+:$CRAFT_CMAKE_ARGS}
|
||||
qtkeychain:
|
||||
after:
|
||||
- kde-neon
|
||||
source: https://github.com/frankosterfeld/qtkeychain.git
|
||||
source-tag: v0.14.0
|
||||
source-depth: 0
|
||||
plugin: cmake
|
||||
build-packages:
|
||||
- libsecret-1-dev
|
||||
stage-packages:
|
||||
- libsecret-1-0
|
||||
- gnome-keyring
|
||||
cmake-parameters:
|
||||
- "-DKDE_INSTALL_USE_QT_SYS_PATHS=FALSE"
|
||||
- "-DCMAKE_INSTALL_PREFIX=/usr"
|
||||
- "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||
- "-DENABLE_TESTING=OFF"
|
||||
- "-DBUILD_TESTING=OFF"
|
||||
- "-DKDE_SKIP_TEST_SETTINGS=ON"
|
||||
- "-DCMAKE_FIND_ROOT_PATH=$CRAFT_STAGE\\;/snap/kf5-5-111-qt-5-15-11-core22/current"
|
||||
- "-DBUILD_TRANSLATIONS=OFF"
|
||||
- "-DLIBSECRET_SUPPORT=ON"
|
||||
- "-DKEYCHAIN_DBUS=1"
|
||||
prime:
|
||||
- "-usr/include/qt5keychain"
|
||||
- "-usr/lib/$CRAFT_ARCH_TRIPLET/libqt5keychain.so"
|
||||
- "-usr/mkspecs"
|
||||
- "-usr/lib/$CRAFT_ARCH_TRIPLET/cmake"
|
||||
libmatrixclient:
|
||||
after:
|
||||
- kde-neon
|
||||
- qtkeychain
|
||||
source: https://github.com/quotient-im/libQuotient.git
|
||||
source-tag: 0.8.1.2
|
||||
source-depth: 0
|
||||
plugin: cmake
|
||||
build-packages:
|
||||
- qtmultimedia5-dev
|
||||
- libolm-dev
|
||||
- libssl-dev
|
||||
cmake-parameters:
|
||||
- "-DCMAKE_INSTALL_PREFIX=/usr"
|
||||
- "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||
- "-DENABLE_TESTING=OFF"
|
||||
- "-DBUILD_TESTING=OFF"
|
||||
- "-DKDE_SKIP_TEST_SETTINGS=ON"
|
||||
- "-DQuotient_ENABLE_E2EE=ON"
|
||||
- "-DBUILDING_SHARED_QUOTIENT=ON"
|
||||
- "-DCMAKE_FIND_ROOT_PATH=$CRAFT_STAGE\\;/snap/kf5-5-111-qt-5-15-11-core22/current"
|
||||
neochat:
|
||||
after:
|
||||
- kde-neon
|
||||
- qtkeychain
|
||||
- libmatrixclient
|
||||
parse-info:
|
||||
- usr/share/metainfo/org.kde.neochat.appdata.xml
|
||||
source: .
|
||||
source-type: local
|
||||
plugin: cmake
|
||||
build-packages:
|
||||
- cmark
|
||||
- gcc-10
|
||||
- g++-10
|
||||
- libcmark-dev
|
||||
- kquickimageeditor-dev
|
||||
- libkf5qqc2desktopstyle-dev
|
||||
- qcoro-qt5-dev
|
||||
- kirigami-addons-dev
|
||||
- reuse
|
||||
- libkf5doctools-dev
|
||||
- qtbase5-private-dev
|
||||
- qml-module-org-kde-kquickimageeditor
|
||||
- qml-module-org-kde-qqc2desktopstyle
|
||||
- kirigami-addons-data
|
||||
- qml-module-org-kde-kirigamiaddons
|
||||
- qml-module-org-kde-quickcharts
|
||||
- libsqlite3-dev
|
||||
- libolm-dev
|
||||
stage-packages:
|
||||
- libcmark0.30.2
|
||||
- qml-module-org-kde-kquickimageeditor
|
||||
- qml-module-org-kde-qqc2desktopstyle
|
||||
- kirigami-addons-data
|
||||
- qml-module-org-kde-kirigamiaddons
|
||||
- qml-module-org-kde-quickcharts
|
||||
- qml-module-org-kde-kirigami2
|
||||
- reuse
|
||||
- libsqlite3-0
|
||||
- libolm3
|
||||
cmake-parameters:
|
||||
- "-DKDE_INSTALL_USE_QT_SYS_PATHS=FALSE"
|
||||
- "-DCMAKE_INSTALL_PREFIX=/usr"
|
||||
- "-DCMAKE_BUILD_TYPE=Release"
|
||||
- "-DENABLE_TESTING=OFF"
|
||||
- "-DBUILD_TESTING=OFF"
|
||||
- "-DKDE_SKIP_TEST_SETTINGS=ON"
|
||||
- "-DNEOCHAT_FLATPAK=ON"
|
||||
- "-DCMAKE_FIND_ROOT_PATH=$CRAFT_STAGE\\;/snap/kf5-5-111-qt-5-15-11-core22-sdk/current"
|
||||
- "-DKDE_INSTALL_PLUGINDIR=/usr/lib/$CRAFT_ARCH_TRIPLET/qt5/plugins/"
|
||||
prime:
|
||||
- "-usr/lib/*/cmake/*"
|
||||
- "-usr/include/*"
|
||||
- "-usr/share/ECM/*"
|
||||
- "-usr/share/doc/*"
|
||||
- "-usr/share/man/*"
|
||||
- "-usr/share/icons/breeze-dark*"
|
||||
- "-usr/bin/X11"
|
||||
- "-usr/lib/gcc/$CRAFT_ARCH_TRIPLET/6.0.0"
|
||||
- "-usr/lib/aspell/*"
|
||||
- "-usr/share/lintian"
|
||||
build-environment: &id005
|
||||
- *id001
|
||||
- *id002
|
||||
- *id003
|
||||
- *id004
|
||||
cleanup:
|
||||
after:
|
||||
- kde-neon
|
||||
- neochat
|
||||
plugin: nil
|
||||
override-prime: |
|
||||
set -eux
|
||||
# find $CRAFT_PRIME/usr/share/doc/ -type f -not -name 'copyright' -delete
|
||||
# find $CRAFT_PRIME/usr/share -type d -empty -delete | /bin/true
|
||||
# # Unused libraries found by linter
|
||||
@@ -3,144 +3,67 @@
|
||||
# SPDX-FileCopyrightText: 2020-2021 Tobias Fella <tobias.fella@kde.org>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
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)
|
||||
configure_file(qml/Component/Timeline/OsmLocationPlugin.qml ${CMAKE_CURRENT_BINARY_DIR}/qml/Component/Timeline/OsmLocationPlugin.qml)
|
||||
|
||||
configure_file(res.qrc ${CMAKE_CURRENT_SOURCE_DIR}/res.generated.qrc)
|
||||
|
||||
add_library(neochat STATIC
|
||||
controller.cpp
|
||||
controller.h
|
||||
actionshandler.cpp
|
||||
actionshandler.h
|
||||
models/emojimodel.cpp
|
||||
models/emojimodel.h
|
||||
emojitones.cpp
|
||||
emojitones.h
|
||||
models/customemojimodel.cpp
|
||||
models/customemojimodel.h
|
||||
clipboard.cpp
|
||||
clipboard.h
|
||||
matriximageprovider.cpp
|
||||
matriximageprovider.h
|
||||
models/messageeventmodel.cpp
|
||||
models/messageeventmodel.h
|
||||
models/messagefiltermodel.cpp
|
||||
models/messagefiltermodel.h
|
||||
models/roomlistmodel.cpp
|
||||
models/roomlistmodel.h
|
||||
models/sortfilterspacelistmodel.cpp
|
||||
models/sortfilterspacelistmodel.h
|
||||
models/accountemoticonmodel.cpp
|
||||
models/accountemoticonmodel.h
|
||||
spacehierarchycache.cpp
|
||||
spacehierarchycache.h
|
||||
roommanager.cpp
|
||||
roommanager.h
|
||||
neochatroom.cpp
|
||||
neochatroom.h
|
||||
neochatuser.cpp
|
||||
neochatuser.h
|
||||
models/userlistmodel.cpp
|
||||
models/userlistmodel.h
|
||||
models/userfiltermodel.cpp
|
||||
models/userfiltermodel.h
|
||||
models/publicroomlistmodel.cpp
|
||||
models/publicroomlistmodel.h
|
||||
models/userdirectorylistmodel.cpp
|
||||
models/userdirectorylistmodel.h
|
||||
models/pushrulemodel.cpp
|
||||
models/pushrulemodel.h
|
||||
models/emoticonfiltermodel.cpp
|
||||
models/emoticonfiltermodel.h
|
||||
models/keywordnotificationrulemodel.cpp
|
||||
notificationsmanager.cpp
|
||||
notificationsmanager.h
|
||||
models/sortfilterroomlistmodel.cpp
|
||||
models/sortfilterroomlistmodel.h
|
||||
chatdocumenthandler.cpp
|
||||
chatdocumenthandler.h
|
||||
models/devicesmodel.cpp
|
||||
models/devicesmodel.h
|
||||
models/devicesproxymodel.cpp
|
||||
filetypesingleton.cpp
|
||||
filetypesingleton.h
|
||||
login.cpp
|
||||
login.h
|
||||
models/webshortcutmodel.cpp
|
||||
models/webshortcutmodel.h
|
||||
blurhash.cpp
|
||||
blurhash.h
|
||||
blurhashimageprovider.cpp
|
||||
blurhashimageprovider.h
|
||||
models/collapsestateproxymodel.cpp
|
||||
models/collapsestateproxymodel.h
|
||||
models/mediamessagefiltermodel.cpp
|
||||
models/mediamessagefiltermodel.h
|
||||
urlhelper.cpp
|
||||
urlhelper.h
|
||||
windowcontroller.cpp
|
||||
windowcontroller.h
|
||||
linkpreviewer.cpp
|
||||
linkpreviewer.h
|
||||
models/completionmodel.cpp
|
||||
models/completionmodel.h
|
||||
models/completionproxymodel.cpp
|
||||
models/completionproxymodel.h
|
||||
models/actionsmodel.cpp
|
||||
models/actionsmodel.h
|
||||
models/serverlistmodel.cpp
|
||||
models/serverlistmodel.h
|
||||
models/statemodel.cpp
|
||||
models/statemodel.h
|
||||
models/statefiltermodel.cpp
|
||||
models/statefiltermodel.h
|
||||
filetransferpseudojob.cpp
|
||||
filetransferpseudojob.h
|
||||
models/searchmodel.cpp
|
||||
models/searchmodel.h
|
||||
texthandler.cpp
|
||||
texthandler.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
models/stickermodel.cpp
|
||||
models/stickermodel.h
|
||||
models/imagepacksmodel.cpp
|
||||
models/imagepacksmodel.h
|
||||
events/imagepackevent.cpp
|
||||
events/imagepackevent.h
|
||||
events/joinrulesevent.cpp
|
||||
events/joinrulesevent.h
|
||||
models/reactionmodel.cpp
|
||||
models/reactionmodel.h
|
||||
delegatesizehelper.cpp
|
||||
delegatesizehelper.h
|
||||
models/livelocationsmodel.cpp
|
||||
models/livelocationsmodel.h
|
||||
models/locationsmodel.cpp
|
||||
models/locationsmodel.h
|
||||
locationhelper.cpp
|
||||
locationhelper.h
|
||||
events/pollevent.cpp
|
||||
pollhandler.cpp
|
||||
events/stickerevent.cpp
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(neochat
|
||||
HEADER "messageeventmodel_logging.h"
|
||||
IDENTIFIER "MessageEvent"
|
||||
CATEGORY_NAME "org.kde.neochat.messageeventmodel"
|
||||
DESCRIPTION "Neochat: messageeventmodel"
|
||||
DEFAULT_SEVERITY Info
|
||||
EXPORT NEOCHAT
|
||||
)
|
||||
|
||||
add_executable(neochat-app
|
||||
main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/res.generated.qrc
|
||||
res.qrc
|
||||
)
|
||||
|
||||
target_include_directories(neochat-app PRIVATE ${CMAKE_BINARY_DIR})
|
||||
@@ -149,16 +72,24 @@ target_link_libraries(neochat-app PRIVATE
|
||||
neochat
|
||||
)
|
||||
|
||||
if(Quotient${QUOTIENT_SUFFIX}_VERSION_MINOR GREATER 6)
|
||||
target_compile_definitions(neochat PUBLIC QUOTIENT_07)
|
||||
target_sources(neochat PRIVATE events/pollevent.cpp pollhandler.cpp)
|
||||
else()
|
||||
target_compile_definitions(neochat PUBLIC QUOTIENT_VERSION=\"${Quotient${QUOTIENT_SUFFIX}_VERSION}\")
|
||||
target_sources(neochat PRIVATE neochataccountregistry.cpp)
|
||||
endif()
|
||||
|
||||
ecm_add_app_icon(NEOCHAT_ICON ICONS ${CMAKE_SOURCE_DIR}/128-logo.png)
|
||||
|
||||
target_sources(neochat-app PRIVATE ${NEOCHAT_ICON})
|
||||
|
||||
if(NOT ANDROID)
|
||||
target_sources(neochat PRIVATE colorschemer.cpp colorschemer.h)
|
||||
target_sources(neochat PRIVATE colorschemer.cpp)
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
target_sources(neochat PRIVATE trayicon_sni.cpp trayicon_sni.h)
|
||||
target_sources(neochat PRIVATE trayicon_sni.cpp)
|
||||
else()
|
||||
target_sources(neochat PRIVATE trayicon.cpp trayicon.h)
|
||||
target_sources(neochat PRIVATE trayicon.cpp)
|
||||
endif()
|
||||
target_link_libraries(neochat PUBLIC KF${QT_MAJOR_VERSION}::ConfigWidgets KF${QT_MAJOR_VERSION}::WindowSystem)
|
||||
target_compile_definitions(neochat PUBLIC -DHAVE_COLORSCHEME)
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include "actionshandler.h"
|
||||
|
||||
#include <Quotient/csapi/joining.h>
|
||||
#include <Quotient/events/roommemberevent.h>
|
||||
#include <csapi/joining.h>
|
||||
#include <events/roommemberevent.h>
|
||||
|
||||
#include <cmark.h>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "models/actionsmodel.h"
|
||||
#include "models/customemojimodel.h"
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatroom.h"
|
||||
#include "texthandler.h"
|
||||
|
||||
using namespace Quotient;
|
||||
@@ -182,5 +183,3 @@ void ActionsHandler::checkEffects(const QString &text)
|
||||
Q_EMIT showEffect(*effect);
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_actionshandler.cpp"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <events/roommessageevent.h>
|
||||
|
||||
#include "neochatroom.h"
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
Q_SIGNALS:
|
||||
void roomChanged();
|
||||
void showEffect(const QString &effect);
|
||||
void showEffect(QString effect);
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <Sonnet/BackgroundChecker>
|
||||
#include <Sonnet/Settings>
|
||||
|
||||
#include "neochatroom.h"
|
||||
|
||||
class SyntaxHighlighter : public QSyntaxHighlighter
|
||||
{
|
||||
public:
|
||||
@@ -218,8 +220,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::DisplayNameRole).toString();
|
||||
auto id = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::SubtitleRole).toString();
|
||||
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 text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char('@'), cursorPosition() - 1);
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
@@ -232,7 +234,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::ReplacedTextRole).toString();
|
||||
auto command = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedText).toString();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char('/'));
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
@@ -240,7 +242,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::SubtitleRole).toString();
|
||||
auto alias = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::Subtitle).toString();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char('#'), cursorPosition() - 1);
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
@@ -253,7 +255,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::ReplacedTextRole).toString();
|
||||
auto shortcode = m_completionModel->data(m_completionModel->index(index, 0), CompletionModel::ReplacedText).toString();
|
||||
auto text = getText();
|
||||
auto at = text.lastIndexOf(QLatin1Char(':'));
|
||||
QTextCursor cursor(document()->textDocument());
|
||||
@@ -353,5 +355,3 @@ void ChatDocumentHandler::setErrorColor(const QColor &color)
|
||||
m_highlighter->rehighlight();
|
||||
Q_EMIT errorColorChanged();
|
||||
}
|
||||
|
||||
#include "moc_chatdocumenthandler.cpp"
|
||||
|
||||
@@ -159,7 +159,7 @@ private:
|
||||
|
||||
bool m_isEdit = false;
|
||||
|
||||
QPointer<QQuickTextDocument> m_document;
|
||||
QQuickTextDocument *m_document;
|
||||
|
||||
QPointer<NeoChatRoom> m_room;
|
||||
bool completionVisible = false;
|
||||
|
||||
@@ -79,5 +79,3 @@ void Clipboard::setImage(const QUrl &url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_clipboard.cpp"
|
||||
|
||||
@@ -44,5 +44,3 @@ QString ColorSchemer::nameForIndex(int index) const
|
||||
{
|
||||
return c->model()->data(c->model()->index(index, 0), Qt::DisplayRole).toString();
|
||||
}
|
||||
|
||||
#include "moc_colorschemer.cpp"
|
||||
|
||||
@@ -28,7 +28,7 @@ class ColorSchemer : public QObject
|
||||
Q_PROPERTY(QAbstractItemModel *model READ model CONSTANT)
|
||||
|
||||
public:
|
||||
explicit ColorSchemer(QObject *parent = nullptr);
|
||||
ColorSchemer(QObject *parent = nullptr);
|
||||
~ColorSchemer();
|
||||
|
||||
QAbstractItemModel *model() const;
|
||||
|
||||
@@ -31,15 +31,23 @@
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/csapi/content-repo.h>
|
||||
#include <Quotient/csapi/logout.h>
|
||||
#include <Quotient/csapi/profile.h>
|
||||
#include <Quotient/jobs/downloadfilejob.h>
|
||||
#include <Quotient/qt_connection_util.h>
|
||||
#include <Quotient/csapi/notifications.h>
|
||||
#include <Quotient/eventstats.h>
|
||||
#ifdef QUOTIENT_07
|
||||
#include "accountregistry.h"
|
||||
#else
|
||||
#include "neochataccountregistry.h"
|
||||
#endif
|
||||
|
||||
#include <connection.h>
|
||||
#include <csapi/content-repo.h>
|
||||
#include <csapi/logout.h>
|
||||
#include <csapi/profile.h>
|
||||
#include <jobs/downloadfilejob.h>
|
||||
#include <qt_connection_util.h>
|
||||
|
||||
#ifdef QUOTIENT_07
|
||||
#include <csapi/notifications.h>
|
||||
#include <eventstats.h>
|
||||
#endif
|
||||
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatroom.h"
|
||||
@@ -101,23 +109,92 @@ Controller::Controller(QObject *parent)
|
||||
}
|
||||
#endif
|
||||
|
||||
connect(&m_accountRegistry, &AccountRegistry::accountCountChanged, this, &Controller::activeConnectionIndexChanged);
|
||||
connect(&AccountRegistry::instance(), &AccountRegistry::accountCountChanged, this, &Controller::activeConnectionIndexChanged);
|
||||
|
||||
#ifdef QUOTIENT_07
|
||||
static int oldAccountCount = 0;
|
||||
connect(&m_accountRegistry, &AccountRegistry::accountCountChanged, this, [this]() {
|
||||
if (m_accountRegistry.size() > oldAccountCount) {
|
||||
auto connection = m_accountRegistry.accounts()[m_accountRegistry.size() - 1];
|
||||
connect(connection, &Connection::syncDone, this, [connection]() {
|
||||
NotificationsManager::instance().handleNotifications(connection);
|
||||
connect(&AccountRegistry::instance(), &AccountRegistry::accountCountChanged, this, [=]() {
|
||||
if (AccountRegistry::instance().size() > oldAccountCount) {
|
||||
auto connection = AccountRegistry::instance().accounts()[AccountRegistry::instance().size() - 1];
|
||||
connect(connection, &Connection::syncDone, this, [=]() {
|
||||
handleNotifications(connection);
|
||||
});
|
||||
}
|
||||
oldAccountCount = m_accountRegistry.size();
|
||||
oldAccountCount = AccountRegistry::instance().size();
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, [this] {
|
||||
m_pushRuleModel = new PushRuleModel;
|
||||
#ifdef QUOTIENT_07
|
||||
void Controller::handleNotifications(QPointer<Quotient::Connection> connection)
|
||||
{
|
||||
static QStringList initial;
|
||||
static QStringList oldNotifications;
|
||||
auto job = connection->callApi<GetNotificationsJob>();
|
||||
|
||||
connect(job, &BaseJob::success, this, [job, connection]() {
|
||||
const auto notifications = job->jsonData()["notifications"].toArray();
|
||||
if (!initial.contains(connection->user()->id())) {
|
||||
initial.append(connection->user()->id());
|
||||
for (const auto &n : notifications) {
|
||||
oldNotifications += n["event"]["event_id"].toString();
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (const auto &n : notifications) {
|
||||
const auto ¬ification = n.toObject();
|
||||
if (notification["read"].toBool()) {
|
||||
oldNotifications.removeOne(notification["event"]["event_id"].toString());
|
||||
continue;
|
||||
}
|
||||
if (oldNotifications.contains(notification["event"]["event_id"].toString())) {
|
||||
continue;
|
||||
}
|
||||
oldNotifications += notification["event"]["event_id"].toString();
|
||||
auto room = connection->room(notification["room_id"].toString());
|
||||
|
||||
// If room exists, room is NOT active OR the application is NOT active, show notification
|
||||
if (room
|
||||
&& !(RoomManager::instance().currentRoom() && room->id() == RoomManager::instance().currentRoom()->id()
|
||||
&& QGuiApplication::applicationState() == Qt::ApplicationActive)) {
|
||||
// The room might have been deleted (for example rejected invitation).
|
||||
auto sender = room->user(notification["event"]["sender"].toString());
|
||||
|
||||
QString body;
|
||||
|
||||
if (notification["event"]["type"].toString() == "org.matrix.msc3381.poll.start") {
|
||||
body = notification["event"]["content"]["org.matrix.msc3381.poll.start"]["question"]["body"].toString();
|
||||
} else {
|
||||
body = notification["event"]["content"]["body"].toString();
|
||||
}
|
||||
|
||||
if (notification["event"]["type"] == "m.room.encrypted") {
|
||||
#ifdef Quotient_E2EE_ENABLED
|
||||
const auto decrypted = connection->decryptNotification(notification);
|
||||
body = decrypted["content"]["body"].toString();
|
||||
#endif
|
||||
if (body.isEmpty()) {
|
||||
body = i18n("Encrypted Message");
|
||||
}
|
||||
}
|
||||
|
||||
QImage avatar_image;
|
||||
if (!sender->avatarUrl(room).isEmpty()) {
|
||||
avatar_image = sender->avatar(128, room);
|
||||
} else {
|
||||
avatar_image = room->avatar(128);
|
||||
}
|
||||
NotificationsManager::instance().postNotification(dynamic_cast<NeoChatRoom *>(room),
|
||||
sender->displayname(room),
|
||||
body,
|
||||
avatar_image,
|
||||
notification["event"].toObject()["event_id"].toString(),
|
||||
true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
Controller &Controller::instance()
|
||||
{
|
||||
@@ -147,10 +224,10 @@ void Controller::logout(Connection *conn, bool serverSideLogout)
|
||||
job.start();
|
||||
loop.exec();
|
||||
|
||||
if (m_accountRegistry.count() > 1) {
|
||||
if (AccountRegistry::instance().count() > 1) {
|
||||
// Only set the connection if the the account being logged out is currently active
|
||||
if (conn == activeConnection()) {
|
||||
setActiveConnection(m_accountRegistry.accounts()[0]);
|
||||
setActiveConnection(AccountRegistry::instance().accounts()[0]);
|
||||
}
|
||||
} else {
|
||||
setActiveConnection(nullptr);
|
||||
@@ -165,7 +242,9 @@ void Controller::addConnection(Connection *c)
|
||||
{
|
||||
Q_ASSERT_X(c, __FUNCTION__, "Attempt to add a null connection");
|
||||
|
||||
m_accountRegistry.add(c);
|
||||
#ifndef QUOTIENT_07
|
||||
AccountRegistry::instance().add(c);
|
||||
#endif
|
||||
|
||||
c->setLazyLoading(true);
|
||||
|
||||
@@ -180,7 +259,7 @@ void Controller::addConnection(Connection *c)
|
||||
});
|
||||
|
||||
connect(c, &Connection::requestFailed, this, [this](BaseJob *job) {
|
||||
if (job->error() == BaseJob::UserConsentRequired) {
|
||||
if (job->error() == BaseJob::UserConsentRequiredError) {
|
||||
Q_EMIT userConsentRequired(job->errorUrl());
|
||||
}
|
||||
});
|
||||
@@ -195,8 +274,15 @@ void Controller::dropConnection(Connection *c)
|
||||
{
|
||||
Q_ASSERT_X(c, __FUNCTION__, "Attempt to drop a null connection");
|
||||
|
||||
#ifndef QUOTIENT_07
|
||||
AccountRegistry::instance().drop(c);
|
||||
#endif
|
||||
|
||||
Q_EMIT connectionDropped(c);
|
||||
Q_EMIT accountCountChanged();
|
||||
#ifndef QUOTIENT_07
|
||||
c->deleteLater();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Controller::invokeLogin()
|
||||
@@ -247,7 +333,7 @@ void Controller::invokeLogin()
|
||||
connect(connection, &Connection::networkError, this, [this](const QString &error, const QString &, int, int) {
|
||||
Q_EMIT errorOccured(i18n("Network Error: %1", error));
|
||||
});
|
||||
connection->assumeIdentity(account.userId(), accessToken);
|
||||
connection->assumeIdentity(account.userId(), accessToken, account.deviceId());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -263,7 +349,7 @@ QKeychain::ReadPasswordJob *Controller::loadAccessTokenFromKeyChain(const Accoun
|
||||
job->setKey(account.userId());
|
||||
|
||||
// Handling of errors
|
||||
connect(job, &QKeychain::Job::finished, this, [this, job]() {
|
||||
connect(job, &QKeychain::Job::finished, this, [this, &account, job]() {
|
||||
if (job->error() == QKeychain::Error::NoError) {
|
||||
return;
|
||||
}
|
||||
@@ -313,9 +399,15 @@ bool Controller::saveAccessTokenToKeyChain(const AccountSettings &account, const
|
||||
void Controller::changeAvatar(Connection *conn, const QUrl &localFile)
|
||||
{
|
||||
auto job = conn->uploadFile(localFile.toLocalFile());
|
||||
connect(job, &BaseJob::success, this, [conn, job] {
|
||||
conn->callApi<SetAvatarUrlJob>(conn->userId(), job->contentUri());
|
||||
});
|
||||
#ifdef QUOTIENT_07
|
||||
if (isJobPending(job)) {
|
||||
#else
|
||||
if (isJobRunning(job)) {
|
||||
#endif
|
||||
connect(job, &BaseJob::success, this, [conn, job] {
|
||||
conn->callApi<SetAvatarUrlJob>(conn->userId(), job->contentUri());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::markAllMessagesAsRead(Connection *conn)
|
||||
@@ -369,7 +461,11 @@ bool Controller::setAvatar(Connection *connection, const QUrl &avatarSource)
|
||||
User *localUser = connection->user();
|
||||
QString decoded = avatarSource.path();
|
||||
if (decoded.isEmpty()) {
|
||||
#ifdef QUOTIENT_07
|
||||
connection->callApi<SetAvatarUrlJob>(localUser->id(), avatarSource);
|
||||
#else
|
||||
connection->callApi<SetAvatarUrlJob>(localUser->id(), QString());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
if (QImageReader(decoded).read().isNull()) {
|
||||
@@ -380,7 +476,11 @@ bool Controller::setAvatar(Connection *connection, const QUrl &avatarSource)
|
||||
}
|
||||
|
||||
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Omittable<QJsonObject> &auth)
|
||||
#ifdef QUOTIENT_07
|
||||
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), "/_matrix/client/r0/account/password")
|
||||
#else
|
||||
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), QStringLiteral("/_matrix/client/r0/account/password"))
|
||||
#endif
|
||||
{
|
||||
QJsonObject _data;
|
||||
addParam<>(_data, QStringLiteral("new_password"), newPassword);
|
||||
@@ -391,7 +491,7 @@ NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, b
|
||||
|
||||
int Controller::accountCount() const
|
||||
{
|
||||
return m_accountRegistry.count();
|
||||
return AccountRegistry::instance().count();
|
||||
}
|
||||
|
||||
void Controller::setQuitOnLastWindowClosed()
|
||||
@@ -448,7 +548,7 @@ void Controller::setActiveConnection(Connection *connection)
|
||||
m_isOnline = true;
|
||||
Q_EMIT isOnlineChanged(true);
|
||||
});
|
||||
connect(connection, &Connection::requestFailed, this, [](BaseJob *job) {
|
||||
connect(connection, &Connection::requestFailed, this, [=](BaseJob *job) {
|
||||
if (dynamic_cast<DownloadFileJob *>(job) && job->jsonData()["errcode"].toString() == "M_TOO_LARGE"_ls) {
|
||||
RoomManager::instance().warning(i18n("File too large to download."), i18n("Contact your matrix server administrator for support."));
|
||||
}
|
||||
@@ -467,18 +567,17 @@ void Controller::setActiveConnection(Connection *connection)
|
||||
Q_EMIT activeAccountLabelChanged();
|
||||
}
|
||||
|
||||
PushRuleModel *Controller::pushRuleModel() const
|
||||
{
|
||||
return m_pushRuleModel;
|
||||
}
|
||||
|
||||
void Controller::saveWindowGeometry()
|
||||
{
|
||||
WindowController::instance().saveGeometry();
|
||||
}
|
||||
|
||||
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Omittable<QJsonObject> &auth)
|
||||
#ifdef QUOTIENT_07
|
||||
: Quotient::BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId).toLatin1())
|
||||
#else
|
||||
: Quotient::BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId))
|
||||
#endif
|
||||
{
|
||||
QJsonObject _data;
|
||||
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
|
||||
@@ -489,30 +588,16 @@ void Controller::createRoom(const QString &name, const QString &topic)
|
||||
{
|
||||
auto createRoomJob = m_connection->createRoom(Connection::PublishRoom, "", name, topic, QStringList());
|
||||
connect(createRoomJob, &CreateRoomJob::failure, this, [this, createRoomJob] {
|
||||
Q_EMIT errorOccured(i18n("Room creation failed: %1", createRoomJob->errorString()));
|
||||
Q_EMIT errorOccured(i18n("Room creation failed: \"%1\"", createRoomJob->errorString()));
|
||||
});
|
||||
connectSingleShot(this, &Controller::roomAdded, &RoomManager::instance(), &RoomManager::enterRoom, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void Controller::createSpace(const QString &name, const QString &topic)
|
||||
{
|
||||
auto createRoomJob = m_connection->createRoom(Connection::UnpublishRoom,
|
||||
{},
|
||||
name,
|
||||
topic,
|
||||
QStringList(),
|
||||
{},
|
||||
{},
|
||||
false,
|
||||
{},
|
||||
{},
|
||||
QJsonObject{
|
||||
{"type"_ls, "m.space"_ls},
|
||||
});
|
||||
connect(createRoomJob, &CreateRoomJob::failure, this, [this, createRoomJob] {
|
||||
Q_EMIT errorOccured(i18n("Space creation failed: %1", createRoomJob->errorString()));
|
||||
});
|
||||
connectSingleShot(this, &Controller::roomAdded, &RoomManager::instance(), &RoomManager::enterRoom, Qt::QueuedConnection);
|
||||
connectSingleShot(
|
||||
this,
|
||||
&Controller::roomAdded,
|
||||
this,
|
||||
[this](NeoChatRoom *room) {
|
||||
RoomManager::instance().enterRoom(room);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
bool Controller::isOnline() const
|
||||
@@ -584,7 +669,11 @@ bool Controller::hasWindowSystem() const
|
||||
|
||||
bool Controller::encryptionSupported() const
|
||||
{
|
||||
#ifdef QUOTIENT_07
|
||||
return Quotient::encryptionSupported();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Controller::forceRefreshTextDocument(QQuickTextDocument *textDocument, QQuickItem *item)
|
||||
@@ -625,16 +714,29 @@ void Controller::setApplicationProxy()
|
||||
|
||||
int Controller::activeConnectionIndex() const
|
||||
{
|
||||
auto result = std::find_if(m_accountRegistry.accounts().begin(), m_accountRegistry.accounts().end(), [this](const auto &it) {
|
||||
#ifdef QUOTIENT_07
|
||||
auto result = std::find_if(Accounts.accounts().begin(), Accounts.accounts().end(), [this](const auto &it) {
|
||||
return it == m_connection;
|
||||
});
|
||||
return result - m_accountRegistry.accounts().begin();
|
||||
return result - Accounts.accounts().begin();
|
||||
#else
|
||||
for (int i = 0; i < AccountRegistry::instance().rowCount(); i++) {
|
||||
if (AccountRegistry::instance().data(AccountRegistry::instance().index(i, 0), AccountRegistry::UserIdRole).toString() == m_connection->userId()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Controller::quotientMinorVersion() const
|
||||
{
|
||||
// TODO libQuotient 0.7: Replace with version function from libQuotient
|
||||
// TODO libQuotient 0.7: Replace with version function from libQuotient
|
||||
#ifdef QUOTIENT_07
|
||||
return 7;
|
||||
#else
|
||||
return 6;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Controller::isFlatpak() const
|
||||
@@ -680,10 +782,3 @@ QVariantList Controller::getSupportedRoomVersions(Quotient::Connection *connecti
|
||||
|
||||
return supportedRoomVersions;
|
||||
}
|
||||
|
||||
AccountRegistry &Controller::accounts()
|
||||
{
|
||||
return m_accountRegistry;
|
||||
}
|
||||
|
||||
#include "moc_controller.cpp"
|
||||
|
||||
@@ -3,15 +3,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "models/pushrulemodel.h"
|
||||
#include <QObject>
|
||||
#include <QQuickItem>
|
||||
|
||||
#include <KFormat>
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/jobs/basejob.h>
|
||||
#include <Quotient/settings.h>
|
||||
#include <jobs/basejob.h>
|
||||
#include <settings.h>
|
||||
|
||||
class NeoChatRoom;
|
||||
class NeoChatUser;
|
||||
@@ -52,11 +50,6 @@ class Controller : public QObject
|
||||
*/
|
||||
Q_PROPERTY(Quotient::Connection *activeConnection READ activeConnection WRITE setActiveConnection NOTIFY activeConnectionChanged)
|
||||
|
||||
/**
|
||||
* @brief The PushRuleModel that has the active connection's push rules.
|
||||
*/
|
||||
Q_PROPERTY(PushRuleModel *pushRuleModel READ pushRuleModel CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief The row number in the accounts directory of the active connection.
|
||||
*/
|
||||
@@ -117,7 +110,7 @@ public:
|
||||
Wrong, /**< The current password entered was wrong. */
|
||||
Other, /**< An unknown problem occurred. */
|
||||
};
|
||||
Q_ENUM(PasswordStatus)
|
||||
Q_ENUM(PasswordStatus);
|
||||
|
||||
static Controller &instance();
|
||||
|
||||
@@ -126,8 +119,6 @@ public:
|
||||
void setActiveConnection(Quotient::Connection *connection);
|
||||
[[nodiscard]] Quotient::Connection *activeConnection() const;
|
||||
|
||||
[[nodiscard]] PushRuleModel *pushRuleModel() const;
|
||||
|
||||
/**
|
||||
* @brief Add a new connection to the account registry.
|
||||
*/
|
||||
@@ -168,11 +159,6 @@ public:
|
||||
*/
|
||||
Q_INVOKABLE void createRoom(const QString &name, const QString &topic);
|
||||
|
||||
/**
|
||||
* @brief Create new space.
|
||||
*/
|
||||
Q_INVOKABLE void createSpace(const QString &name, const QString &topic);
|
||||
|
||||
/**
|
||||
* @brief Join a room.
|
||||
*/
|
||||
@@ -230,8 +216,6 @@ public:
|
||||
|
||||
Q_INVOKABLE QVariantList getSupportedRoomVersions(Quotient::Connection *connection);
|
||||
|
||||
Quotient::AccountRegistry &accounts();
|
||||
|
||||
private:
|
||||
explicit Controller(QObject *parent = nullptr);
|
||||
|
||||
@@ -246,9 +230,9 @@ private:
|
||||
QMap<Quotient::Room *, int> m_notificationCounts;
|
||||
|
||||
bool hasWindowSystem() const;
|
||||
|
||||
QPointer<PushRuleModel> m_pushRuleModel;
|
||||
Quotient::AccountRegistry m_accountRegistry;
|
||||
#ifdef QUOTIENT_07
|
||||
void handleNotifications(QPointer<Quotient::Connection> connection);
|
||||
#endif
|
||||
|
||||
private Q_SLOTS:
|
||||
void invokeLogin();
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "delegatesizehelper.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
DelegateSizeHelper::DelegateSizeHelper(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::parentWidth() const
|
||||
{
|
||||
return m_parentWidth;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setParentWidth(qreal parentWidth)
|
||||
{
|
||||
if (parentWidth == m_parentWidth) {
|
||||
return;
|
||||
}
|
||||
m_parentWidth = parentWidth;
|
||||
Q_EMIT parentWidthChanged();
|
||||
Q_EMIT currentPercentageWidthChanged();
|
||||
Q_EMIT currentWidthChanged();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::startBreakpoint() const
|
||||
{
|
||||
return m_startBreakpoint;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setStartBreakpoint(qreal startBreakpoint)
|
||||
{
|
||||
if (startBreakpoint == m_startBreakpoint) {
|
||||
return;
|
||||
}
|
||||
m_startBreakpoint = startBreakpoint;
|
||||
Q_EMIT startBreakpointChanged();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::endBreakpoint() const
|
||||
{
|
||||
return m_endBreakpoint;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setEndBreakpoint(qreal endBreakpoint)
|
||||
{
|
||||
if (endBreakpoint == m_endBreakpoint) {
|
||||
return;
|
||||
}
|
||||
m_endBreakpoint = endBreakpoint;
|
||||
Q_EMIT endBreakpointChanged();
|
||||
}
|
||||
|
||||
int DelegateSizeHelper::startPercentWidth() const
|
||||
{
|
||||
return m_startPercentWidth;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setStartPercentWidth(int startPercentWidth)
|
||||
{
|
||||
if (startPercentWidth == m_startPercentWidth) {
|
||||
return;
|
||||
}
|
||||
m_startPercentWidth = startPercentWidth;
|
||||
Q_EMIT startPercentWidthChanged();
|
||||
}
|
||||
|
||||
int DelegateSizeHelper::endPercentWidth() const
|
||||
{
|
||||
return m_endPercentWidth;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setEndPercentWidth(int endPercentWidth)
|
||||
{
|
||||
if (endPercentWidth == m_endPercentWidth) {
|
||||
return;
|
||||
}
|
||||
m_endPercentWidth = endPercentWidth;
|
||||
Q_EMIT endPercentWidthChanged();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::maxWidth() const
|
||||
{
|
||||
return m_maxWidth;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setMaxWidth(qreal maxWidth)
|
||||
{
|
||||
if (maxWidth == m_maxWidth) {
|
||||
return;
|
||||
}
|
||||
m_maxWidth = maxWidth;
|
||||
Q_EMIT maxWidthChanged();
|
||||
}
|
||||
|
||||
int DelegateSizeHelper::calculateCurrentPercentageWidth() const
|
||||
{
|
||||
// Don't do anything if m_parentWidth hasn't been set yet.
|
||||
if (m_parentWidth < 0) {
|
||||
return -1;
|
||||
}
|
||||
// Don't bother with calculations for a horizontal line.
|
||||
if (m_startPercentWidth == m_endPercentWidth) {
|
||||
return m_startPercentWidth;
|
||||
}
|
||||
// Dividing by zero is a bad idea.
|
||||
if (m_startBreakpoint == m_endBreakpoint) {
|
||||
qWarning() << "DelegateSizeHelper::calculateCurrentPercentageWidth() - m_startBreakpoint is equal to m_endBreakpoint this would lead to divide by "
|
||||
"zero, aborting";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fit to y = mx + c
|
||||
qreal m = (m_endPercentWidth - m_startPercentWidth) / (m_endBreakpoint - m_startBreakpoint);
|
||||
qreal c = m_startPercentWidth - m * m_startBreakpoint;
|
||||
|
||||
// This allows us to clamp correctly if the start or end width is bigger.
|
||||
bool endPercentBigger = m_endPercentWidth > m_startPercentWidth;
|
||||
int maxPercentWidth = endPercentBigger ? m_endPercentWidth : m_startPercentWidth;
|
||||
int minPercentWidth = endPercentBigger ? m_startPercentWidth : m_endPercentWidth;
|
||||
|
||||
int calcPercentWidth = std::ceil(m * m_parentWidth + c);
|
||||
return std::clamp(calcPercentWidth, minPercentWidth, maxPercentWidth);
|
||||
}
|
||||
|
||||
int DelegateSizeHelper::currentPercentageWidth() const
|
||||
{
|
||||
return calculateCurrentPercentageWidth();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::currentWidth() const
|
||||
{
|
||||
if (m_parentWidth < 0) {
|
||||
return 0.0;
|
||||
}
|
||||
int percentWidth = calculateCurrentPercentageWidth();
|
||||
// - 1 means bad input values so don't try to calculate.
|
||||
if (percentWidth == -1) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
qreal absoluteWidth = m_parentWidth * percentWidth * 0.01;
|
||||
if (m_maxWidth < 0.0) {
|
||||
return std::ceil(absoluteWidth);
|
||||
} else {
|
||||
return std::ceil(std::min(absoluteWidth, m_maxWidth));
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_delegatesizehelper.cpp"
|
||||
@@ -1,123 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
/**
|
||||
* @class DelegateSizeHelper
|
||||
*
|
||||
* A class to help calculate the current width of a chat delegate/bar.
|
||||
*
|
||||
* The aim is to support a dynamic sizing based upon the width of the page. There is
|
||||
* a built in curve that allows the width to transition between two percentages based
|
||||
* upon a start and finish break point. This is to provide better convergence where
|
||||
* generally the delegate will need to fill all or most the screen when thin but
|
||||
* should max out in size and only fill a lower percentage of the screen when wide.
|
||||
*
|
||||
* @note While the main intended usage is to start with a high percentage when the parentWidth
|
||||
* is small and transition to a lower one when large, the math is setup for the
|
||||
* general case so any combination of parameters works.
|
||||
*/
|
||||
class DelegateSizeHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* @brief The width of the component's parent.
|
||||
*/
|
||||
Q_PROPERTY(qreal parentWidth READ parentWidth WRITE setParentWidth NOTIFY parentWidthChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in px) when the width percentage should start to transition.
|
||||
*/
|
||||
Q_PROPERTY(qreal startBreakpoint READ startBreakpoint WRITE setStartBreakpoint NOTIFY startBreakpointChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in px) when the width percentage should finish transitioning.
|
||||
*/
|
||||
Q_PROPERTY(qreal endBreakpoint READ endBreakpoint WRITE setEndBreakpoint NOTIFY endBreakpointChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in %) of the component at or before the startBreakpoint.
|
||||
*
|
||||
* @sa startBreakpoint
|
||||
*/
|
||||
Q_PROPERTY(int startPercentWidth READ startPercentWidth WRITE setStartPercentWidth NOTIFY startPercentWidthChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in %) of the component at or after the endBreakpoint.
|
||||
*
|
||||
* @sa endBreakpoint
|
||||
*/
|
||||
Q_PROPERTY(int endPercentWidth READ endPercentWidth WRITE setEndPercentWidth NOTIFY endPercentWidthChanged)
|
||||
|
||||
/**
|
||||
* @brief The absolute maximum width (in px) the component can be.
|
||||
*/
|
||||
Q_PROPERTY(qreal maxWidth READ maxWidth WRITE setMaxWidth NOTIFY maxWidthChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in %) of the component at the current parentWidth.
|
||||
*
|
||||
* Will return -1 if no parentWidth is set or startBreakpoint == endBreakpoint.
|
||||
*
|
||||
* @sa parentWidth, startBreakpoint, endBreakpoint
|
||||
*/
|
||||
Q_PROPERTY(int currentPercentageWidth READ currentPercentageWidth NOTIFY currentPercentageWidthChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in px) of the component at the current parentWidth.
|
||||
*
|
||||
* Will return 0.0 if no parentWidth is set.
|
||||
*
|
||||
* @sa parentWidth
|
||||
*/
|
||||
Q_PROPERTY(qreal currentWidth READ currentWidth NOTIFY currentWidthChanged)
|
||||
|
||||
public:
|
||||
explicit DelegateSizeHelper(QObject *parent = nullptr);
|
||||
|
||||
qreal parentWidth() const;
|
||||
void setParentWidth(qreal parentWidth);
|
||||
|
||||
qreal startBreakpoint() const;
|
||||
void setStartBreakpoint(qreal startBreakpoint);
|
||||
|
||||
qreal endBreakpoint() const;
|
||||
void setEndBreakpoint(qreal endBreakpoint);
|
||||
|
||||
int startPercentWidth() const;
|
||||
void setStartPercentWidth(int startPercentWidth);
|
||||
|
||||
int endPercentWidth() const;
|
||||
void setEndPercentWidth(int endPercentWidth);
|
||||
|
||||
qreal maxWidth() const;
|
||||
void setMaxWidth(qreal maxWidth);
|
||||
|
||||
int currentPercentageWidth() const;
|
||||
|
||||
qreal currentWidth() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void parentWidthChanged();
|
||||
void startBreakpointChanged();
|
||||
void endBreakpointChanged();
|
||||
void startPercentWidthChanged();
|
||||
void endPercentWidthChanged();
|
||||
void maxWidthChanged();
|
||||
void currentPercentageWidthChanged();
|
||||
void currentWidthChanged();
|
||||
|
||||
private:
|
||||
qreal m_parentWidth = -1.0;
|
||||
qreal m_startBreakpoint;
|
||||
qreal m_endBreakpoint;
|
||||
int m_startPercentWidth;
|
||||
int m_endPercentWidth;
|
||||
qreal m_maxWidth = -1.0;
|
||||
|
||||
int calculateCurrentPercentageWidth() const;
|
||||
};
|
||||
@@ -11,7 +11,11 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
|
||||
if (json.contains(QStringLiteral("pack"))) {
|
||||
pack = ImagePackEventContent::Pack{
|
||||
fromJson<Omittable<QString>>(json["pack"].toObject()["display_name"]),
|
||||
#ifdef QUOTIENT_07
|
||||
fromJson<Omittable<QUrl>>(json["pack"].toObject()["avatar_url"]),
|
||||
#else
|
||||
QUrl(),
|
||||
#endif
|
||||
fromJson<Omittable<QStringList>>(json["pack"].toObject()["usage"]),
|
||||
fromJson<Omittable<QString>>(json["pack"].toObject()["attribution"]),
|
||||
};
|
||||
@@ -23,13 +27,21 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
|
||||
for (const auto &k : keys) {
|
||||
Omittable<EventContent::ImageInfo> info;
|
||||
if (json["images"][k].toObject().contains(QStringLiteral("info"))) {
|
||||
#ifdef QUOTIENT_07
|
||||
info = EventContent::ImageInfo(QUrl(json["images"][k]["url"].toString()), json["images"][k]["info"].toObject(), k);
|
||||
#else
|
||||
info = EventContent::ImageInfo(QUrl(json["images"][k]["url"].toString()), json["images"][k].toObject(), k);
|
||||
#endif
|
||||
} else {
|
||||
info = none;
|
||||
}
|
||||
images += ImagePackImage{
|
||||
k,
|
||||
#ifdef QUOTIENT_07
|
||||
fromJson<QUrl>(json["images"][k]["url"].toString()),
|
||||
#else
|
||||
QUrl(),
|
||||
#endif
|
||||
fromJson<Omittable<QString>>(json["images"][k]["body"]),
|
||||
info,
|
||||
fromJson<Omittable<QStringList>>(json["images"][k]["usage"]),
|
||||
@@ -39,42 +51,5 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
|
||||
|
||||
void ImagePackEventContent::fillJson(QJsonObject *o) const
|
||||
{
|
||||
if (pack) {
|
||||
QJsonObject packJson;
|
||||
if (pack->displayName) {
|
||||
packJson["display_name"] = *pack->displayName;
|
||||
}
|
||||
if (pack->usage) {
|
||||
QJsonArray usageJson;
|
||||
for (const auto &usage : *pack->usage) {
|
||||
usageJson += usage;
|
||||
}
|
||||
packJson["usage"] = usageJson;
|
||||
}
|
||||
if (pack->avatarUrl) {
|
||||
packJson["avatar_url"] = pack->avatarUrl->toString();
|
||||
}
|
||||
if (pack->attribution) {
|
||||
packJson["attribution"] = *pack->attribution;
|
||||
}
|
||||
(*o)["pack"_ls] = packJson;
|
||||
}
|
||||
|
||||
QJsonObject imagesJson;
|
||||
for (const auto &image : images) {
|
||||
QJsonObject imageJson;
|
||||
imageJson["url"] = image.url.toString();
|
||||
if (image.body) {
|
||||
imageJson["body"] = *image.body;
|
||||
}
|
||||
if (image.usage) {
|
||||
QJsonArray usageJson;
|
||||
for (const auto &usage : *image.usage) {
|
||||
usageJson += usage;
|
||||
}
|
||||
imageJson["usage"] = usageJson;
|
||||
}
|
||||
imagesJson[image.shortcode] = imageJson;
|
||||
}
|
||||
(*o)["images"_ls] = imagesJson;
|
||||
// TODO
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <QVector>
|
||||
#include <Quotient/events/eventcontent.h>
|
||||
#include <Quotient/events/stateevent.h>
|
||||
#include <events/eventcontent.h>
|
||||
#include <events/stateevent.h>
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
@@ -83,11 +83,23 @@ public:
|
||||
*
|
||||
* @sa Quotient::StateEvent, ImagePackEventContent
|
||||
*/
|
||||
#ifdef QUOTIENT_07
|
||||
class ImagePackEvent : public KeyedStateEventBase<ImagePackEvent, ImagePackEventContent>
|
||||
#else
|
||||
class ImagePackEvent : public StateEvent<ImagePackEventContent>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
#ifdef QUOTIENT_07
|
||||
QUO_EVENT(ImagePackEvent, "im.ponies.room_emotes")
|
||||
using KeyedStateEventBase::KeyedStateEventBase;
|
||||
#else
|
||||
DEFINE_EVENT_TYPEID("im.ponies.room_emotes", ImagePackEvent)
|
||||
explicit ImagePackEvent(const QJsonObject &obj)
|
||||
: StateEvent(typeId(), obj)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
REGISTER_EVENT_TYPE(ImagePackEvent)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/events/stateevent.h>
|
||||
#include <events/stateevent.h>
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
@@ -14,13 +14,25 @@ namespace Quotient
|
||||
*
|
||||
* @sa Quotient::StateEvent
|
||||
*/
|
||||
#ifdef QUOTIENT_07
|
||||
class JoinRulesEvent : public StateEvent
|
||||
#else
|
||||
class JoinRulesEvent : public StateEventBase
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
#ifdef QUOTIENT_07
|
||||
QUO_EVENT(JoinRulesEvent, "m.room.join_rules")
|
||||
#else
|
||||
DEFINE_EVENT_TYPEID("m.room.join_rules", JoinRulesEvent)
|
||||
#endif
|
||||
|
||||
explicit JoinRulesEvent(const QJsonObject &obj)
|
||||
#ifdef QUOTIENT_07
|
||||
: StateEvent(obj)
|
||||
#else
|
||||
: StateEventBase(typeId(), obj)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Quotient/events/roomevent.h>
|
||||
#include <events/eventcontent.h>
|
||||
#include <events/roomevent.h>
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
|
||||
35
src/events/stickerevent.cpp
Normal file
35
src/events/stickerevent.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "stickerevent.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
StickerEvent::StickerEvent(const QJsonObject &obj)
|
||||
#ifdef QUOTIENT_07
|
||||
: RoomEvent(obj)
|
||||
#else
|
||||
: RoomEvent(typeId(), obj)
|
||||
#endif
|
||||
, m_imageContent(EventContent::ImageContent(obj["content"_ls].toObject()))
|
||||
{
|
||||
}
|
||||
|
||||
QString StickerEvent::body() const
|
||||
{
|
||||
return content<QString>("body"_ls);
|
||||
}
|
||||
|
||||
const EventContent::ImageContent &StickerEvent::image() const
|
||||
{
|
||||
return m_imageContent;
|
||||
}
|
||||
|
||||
QUrl StickerEvent::url() const
|
||||
{
|
||||
#ifdef QUOTIENT_07
|
||||
return m_imageContent.url();
|
||||
#else
|
||||
return m_imageContent.url;
|
||||
#endif
|
||||
}
|
||||
55
src/events/stickerevent.h
Normal file
55
src/events/stickerevent.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <events/eventcontent.h>
|
||||
#include <events/roomevent.h>
|
||||
|
||||
namespace Quotient
|
||||
{
|
||||
/**
|
||||
* @class StickerEvent
|
||||
*
|
||||
* Class to define a sticker event.
|
||||
*
|
||||
* Sticker messages are specialised image messages that are displayed without
|
||||
* controls (e.g. no "download" link, or light-box view on click, as would be
|
||||
* displayed for for m.image events).
|
||||
*
|
||||
* @sa Quotient::RoomEvent
|
||||
*/
|
||||
class StickerEvent : public RoomEvent
|
||||
{
|
||||
public:
|
||||
#ifdef QUOTIENT_07
|
||||
QUO_EVENT(StickerEvent, "m.sticker")
|
||||
#else
|
||||
DEFINE_EVENT_TYPEID("m.sticker", StickerEvent)
|
||||
#endif
|
||||
|
||||
explicit StickerEvent(const QJsonObject &obj);
|
||||
|
||||
/**
|
||||
* @brief A textual representation or associated description of the sticker image.
|
||||
*
|
||||
* This could be the alt text of the original image, or a message to accompany
|
||||
* and further describe the sticker.
|
||||
*/
|
||||
QString body() const;
|
||||
|
||||
/**
|
||||
* @brief Metadata about the image referred to in url including a thumbnail representation.
|
||||
*/
|
||||
const EventContent::ImageContent &image() const;
|
||||
|
||||
/**
|
||||
* @brief The URL to the sticker image. This must be a valid mxc:// URI.
|
||||
*/
|
||||
QUrl url() const;
|
||||
|
||||
private:
|
||||
EventContent::ImageContent m_imageContent;
|
||||
};
|
||||
REGISTER_EVENT_TYPE(StickerEvent)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ FileTransferPseudoJob::FileTransferPseudoJob(Operation operation, const QString
|
||||
{
|
||||
}
|
||||
|
||||
void FileTransferPseudoJob::fileTransferProgress(const QString &id, qint64 progress, qint64 total)
|
||||
void FileTransferPseudoJob::fileTransferProgress(QString id, qint64 progress, qint64 total)
|
||||
{
|
||||
if (id != m_eventId) {
|
||||
return;
|
||||
@@ -23,7 +23,7 @@ void FileTransferPseudoJob::fileTransferProgress(const QString &id, qint64 progr
|
||||
setTotalAmount(Unit::Bytes, total);
|
||||
}
|
||||
|
||||
void FileTransferPseudoJob::fileTransferCompleted(const QString &id, const QUrl &localFile)
|
||||
void FileTransferPseudoJob::fileTransferCompleted(QString id, QUrl localFile)
|
||||
{
|
||||
Q_UNUSED(localFile);
|
||||
if (id != m_eventId) {
|
||||
@@ -32,7 +32,7 @@ void FileTransferPseudoJob::fileTransferCompleted(const QString &id, const QUrl
|
||||
emitResult();
|
||||
}
|
||||
|
||||
void FileTransferPseudoJob::fileTransferFailed(const QString &id, const QString &errorMessage)
|
||||
void FileTransferPseudoJob::fileTransferFailed(QString id, QString errorMessage)
|
||||
{
|
||||
if (id != m_eventId) {
|
||||
return;
|
||||
|
||||
@@ -20,23 +20,23 @@ public:
|
||||
Download,
|
||||
Upload,
|
||||
};
|
||||
Q_ENUM(Operation)
|
||||
Q_ENUM(Operation);
|
||||
FileTransferPseudoJob(Operation operation, const QString &srcDest, const QString &path);
|
||||
|
||||
/**
|
||||
* @brief Set the current number of bytes transferred.
|
||||
*/
|
||||
void fileTransferProgress(const QString &id, qint64 progress, qint64 total);
|
||||
void fileTransferProgress(QString id, qint64 progress, qint64 total);
|
||||
|
||||
/**
|
||||
* @brief Set the file transfer as complete.
|
||||
*/
|
||||
void fileTransferCompleted(const QString &id, const QUrl &localFile);
|
||||
void fileTransferCompleted(QString id, QUrl localFile);
|
||||
|
||||
/**
|
||||
* @brief Set the file transfer as failed.
|
||||
*/
|
||||
void fileTransferFailed(const QString &id, const QString &errorMessage = {});
|
||||
void fileTransferFailed(QString id, QString errorMessage = {});
|
||||
|
||||
/**
|
||||
* @brief Start the file transfer.
|
||||
|
||||
@@ -112,5 +112,3 @@ QStringList FileTypeSingleton::supportedAnimatedImageFormats() const
|
||||
Q_D(const FileTypeSingleton);
|
||||
return d->supportedAnimatedImageFormats;
|
||||
}
|
||||
|
||||
#include "moc_filetypesingleton.cpp"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QMimeDatabase>
|
||||
#include <QObject>
|
||||
#include <qqml.h>
|
||||
|
||||
@@ -3,16 +3,14 @@
|
||||
|
||||
#include "linkpreviewer.h"
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/csapi/content-repo.h>
|
||||
#include <connection.h>
|
||||
#include <csapi/content-repo.h>
|
||||
|
||||
#include "neochatroom.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
LinkPreviewer::LinkPreviewer(QObject *parent, NeoChatRoom *room, const QUrl &url)
|
||||
LinkPreviewer::LinkPreviewer(QObject *parent, NeoChatRoom *room, QUrl url)
|
||||
: QObject(parent)
|
||||
, m_currentRoom(room)
|
||||
, m_loaded(false)
|
||||
@@ -71,7 +69,14 @@ void LinkPreviewer::loadUrlPreview()
|
||||
|
||||
auto imageUrl = QUrl(json["og:image"].toString());
|
||||
if (imageUrl.isValid() && imageUrl.scheme() == QStringLiteral("mxc")) {
|
||||
#ifdef QUOTIENT_07
|
||||
m_imageSource = conn->makeMediaUrl(imageUrl);
|
||||
#else
|
||||
QUrlQuery q(imageUrl.query());
|
||||
q.addQueryItem(QStringLiteral("user_id"), conn->userId());
|
||||
imageUrl.setQuery(q);
|
||||
m_imageSource = imageUrl;
|
||||
#endif
|
||||
} else {
|
||||
m_imageSource = QUrl();
|
||||
}
|
||||
@@ -84,5 +89,3 @@ void LinkPreviewer::loadUrlPreview()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_linkpreviewer.cpp"
|
||||
|
||||
@@ -45,7 +45,7 @@ class LinkPreviewer : public QObject
|
||||
Q_PROPERTY(QUrl imageSource READ imageSource NOTIFY imageSourceChanged)
|
||||
|
||||
public:
|
||||
explicit LinkPreviewer(QObject *parent = nullptr, NeoChatRoom *room = nullptr, const QUrl &url = {});
|
||||
explicit LinkPreviewer(QObject *parent = nullptr, NeoChatRoom *room = nullptr, QUrl url = {});
|
||||
|
||||
[[nodiscard]] QUrl url() const;
|
||||
void setUrl(QUrl);
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "locationhelper.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
QRectF LocationHelper::unite(const QRectF &r1, const QRectF &r2)
|
||||
{
|
||||
// this looks weird but is actually intentional as we need to handle point-like "rects" as well
|
||||
if ((!r1.isEmpty() || r1.isNull()) && (!r2.isEmpty() || r2.isNull())) {
|
||||
return r1 | r2;
|
||||
}
|
||||
return (!r1.isEmpty() || r1.isNull()) ? r1 : r2;
|
||||
}
|
||||
|
||||
QPointF LocationHelper::center(const QRectF &r)
|
||||
{
|
||||
return r.center();
|
||||
}
|
||||
|
||||
constexpr inline double degToRad(double deg)
|
||||
{
|
||||
return deg / 180.0 * M_PI;
|
||||
}
|
||||
|
||||
static QPointF mercatorProject(double lat, double lon, double zoom)
|
||||
{
|
||||
const auto x = (256.0 / (2.0 * M_PI)) * std::pow(2.0, zoom) * (degToRad(lon) + M_PI);
|
||||
const auto y = (256.0 / (2.0 * M_PI)) * std::pow(2.0, zoom) * (M_PI - std::log(std::tan(M_PI / 4.0 + degToRad(lat) / 2.0)));
|
||||
return QPointF(x, y);
|
||||
}
|
||||
|
||||
float LocationHelper::zoomToFit(const QRectF &r, float mapWidth, float mapHeight)
|
||||
{
|
||||
const auto p1 = mercatorProject(r.bottomLeft().y(), r.bottomLeft().x(), 1.0);
|
||||
const auto p2 = mercatorProject(r.topRight().y(), r.topRight().x(), 1.0);
|
||||
|
||||
const auto zx = std::log2((mapWidth / (p2.x() - p1.x())));
|
||||
const auto zy = std::log2((mapHeight / (p2.y() - p1.y())));
|
||||
const auto z = std::min(zx, zy);
|
||||
|
||||
return std::clamp(z, 5.0, 18.0);
|
||||
}
|
||||
|
||||
#include "moc_locationhelper.cpp"
|
||||
@@ -1,23 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "linkpreviewer.h"
|
||||
#include <QMetaType>
|
||||
#include <QRectF>
|
||||
|
||||
/** Location related helper functions for QML. */
|
||||
class LocationHelper
|
||||
{
|
||||
Q_GADGET
|
||||
public:
|
||||
/** Unite two rectanlges. */
|
||||
Q_INVOKABLE static QRectF unite(const QRectF &r1, const QRectF &r2);
|
||||
/** Returns the center of @p r. */
|
||||
Q_INVOKABLE static QPointF center(const QRectF &r);
|
||||
|
||||
/** Returns the highest zoom level to fit @r into a map of size @p mapWidth x @p mapHeight. */
|
||||
Q_INVOKABLE static float zoomToFit(const QRectF &r, float mapWidth, float mapHeight);
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(LocationHelper)
|
||||
@@ -131,36 +131,22 @@ public:
|
||||
}
|
||||
auto filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QDir::separator() + appName;
|
||||
|
||||
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QDir::separator());
|
||||
auto entryList = dir.entryList({appName + QStringLiteral(".*")});
|
||||
std::sort(entryList.begin(), entryList.end(), [](const auto &left, const auto &right) {
|
||||
auto leftIndex = left.split(".").last().toInt();
|
||||
auto rightIndex = right.split(".").last().toInt();
|
||||
return leftIndex > rightIndex;
|
||||
});
|
||||
for (const auto &entry : entryList) {
|
||||
bool ok = false;
|
||||
const auto index = entry.split(".").last().toInt(&ok);
|
||||
if (!ok) {
|
||||
continue;
|
||||
QFileInfo infoOld(filePath + QLatin1String(".old"));
|
||||
if (infoOld.exists()) {
|
||||
QFile fileOld(infoOld.absoluteFilePath());
|
||||
const bool success = fileOld.remove();
|
||||
if (!success) {
|
||||
qFatal("Cannot remove old log file '%s': %s", qUtf8Printable(fileOld.fileName()), qUtf8Printable(fileOld.errorString()));
|
||||
}
|
||||
QFileInfo info(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QDir::separator() + entry);
|
||||
if (info.exists()) {
|
||||
QFile file(info.absoluteFilePath());
|
||||
if (index > 50) {
|
||||
file.remove();
|
||||
continue;
|
||||
}
|
||||
const QString newName = filePath + QStringLiteral(".%1").arg(index + 1);
|
||||
const bool success = file.copy(newName);
|
||||
if (success) {
|
||||
file.remove();
|
||||
} else {
|
||||
qFatal("Cannot rename log file '%s' to '%s': %s",
|
||||
qUtf8Printable(file.fileName()),
|
||||
qUtf8Printable(newName),
|
||||
qUtf8Printable(file.errorString()));
|
||||
}
|
||||
}
|
||||
|
||||
QFileInfo info(filePath);
|
||||
if (info.exists()) {
|
||||
QFile file(info.absoluteFilePath());
|
||||
const QString oldName = filePath + QLatin1String(".old");
|
||||
const bool success = file.copy(oldName);
|
||||
if (!success) {
|
||||
qFatal("Cannot rename log file '%s' to '%s': %s", qUtf8Printable(file.fileName()), qUtf8Printable(oldName), qUtf8Printable(file.errorString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +154,7 @@ public:
|
||||
if (!finfo.absoluteDir().exists()) {
|
||||
QDir().mkpath(finfo.absolutePath());
|
||||
}
|
||||
file.setFileName(filePath + QStringLiteral(".0"));
|
||||
file.setFileName(filePath);
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Unbuffered);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
|
||||
#include "login.h"
|
||||
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/qt_connection_util.h>
|
||||
#ifdef QUOTIENT_07
|
||||
#include <accountregistry.h>
|
||||
#else
|
||||
#include "neochataccountregistry.h"
|
||||
#endif
|
||||
|
||||
#include <connection.h>
|
||||
#include <qt_connection_util.h>
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
@@ -33,16 +38,12 @@ void Login::init()
|
||||
|
||||
connect(this, &Login::matrixIdChanged, this, [this]() {
|
||||
setHomeserverReachable(false);
|
||||
QRegularExpression validator("^\\@?[a-zA-Z0-9\\._=\\-/]+\\:[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)*(\\:[0-9]+)?$");
|
||||
if (!validator.match(m_matrixId).hasMatch()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_matrixId == "@") {
|
||||
return;
|
||||
}
|
||||
|
||||
m_isLoggedIn = Controller::instance().accounts().isLoggedIn(m_matrixId);
|
||||
m_isLoggedIn = AccountRegistry::instance().isLoggedIn(m_matrixId);
|
||||
Q_EMIT isLoggedInChanged();
|
||||
if (m_isLoggedIn) {
|
||||
return;
|
||||
@@ -96,7 +97,7 @@ void Login::init()
|
||||
Q_EMIT Controller::instance().globalErrorOccured(i18n("Network Error"), std::move(error));
|
||||
});
|
||||
|
||||
connectSingleShot(m_connection, &Connection::syncDone, this, []() {
|
||||
connectSingleShot(m_connection, &Connection::syncDone, this, [this]() {
|
||||
Q_EMIT Controller::instance().initiated();
|
||||
});
|
||||
}
|
||||
@@ -198,5 +199,3 @@ bool Login::isLoggedIn() const
|
||||
{
|
||||
return m_isLoggedIn;
|
||||
}
|
||||
|
||||
#include "moc_login.cpp"
|
||||
|
||||
@@ -112,7 +112,7 @@ Q_SIGNALS:
|
||||
void loginFlowsChanged();
|
||||
void ssoUrlChanged();
|
||||
void connected();
|
||||
void errorOccured(const QString &message);
|
||||
void errorOccured(QString message);
|
||||
void testingChanged();
|
||||
void isLoggingInChanged();
|
||||
void isLoggedInChanged();
|
||||
|
||||
76
src/main.cpp
76
src/main.cpp
@@ -28,47 +28,40 @@
|
||||
|
||||
#include "neochat-version.h"
|
||||
|
||||
#include <Quotient/keyverificationsession.h>
|
||||
#include <Quotient/accountregistry.h>
|
||||
#include <Quotient/networkaccessmanager.h>
|
||||
#include <Quotient/room.h>
|
||||
#include <Quotient/util.h>
|
||||
#ifdef QUOTIENT_07
|
||||
#include <accountregistry.h>
|
||||
#else
|
||||
#include "neochataccountregistry.h"
|
||||
#endif
|
||||
|
||||
#include <networkaccessmanager.h>
|
||||
#include <room.h>
|
||||
#include <util.h>
|
||||
|
||||
#include "actionshandler.h"
|
||||
#include "blurhashimageprovider.h"
|
||||
#include "chatdocumenthandler.h"
|
||||
#include "clipboard.h"
|
||||
#include "controller.h"
|
||||
#include "delegatesizehelper.h"
|
||||
#include "filetypesingleton.h"
|
||||
#include "linkpreviewer.h"
|
||||
#include "locationhelper.h"
|
||||
#include "logger.h"
|
||||
#include "login.h"
|
||||
#include "matriximageprovider.h"
|
||||
#include "models/accountemoticonmodel.h"
|
||||
#include "models/collapsestateproxymodel.h"
|
||||
#include "models/customemojimodel.h"
|
||||
#include "models/devicesmodel.h"
|
||||
#include "models/devicesproxymodel.h"
|
||||
#include "models/emojimodel.h"
|
||||
#include "models/emoticonfiltermodel.h"
|
||||
#include "models/imagepacksmodel.h"
|
||||
#include "models/livelocationsmodel.h"
|
||||
#include "models/locationsmodel.h"
|
||||
#include "models/mediamessagefiltermodel.h"
|
||||
#include "models/keywordnotificationrulemodel.h"
|
||||
#include "models/messageeventmodel.h"
|
||||
#include "models/messagefiltermodel.h"
|
||||
#include "models/publicroomlistmodel.h"
|
||||
#include "models/pushrulemodel.h"
|
||||
#include "models/reactionmodel.h"
|
||||
#include "models/roomlistmodel.h"
|
||||
#include "models/searchmodel.h"
|
||||
#include "models/serverlistmodel.h"
|
||||
#include "models/sortfilterroomlistmodel.h"
|
||||
#include "models/sortfilterspacelistmodel.h"
|
||||
#include "models/statefiltermodel.h"
|
||||
#include "models/stickermodel.h"
|
||||
#include "models/userdirectorylistmodel.h"
|
||||
#include "models/userfiltermodel.h"
|
||||
#include "models/userlistmodel.h"
|
||||
@@ -77,12 +70,18 @@
|
||||
#include "neochatroom.h"
|
||||
#include "neochatuser.h"
|
||||
#include "notificationsmanager.h"
|
||||
#ifdef QUOTIENT_07
|
||||
#include "pollhandler.h"
|
||||
#endif
|
||||
#include "models/statefiltermodel.h"
|
||||
#include "models/stickermodel.h"
|
||||
#include "roommanager.h"
|
||||
#include "spacehierarchycache.h"
|
||||
#include "urlhelper.h"
|
||||
#include "windowcontroller.h"
|
||||
|
||||
#ifdef QUOTIENT_07
|
||||
#include <keyverificationsession.h>
|
||||
#endif
|
||||
#ifdef HAVE_COLORSCHEME
|
||||
#include "colorschemer.h"
|
||||
#endif
|
||||
@@ -122,9 +121,7 @@ Q_DECL_EXPORT
|
||||
#endif
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#endif
|
||||
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
|
||||
@@ -161,7 +158,7 @@ int main(int argc, char *argv[])
|
||||
QStringLiteral(NEOCHAT_VERSION_STRING),
|
||||
i18n("Matrix client"),
|
||||
KAboutLicense::GPL_V3,
|
||||
i18n("© 2018-2020 Black Hat, 2020-2023 KDE Community"));
|
||||
i18n("© 2018-2020 Black Hat, 2020-2022 KDE Community"));
|
||||
about.addAuthor(i18n("Carl Schwan"), i18n("Maintainer"), QStringLiteral("carl@carlschwan.eu"), QStringLiteral("https://carlschwan.eu"));
|
||||
about.addAuthor(i18n("Tobias Fella"), i18n("Maintainer"), QStringLiteral("tobias.fella@kde.org"), QStringLiteral("https://tobiasfella.de"));
|
||||
about.addAuthor(i18n("James Graham"), i18n("Maintainer"), QStringLiteral("james.h.graham@protonmail.com"));
|
||||
@@ -172,10 +169,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
about.addComponent(QStringLiteral("libQuotient"),
|
||||
i18n("A Qt5 library to write cross-platform clients for Matrix"),
|
||||
#ifdef QUOTIENT_07
|
||||
i18nc("<version number> (built against <possibly different version number>)",
|
||||
"%1 (built against %2)",
|
||||
Quotient::versionString(),
|
||||
QStringLiteral(Quotient_VERSION_STRING)),
|
||||
#else
|
||||
QStringLiteral(QUOTIENT_VERSION),
|
||||
#endif
|
||||
QStringLiteral("https://github.com/quotient-im/libquotient"),
|
||||
KAboutLicense::LGPL_V2_1);
|
||||
|
||||
@@ -184,12 +185,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
initLogging();
|
||||
|
||||
#if Quotient_VERSION_MINOR == 8
|
||||
#ifdef Quotient_E2EE_ENABLED
|
||||
Connection::setEncryptionDefault(true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NEOCHAT_FLATPAK
|
||||
// Copy over the included FontConfig configuration to the
|
||||
// app's config dir:
|
||||
@@ -220,7 +215,11 @@ int main(int argc, char *argv[])
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "LoginHelper", login);
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "UrlHelper", &urlHelper);
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "EmojiModel", &EmojiModel::instance());
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "AccountRegistry", &Controller::instance().accounts());
|
||||
#ifdef QUOTIENT_07
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "AccountRegistry", &Quotient::Accounts);
|
||||
#else
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "AccountRegistry", &Quotient::AccountRegistry::instance());
|
||||
#endif
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "SpaceHierarchyCache", &SpaceHierarchyCache::instance());
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "CustomEmojiModel", &CustomEmojiModel::instance());
|
||||
qmlRegisterType<ActionsHandler>("org.kde.neochat", 1, 0, "ActionsHandler");
|
||||
@@ -229,9 +228,7 @@ int main(int argc, char *argv[])
|
||||
qmlRegisterType<KWebShortcutModel>("org.kde.neochat", 1, 0, "WebShortcutModel");
|
||||
qmlRegisterType<UserListModel>("org.kde.neochat", 1, 0, "UserListModel");
|
||||
qmlRegisterType<MessageEventModel>("org.kde.neochat", 1, 0, "MessageEventModel");
|
||||
qmlRegisterType<ReactionModel>("org.kde.neochat", 1, 0, "ReactionModel");
|
||||
qmlRegisterType<CollapseStateProxyModel>("org.kde.neochat", 1, 0, "CollapseStateProxyModel");
|
||||
qmlRegisterType<MediaMessageFilterModel>("org.kde.neochat", 1, 0, "MediaMessageFilterModel");
|
||||
qmlRegisterType<MessageFilterModel>("org.kde.neochat", 1, 0, "MessageFilterModel");
|
||||
qmlRegisterType<UserFilterModel>("org.kde.neochat", 1, 0, "UserFilterModel");
|
||||
qmlRegisterType<PublicRoomListModel>("org.kde.neochat", 1, 0, "PublicRoomListModel");
|
||||
@@ -240,29 +237,22 @@ int main(int argc, char *argv[])
|
||||
qmlRegisterType<SortFilterRoomListModel>("org.kde.neochat", 1, 0, "SortFilterRoomListModel");
|
||||
qmlRegisterType<SortFilterSpaceListModel>("org.kde.neochat", 1, 0, "SortFilterSpaceListModel");
|
||||
qmlRegisterType<DevicesModel>("org.kde.neochat", 1, 0, "DevicesModel");
|
||||
qmlRegisterType<DevicesProxyModel>("org.kde.neochat", 1, 0, "DevicesProxyModel");
|
||||
qmlRegisterType<LinkPreviewer>("org.kde.neochat", 1, 0, "LinkPreviewer");
|
||||
qmlRegisterType<CompletionModel>("org.kde.neochat", 1, 0, "CompletionModel");
|
||||
qmlRegisterType<StateModel>("org.kde.neochat", 1, 0, "StateModel");
|
||||
qmlRegisterType<StateFilterModel>("org.kde.neochat", 1, 0, "StateFilterModel");
|
||||
qmlRegisterType<SearchModel>("org.kde.neochat", 1, 0, "SearchModel");
|
||||
qmlRegisterType<LiveLocationsModel>("org.kde.neochat", 1, 0, "LiveLocationsModel");
|
||||
qmlRegisterType<LocationsModel>("org.kde.neochat", 1, 0, "LocationsModel");
|
||||
#ifdef QUOTIENT_07
|
||||
qmlRegisterType<PollHandler>("org.kde.neochat", 1, 0, "PollHandler");
|
||||
qmlRegisterType<PushRuleModel>("org.kde.neochat", 1, 0, "PushRuleModel");
|
||||
#endif
|
||||
qmlRegisterType<KeywordNotificationRuleModel>("org.kde.neochat", 1, 0, "KeywordNotificationRuleModel");
|
||||
qmlRegisterType<StickerModel>("org.kde.neochat", 1, 0, "StickerModel");
|
||||
qmlRegisterType<ImagePacksModel>("org.kde.neochat", 1, 0, "ImagePacksModel");
|
||||
qmlRegisterType<AccountEmoticonModel>("org.kde.neochat", 1, 0, "AccountEmoticonModel");
|
||||
qmlRegisterType<EmoticonFilterModel>("org.kde.neochat", 1, 0, "EmoticonFilterModel");
|
||||
qmlRegisterType<DelegateSizeHelper>("org.kde.neochat", 1, 0, "DelegateSizeHelper");
|
||||
qmlRegisterUncreatableType<RoomMessageEvent>("org.kde.neochat", 1, 0, "RoomMessageEvent", "ENUM");
|
||||
qmlRegisterUncreatableType<PushNotificationKind>("org.kde.neochat", 1, 0, "PushNotificationKind", "ENUM");
|
||||
qmlRegisterUncreatableType<PushNotificationSection>("org.kde.neochat", 1, 0, "PushNotificationSection", "ENUM");
|
||||
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<NeoChatRoom>("org.kde.neochat", 1, 0, "NeoChatRoom", {});
|
||||
|
||||
qRegisterMetaType<User *>("User*");
|
||||
qRegisterMetaType<User *>("const User*");
|
||||
@@ -274,18 +264,16 @@ int main(int argc, char *argv[])
|
||||
qRegisterMetaType<NeoChatUser *>("NeoChatUser*");
|
||||
qRegisterMetaType<GetRoomEventsJob *>("GetRoomEventsJob*");
|
||||
qRegisterMetaType<QMimeType>("QMimeType");
|
||||
#ifdef QUOTIENT_07
|
||||
#ifdef Quotient_E2EE_ENABLED
|
||||
qRegisterMetaType<KeyVerificationSession *>("KeyVerificationSession*");
|
||||
qmlRegisterUncreatableType<KeyVerificationSession>("org.kde.neochat", 1, 0, "KeyVerificationSession", {});
|
||||
qRegisterMetaType<QVector<EmojiEntry>>("QVector<EmojiEntry>");
|
||||
#endif
|
||||
#endif
|
||||
qmlRegisterSingletonType("org.kde.neochat", 1, 0, "About", [](QQmlEngine *engine, QJSEngine *) -> QJSValue {
|
||||
return engine->toScriptValue(KAboutData::applicationData());
|
||||
});
|
||||
qmlRegisterSingletonType(QUrl("qrc:/OsmLocationPlugin.qml"), "org.kde.neochat", 1, 0, "OsmLocationPlugin");
|
||||
qmlRegisterSingletonType("org.kde.neochat", 1, 0, "LocationHelper", [](QQmlEngine *engine, QJSEngine *) -> QJSValue {
|
||||
return engine->toScriptValue(LocationHelper());
|
||||
});
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
qRegisterMetaTypeStreamOperators<Emoji>();
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "controller.h"
|
||||
#include <Quotient/connection.h>
|
||||
#include <connection.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
@@ -32,17 +32,11 @@ ThumbnailResponse::ThumbnailResponse(QString id, QSize size)
|
||||
requestedSize.setWidth(100);
|
||||
}
|
||||
if (mediaId.count('/') != 1) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
@@ -120,5 +114,3 @@ QQuickImageResponse *MatrixImageProvider::requestImageResponse(const QString &id
|
||||
{
|
||||
return new ThumbnailResponse(id, requestedSize);
|
||||
}
|
||||
|
||||
#include "moc_matriximageprovider.cpp"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <QQuickAsyncImageProvider>
|
||||
|
||||
#include <Quotient/jobs/mediathumbnailjob.h>
|
||||
#include <jobs/mediathumbnailjob.h>
|
||||
|
||||
#include <QReadWriteLock>
|
||||
|
||||
@@ -26,7 +26,7 @@ class ThumbnailResponse : public QQuickImageResponse
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ThumbnailResponse(QString mediaId, QSize requestedSize);
|
||||
ThumbnailResponse(QString mediaId, QSize requestedSize);
|
||||
~ThumbnailResponse() override = default;
|
||||
|
||||
private Q_SLOTS:
|
||||
@@ -34,7 +34,7 @@ private Q_SLOTS:
|
||||
void prepareResult();
|
||||
|
||||
private:
|
||||
QString mediaId;
|
||||
const QString mediaId;
|
||||
QSize requestedSize;
|
||||
const QString localFile;
|
||||
Quotient::MediaThumbnailJob *job = nullptr;
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2021-2023 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "accountemoticonmodel.h"
|
||||
|
||||
#include <Quotient/csapi/content-repo.h>
|
||||
#include <qcoro/qcorosignal.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
AccountEmoticonModel::AccountEmoticonModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int AccountEmoticonModel::rowCount(const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
if (!m_images) {
|
||||
return 0;
|
||||
}
|
||||
return m_images->images.size();
|
||||
}
|
||||
|
||||
QVariant AccountEmoticonModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
const auto &row = index.row();
|
||||
const auto &image = m_images->images[row];
|
||||
if (role == UrlRole) {
|
||||
return m_connection->makeMediaUrl(image.url);
|
||||
}
|
||||
if (role == BodyRole) {
|
||||
if (image.body) {
|
||||
return *image.body;
|
||||
}
|
||||
}
|
||||
if (role == ShortCodeRole) {
|
||||
return image.shortcode;
|
||||
}
|
||||
if (role == IsStickerRole) {
|
||||
if (image.usage) {
|
||||
return image.usage->isEmpty() || image.usage->contains("sticker"_ls);
|
||||
}
|
||||
if (m_images->pack && m_images->pack->usage) {
|
||||
return m_images->pack->usage->isEmpty() || m_images->pack->usage->contains("sticker"_ls);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (role == IsEmojiRole) {
|
||||
if (image.usage) {
|
||||
return image.usage->isEmpty() || image.usage->contains("emoticon"_ls);
|
||||
}
|
||||
if (m_images->pack && m_images->pack->usage) {
|
||||
return m_images->pack->usage->isEmpty() || m_images->pack->usage->contains("emoticon"_ls);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> AccountEmoticonModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{AccountEmoticonModel::UrlRole, "url"},
|
||||
{AccountEmoticonModel::BodyRole, "body"},
|
||||
{AccountEmoticonModel::ShortCodeRole, "shortcode"},
|
||||
{AccountEmoticonModel::IsStickerRole, "isSticker"},
|
||||
{AccountEmoticonModel::IsEmojiRole, "isEmoji"},
|
||||
};
|
||||
}
|
||||
|
||||
Connection *AccountEmoticonModel::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void AccountEmoticonModel::setConnection(Connection *connection)
|
||||
{
|
||||
if (m_connection) {
|
||||
disconnect(m_connection, nullptr, this, nullptr);
|
||||
}
|
||||
|
||||
m_connection = connection;
|
||||
Q_EMIT connectionChanged();
|
||||
connect(m_connection, &Connection::accountDataChanged, this, [this](QString type) {
|
||||
if (type == QStringLiteral("im.ponies.user_emotes")) {
|
||||
reloadEmoticons();
|
||||
}
|
||||
});
|
||||
reloadEmoticons();
|
||||
}
|
||||
|
||||
void AccountEmoticonModel::reloadEmoticons()
|
||||
{
|
||||
QJsonObject json;
|
||||
if (m_connection->hasAccountData("im.ponies.user_emotes"_ls)) {
|
||||
json = m_connection->accountData("im.ponies.user_emotes"_ls)->contentJson();
|
||||
}
|
||||
const auto &content = ImagePackEventContent(json);
|
||||
beginResetModel();
|
||||
m_images = content;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void AccountEmoticonModel::deleteEmoticon(int index)
|
||||
{
|
||||
QJsonObject data;
|
||||
m_images->images.removeAt(index);
|
||||
m_images->fillJson(&data);
|
||||
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
|
||||
}
|
||||
|
||||
void AccountEmoticonModel::setEmoticonBody(int index, const QString &text)
|
||||
{
|
||||
m_images->images[index].body = text;
|
||||
QJsonObject data;
|
||||
m_images->fillJson(&data);
|
||||
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
|
||||
}
|
||||
|
||||
void AccountEmoticonModel::setEmoticonShortcode(int index, const QString &shortcode)
|
||||
{
|
||||
m_images->images[index].shortcode = shortcode;
|
||||
QJsonObject data;
|
||||
m_images->fillJson(&data);
|
||||
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
|
||||
}
|
||||
|
||||
void AccountEmoticonModel::setEmoticonImage(int index, const QUrl &source)
|
||||
{
|
||||
doSetEmoticonImage(index, source);
|
||||
}
|
||||
|
||||
QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl source)
|
||||
{
|
||||
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||
co_await qCoro(job, &BaseJob::finished);
|
||||
if (job->error() != BaseJob::NoError) {
|
||||
co_return;
|
||||
}
|
||||
m_images->images[index].url = job->contentUri().toString();
|
||||
m_images->images[index].info = none;
|
||||
QJsonObject data;
|
||||
m_images->fillJson(&data);
|
||||
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
|
||||
}
|
||||
|
||||
QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString shortcode, QString description, QString type)
|
||||
{
|
||||
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
|
||||
co_await qCoro(job, &BaseJob::finished);
|
||||
if (job->error() != BaseJob::NoError) {
|
||||
co_return;
|
||||
}
|
||||
m_images->images.append(ImagePackEventContent::ImagePackImage{
|
||||
shortcode,
|
||||
job->contentUri(),
|
||||
description,
|
||||
none,
|
||||
QStringList{type},
|
||||
});
|
||||
QJsonObject data;
|
||||
m_images->fillJson(&data);
|
||||
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
|
||||
}
|
||||
|
||||
void AccountEmoticonModel::addEmoticon(const QUrl &source, const QString &shortcode, const QString &description, const QString &type)
|
||||
{
|
||||
doAddEmoticon(source, shortcode, description, type);
|
||||
}
|
||||
|
||||
#include "moc_accountemoticonmodel.cpp"
|
||||
@@ -1,103 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "events/imagepackevent.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QCoroTask>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QVector>
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
|
||||
class ImagePacksModel;
|
||||
|
||||
/**
|
||||
* @class AccountEmoticonModel
|
||||
*
|
||||
* This class defines the model for visualising the account stickers and emojis.
|
||||
*
|
||||
* This is based upon the im.ponies.user_emotes spec (MSC2545).
|
||||
*/
|
||||
class AccountEmoticonModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
/**
|
||||
* @brief The connection to get emoticons from.
|
||||
*/
|
||||
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
UrlRole = Qt::UserRole + 1, /**< The URL for the emoticon. */
|
||||
ShortCodeRole, /**< The shortcode for the emoticon. */
|
||||
BodyRole, //**< A textual description of the emoticon */
|
||||
IsStickerRole, //**< Whether this emoticon is a sticker */
|
||||
IsEmojiRole, //**< Whether this emoticon is an emoji */
|
||||
};
|
||||
|
||||
explicit AccountEmoticonModel(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Number of rows in the model.
|
||||
*
|
||||
* @sa QAbstractItemModel::rowCount
|
||||
*/
|
||||
[[nodiscard]] int rowCount(const QModelIndex &index) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the given role value at the given index.
|
||||
*
|
||||
* @sa QAbstractItemModel::data
|
||||
*/
|
||||
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
/**
|
||||
* @brief Returns a mapping from Role enum values to role names.
|
||||
*
|
||||
* @sa Roles, QAbstractItemModel::roleNames()
|
||||
*/
|
||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
[[nodiscard]] Quotient::Connection *connection() const;
|
||||
void setConnection(Quotient::Connection *connection);
|
||||
|
||||
/**
|
||||
* @brief Deletes the emoticon at the given index.
|
||||
*/
|
||||
Q_INVOKABLE void deleteEmoticon(int index);
|
||||
|
||||
/**
|
||||
* @brief Changes the description for the emoticon at the given index.
|
||||
*/
|
||||
Q_INVOKABLE void setEmoticonBody(int index, const QString &text);
|
||||
|
||||
/**
|
||||
* @brief Changes the shortcode for the emoticon at the given index.
|
||||
*/
|
||||
Q_INVOKABLE void setEmoticonShortcode(int index, const QString &shortCode);
|
||||
|
||||
/**
|
||||
* @brief Changes the image for the emoticon at the given index.
|
||||
*/
|
||||
Q_INVOKABLE void setEmoticonImage(int index, const QUrl &source);
|
||||
|
||||
/**
|
||||
* @brief Add an emoticon with the given parameters.
|
||||
*/
|
||||
Q_INVOKABLE void addEmoticon(const QUrl &source, const QString &shortcode, const QString &description, const QString &type);
|
||||
|
||||
Q_SIGNALS:
|
||||
void connectionChanged();
|
||||
|
||||
private:
|
||||
std::optional<Quotient::ImagePackEventContent> m_images;
|
||||
QPointer<Quotient::Connection> m_connection;
|
||||
QCoro::Task<void> doSetEmoticonImage(int index, QUrl source);
|
||||
QCoro::Task<void> doAddEmoticon(QUrl source, QString shortcode, QString description, QString type);
|
||||
|
||||
void reloadEmoticons();
|
||||
};
|
||||
@@ -6,8 +6,8 @@
|
||||
#include "controller.h"
|
||||
#include "neochatroom.h"
|
||||
#include "roommanager.h"
|
||||
#include <Quotient/events/roommemberevent.h>
|
||||
#include <Quotient/events/roompowerlevelsevent.h>
|
||||
#include <events/roommemberevent.h>
|
||||
#include <events/roompowerlevelsevent.h>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
@@ -191,6 +191,7 @@ QVector<ActionsModel::Action> actions{
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", text));
|
||||
return QString();
|
||||
}
|
||||
#ifdef QUOTIENT_07
|
||||
const RoomMemberEvent *roomMemberEvent = room->currentState().get<RoomMemberEvent>(text);
|
||||
if (roomMemberEvent && roomMemberEvent->membership() == Membership::Invite) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already invited to this room.", "%1 is already invited to this room.", text));
|
||||
@@ -200,6 +201,7 @@ QVector<ActionsModel::Action> actions{
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is banned from this room.", "%1 is banned from this room.", text));
|
||||
return QString();
|
||||
}
|
||||
#endif
|
||||
if (room->localUser()->id() == text) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18n("You are already in this room."));
|
||||
return QString();
|
||||
@@ -241,6 +243,7 @@ QVector<ActionsModel::Action> actions{
|
||||
kli18n("<room alias or id>"),
|
||||
kli18n("Joins the given room"),
|
||||
},
|
||||
#ifdef QUOTIENT_07
|
||||
Action{
|
||||
QStringLiteral("knock"),
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
@@ -273,6 +276,7 @@ QVector<ActionsModel::Action> actions{
|
||||
kli18n("<room alias or id> [<reason>]"),
|
||||
kli18n("Requests to join the given room"),
|
||||
},
|
||||
#endif
|
||||
Action{
|
||||
QStringLiteral("j"),
|
||||
[](const QString &text, NeoChatRoom *room) {
|
||||
@@ -431,15 +435,14 @@ QVector<ActionsModel::Action> actions{
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", text));
|
||||
return QString();
|
||||
}
|
||||
#ifdef QUOTIENT_07
|
||||
auto state = room->currentState().get<RoomMemberEvent>(parts[0]);
|
||||
if (state && state->membership() == Membership::Ban) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already banned from this room.", "%1 is already banned from this room.", text));
|
||||
return QString();
|
||||
}
|
||||
auto plEvent = room->currentState().get<RoomPowerLevelsEvent>();
|
||||
if (!plEvent) {
|
||||
return QString();
|
||||
}
|
||||
#endif
|
||||
auto plEvent = room->getCurrentState<RoomPowerLevelsEvent>();
|
||||
if (plEvent->ban() > plEvent->powerLevelForUser(room->localUser()->id())) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to ban users from this room."));
|
||||
return QString();
|
||||
@@ -469,19 +472,18 @@ QVector<ActionsModel::Action> actions{
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", text));
|
||||
return QString();
|
||||
}
|
||||
auto plEvent = room->currentState().get<RoomPowerLevelsEvent>();
|
||||
if (!plEvent) {
|
||||
return QString();
|
||||
}
|
||||
auto plEvent = room->getCurrentState<RoomPowerLevelsEvent>();
|
||||
if (plEvent->ban() > plEvent->powerLevelForUser(room->localUser()->id())) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to unban users from this room."));
|
||||
return QString();
|
||||
}
|
||||
#ifdef QUOTIENT_07
|
||||
auto state = room->currentState().get<RoomMemberEvent>(text);
|
||||
if (state && state->membership() != Membership::Ban) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is not banned from this room.", "%1 is not banned from this room.", text));
|
||||
return QString();
|
||||
}
|
||||
#endif
|
||||
room->unban(text);
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> was unbanned from this room.", "%1 was unbanned from this room.", text));
|
||||
|
||||
@@ -508,14 +510,13 @@ QVector<ActionsModel::Action> actions{
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You cannot kick yourself from the room."));
|
||||
return QString();
|
||||
}
|
||||
#ifdef QUOTIENT_07
|
||||
if (!room->isMember(parts[0])) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("<username> is not in this room", "%1 is not in this room.", parts[0]));
|
||||
return QString();
|
||||
}
|
||||
auto plEvent = room->currentState().get<RoomPowerLevelsEvent>();
|
||||
if (!plEvent) {
|
||||
return QString();
|
||||
}
|
||||
#endif
|
||||
auto plEvent = room->getCurrentState<RoomPowerLevelsEvent>();
|
||||
auto kick = plEvent->kick();
|
||||
if (plEvent->powerLevelForUser(room->localUser()->id()) < kick) {
|
||||
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to kick users from this room."));
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <KLazyLocalizedString>
|
||||
#include <QAbstractListModel>
|
||||
#include <Quotient/events/roommessageevent.h>
|
||||
#include <events/roommessageevent.h>
|
||||
|
||||
class NeoChatRoom;
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
CompletionType, /**< The completion type (always "action" for this model). */
|
||||
Parameters, /**< The input parameters expected by the action. */
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
Q_ENUM(Roles);
|
||||
|
||||
/**
|
||||
* @brief Get the given role value at the given index.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
#include "collapsestateproxymodel.h"
|
||||
#include "messageeventmodel.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
@@ -10,9 +11,8 @@ bool CollapseStateProxyModel::filterAcceptsRow(int source_row, const QModelIndex
|
||||
Q_UNUSED(source_parent);
|
||||
return sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If this is not a state, show it
|
||||
|| (source_row < sourceModel()->rowCount() - 1
|
||||
&& sourceModel()->data(sourceModel()->index(source_row + 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State) // If this is the first state in a block, show it. TODO hidden events?
|
||||
|| sourceModel()->data(sourceModel()->index(source_row + 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If this is the first state in a block, show it. TODO hidden events?
|
||||
|| sourceModel()->data(sourceModel()->index(source_row, 0), MessageEventModel::ShowSectionRole).toBool(); // If it's a new day, show it
|
||||
}
|
||||
|
||||
@@ -50,11 +50,10 @@ QString CollapseStateProxyModel::aggregateEventToString(int sourceRow) const
|
||||
if (!uniqueAuthors.contains(nextAuthor)) {
|
||||
uniqueAuthors.append(nextAuthor);
|
||||
}
|
||||
if (i > 0
|
||||
&& (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
)) {
|
||||
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +80,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().toHtmlEscaped());
|
||||
uniqueAuthors[0].toMap()["displayName"].toString());
|
||||
text += userText;
|
||||
text += chunks.takeFirst();
|
||||
|
||||
@@ -109,11 +108,10 @@ QVariantList CollapseStateProxyModel::stateEventsList(int sourceRow) const
|
||||
{"text", sourceModel()->data(sourceModel()->index(i, 0), Qt::DisplayRole).toString()},
|
||||
};
|
||||
stateEvents.append(nextState);
|
||||
if (i > 0
|
||||
&& (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
)) {
|
||||
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -128,11 +126,10 @@ QVariantList CollapseStateProxyModel::authorList(int sourceRow) const
|
||||
if (!uniqueAuthors.contains(nextAvatar)) {
|
||||
uniqueAuthors.append(nextAvatar);
|
||||
}
|
||||
if (i > 0
|
||||
&& (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
)) {
|
||||
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -151,11 +148,10 @@ QString CollapseStateProxyModel::excessAuthors(int row) const
|
||||
if (!uniqueAuthors.contains(nextAvatar)) {
|
||||
uniqueAuthors.append(nextAvatar);
|
||||
}
|
||||
if (i > 0
|
||||
&& (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
)) {
|
||||
if (sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::DelegateTypeRole)
|
||||
!= MessageEventModel::DelegateType::State // If it's not a state event
|
||||
|| sourceModel()->data(sourceModel()->index(i - 1, 0), MessageEventModel::ShowSectionRole).toBool() // or the section needs to be visible
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -173,5 +169,3 @@ QString CollapseStateProxyModel::excessAuthors(int row) const
|
||||
return QStringLiteral("+ %1").arg(excessAuthors);
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_collapsestateproxymodel.cpp"
|
||||
|
||||
@@ -27,7 +27,6 @@ public:
|
||||
StateEventsRole, /**< List of state events in the aggregated state. */
|
||||
AuthorListRole, /**< List of the first 5 unique authors of the aggregated state event. */
|
||||
ExcessAuthorsRole, /**< The number of unique authors beyond the first 5. */
|
||||
LastRole, // Keep this last
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 == DisplayNameRole) {
|
||||
return m_filterModel->data(filterIndex, UserListModel::DisplayNameRole);
|
||||
if (role == Text) {
|
||||
return m_filterModel->data(filterIndex, UserListModel::NameRole);
|
||||
}
|
||||
if (role == SubtitleRole) {
|
||||
if (role == Subtitle) {
|
||||
return m_filterModel->data(filterIndex, UserListModel::UserIdRole);
|
||||
}
|
||||
if (role == IconNameRole) {
|
||||
if (role == Icon) {
|
||||
return m_filterModel->data(filterIndex, UserListModel::AvatarRole);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_autoCompletionType == Command) {
|
||||
if (role == DisplayNameRole) {
|
||||
if (role == Text) {
|
||||
return m_filterModel->data(filterIndex, ActionsModel::Prefix).toString() + QStringLiteral(" ")
|
||||
+ m_filterModel->data(filterIndex, ActionsModel::Parameters).toString();
|
||||
}
|
||||
if (role == SubtitleRole) {
|
||||
if (role == Subtitle) {
|
||||
return m_filterModel->data(filterIndex, ActionsModel::Description);
|
||||
}
|
||||
if (role == IconNameRole) {
|
||||
if (role == Icon) {
|
||||
return QStringLiteral("invalid");
|
||||
}
|
||||
if (role == ReplacedTextRole) {
|
||||
if (role == ReplacedText) {
|
||||
return m_filterModel->data(filterIndex, ActionsModel::Prefix);
|
||||
}
|
||||
}
|
||||
if (m_autoCompletionType == Room) {
|
||||
if (role == DisplayNameRole) {
|
||||
if (role == Text) {
|
||||
return m_filterModel->data(filterIndex, RoomListModel::DisplayNameRole);
|
||||
}
|
||||
if (role == SubtitleRole) {
|
||||
if (role == Subtitle) {
|
||||
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
|
||||
}
|
||||
if (role == IconNameRole) {
|
||||
if (role == Icon) {
|
||||
return m_filterModel->data(filterIndex, RoomListModel::AvatarRole);
|
||||
}
|
||||
}
|
||||
if (m_autoCompletionType == Emoji) {
|
||||
if (role == DisplayNameRole) {
|
||||
if (role == Text) {
|
||||
return m_filterModel->data(filterIndex, CustomEmojiModel::DisplayRole);
|
||||
}
|
||||
if (role == IconNameRole) {
|
||||
if (role == Icon) {
|
||||
return m_filterModel->data(filterIndex, CustomEmojiModel::MxcUrl);
|
||||
}
|
||||
if (role == ReplacedTextRole) {
|
||||
if (role == ReplacedText) {
|
||||
return m_filterModel->data(filterIndex, CustomEmojiModel::ReplacedTextRole);
|
||||
}
|
||||
if (role == SubtitleRole) {
|
||||
if (role == Subtitle) {
|
||||
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 {
|
||||
{DisplayNameRole, "displayName"},
|
||||
{SubtitleRole, "subtitle"},
|
||||
{IconNameRole, "iconName"},
|
||||
{ReplacedTextRole, "replacedText"},
|
||||
{Text, "text"},
|
||||
{Subtitle, "subtitle"},
|
||||
{Icon, "icon"},
|
||||
{ReplacedText, "replacedText"},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ void CompletionModel::updateCompletion()
|
||||
if (text().startsWith(QLatin1Char('@'))) {
|
||||
m_filterModel->setSourceModel(m_userListModel);
|
||||
m_filterModel->setFilterRole(UserListModel::UserIdRole);
|
||||
m_filterModel->setSecondaryFilterRole(UserListModel::DisplayNameRole);
|
||||
m_filterModel->setSecondaryFilterRole(UserListModel::NameRole);
|
||||
m_filterModel->setFullText(m_fullText);
|
||||
m_filterModel->setFilterText(m_text);
|
||||
m_autoCompletionType = User;
|
||||
@@ -193,5 +193,3 @@ void CompletionModel::setRoomListModel(RoomListModel *roomListModel)
|
||||
m_roomListModel = roomListModel;
|
||||
Q_EMIT roomListModelChanged();
|
||||
}
|
||||
|
||||
#include "moc_completionmodel.cpp"
|
||||
|
||||
@@ -64,14 +64,14 @@ public:
|
||||
* @brief Defines the model roles.
|
||||
*/
|
||||
enum Roles {
|
||||
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. */
|
||||
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. */
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
Q_ENUM(Roles);
|
||||
|
||||
explicit CompletionModel(QObject *parent = nullptr);
|
||||
CompletionModel(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Get the given role value at the given index.
|
||||
|
||||
@@ -59,5 +59,3 @@ void CompletionProxyModel::setFullText(const QString &fullText)
|
||||
{
|
||||
m_fullText = fullText;
|
||||
}
|
||||
|
||||
#include "moc_completionproxymodel.cpp"
|
||||
|
||||
@@ -9,12 +9,19 @@
|
||||
#include "controller.h"
|
||||
#include "emojimodel.h"
|
||||
|
||||
#include <Quotient/connection.h>
|
||||
#include <Quotient/csapi/account-data.h>
|
||||
#include <Quotient/csapi/content-repo.h>
|
||||
#include <connection.h>
|
||||
#include <csapi/account-data.h>
|
||||
#include <csapi/content-repo.h>
|
||||
#include <events/eventcontent.h>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
#ifdef QUOTIENT_07
|
||||
#define running isJobPending
|
||||
#else
|
||||
#define running isJobRunning
|
||||
#endif
|
||||
|
||||
void CustomEmojiModel::fetchEmojis()
|
||||
{
|
||||
if (!Controller::instance().activeConnection()) {
|
||||
@@ -55,31 +62,36 @@ void CustomEmojiModel::addEmoji(const QString &name, const QUrl &location)
|
||||
|
||||
auto job = Controller::instance().activeConnection()->uploadFile(location.toLocalFile());
|
||||
|
||||
connect(job, &BaseJob::success, this, [name, location, job] {
|
||||
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes");
|
||||
auto json = data != nullptr ? data->contentJson() : QJsonObject();
|
||||
auto emojiData = json["images"].toObject();
|
||||
if (running(job)) {
|
||||
connect(job, &BaseJob::success, this, [name, location, job] {
|
||||
const auto &data = Controller::instance().activeConnection()->accountData("im.ponies.user_emotes");
|
||||
auto json = data != nullptr ? data->contentJson() : QJsonObject();
|
||||
auto emojiData = json["images"].toObject();
|
||||
|
||||
QString url;
|
||||
url = job->contentUri().toString();
|
||||
QString url;
|
||||
#ifdef QUOTIENT_07
|
||||
url = job->contentUri().toString();
|
||||
#else
|
||||
url = job->contentUri();
|
||||
#endif
|
||||
|
||||
QImage image(location.toLocalFile());
|
||||
QJsonObject imageInfo;
|
||||
imageInfo["w"] = image.width();
|
||||
imageInfo["h"] = image.height();
|
||||
imageInfo["mimetype"] = QMimeDatabase().mimeTypeForFile(location.toLocalFile()).name();
|
||||
imageInfo["size"] = image.sizeInBytes();
|
||||
QImage image(location.toLocalFile());
|
||||
QJsonObject imageInfo;
|
||||
imageInfo["w"] = image.width();
|
||||
imageInfo["h"] = image.height();
|
||||
imageInfo["mimetype"] = QMimeDatabase().mimeTypeForFile(location.toLocalFile()).name();
|
||||
imageInfo["size"] = image.sizeInBytes();
|
||||
|
||||
emojiData[QStringLiteral("%1").arg(name)] = QJsonObject({
|
||||
{QStringLiteral("url"), url},
|
||||
{QStringLiteral("info"), imageInfo},
|
||||
{QStringLiteral("body"), location.fileName()},
|
||||
{"usage"_ls, "emoticon"_ls},
|
||||
emojiData[QStringLiteral("%1").arg(name)] = QJsonObject({
|
||||
{QStringLiteral("url"), url},
|
||||
{QStringLiteral("info"), imageInfo},
|
||||
{QStringLiteral("body"), location.fileName()},
|
||||
});
|
||||
|
||||
json["images"] = emojiData;
|
||||
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes", json);
|
||||
});
|
||||
|
||||
json["images"] = emojiData;
|
||||
Controller::instance().activeConnection()->setAccountData("im.ponies.user_emotes", json);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void CustomEmojiModel::removeEmoji(const QString &name)
|
||||
@@ -203,5 +215,3 @@ QVariantList CustomEmojiModel::filterModel(const QString &filter)
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
#include "moc_customemojimodel.cpp"
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
ReplacedTextRole = 52, /**< The name of the emoji. For compatibility with EmojiModel. */
|
||||
DescriptionRole = 53, /**< Invalid, reserved. For compatibility with EmojiModel. */
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
Q_ENUM(Roles);
|
||||
|
||||
static CustomEmojiModel &instance()
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user