Compare commits

..

2 Commits

Author SHA1 Message Date
Joshua Goins
80ebe71f6a ManualRoomDialog: Use Window.window attached property
This fixes a runtime error since applicationWindow is undefined.
2024-10-30 22:03:46 -04:00
Joshua Goins
02578dd38f ExploreRoomsPage: Fix "Enter a room address" button not working
This was due to an undefined applicationWindow singleton, but we don't
actually need it and can use Overlay.overlay directly.
2024-10-30 22:03:10 -04:00
112 changed files with 12888 additions and 13403 deletions

View File

@@ -110,7 +110,7 @@
{ {
"type": "git", "type": "git",
"url": "https://github.com/quotient-im/libQuotient.git", "url": "https://github.com/quotient-im/libQuotient.git",
"branch": "dev", "branch": "0.8.x",
"disable-submodules": true "disable-submodules": true
} }
], ],

View File

@@ -9,7 +9,7 @@ cmake_minimum_required(VERSION 3.16)
# KDE Applications version, managed by release script. # KDE Applications version, managed by release script.
set(RELEASE_SERVICE_VERSION_MAJOR "24") set(RELEASE_SERVICE_VERSION_MAJOR "24")
set(RELEASE_SERVICE_VERSION_MINOR "11") set(RELEASE_SERVICE_VERSION_MINOR "11")
set(RELEASE_SERVICE_VERSION_MICRO "80") set(RELEASE_SERVICE_VERSION_MICRO "70")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION}) project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
@@ -107,7 +107,7 @@ if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU)
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED) find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
endif() endif()
find_package(QuotientQt6 0.9) find_package(QuotientQt6 0.8.2)
set_package_properties(QuotientQt6 PROPERTIES set_package_properties(QuotientQt6 PROPERTIES
TYPE REQUIRED TYPE REQUIRED
DESCRIPTION "Qt wrapper around Matrix API" DESCRIPTION "Qt wrapper around Matrix API"
@@ -115,6 +115,11 @@ set_package_properties(QuotientQt6 PROPERTIES
PURPOSE "Talk with matrix server" PURPOSE "Talk with matrix server"
) )
if (NOT TARGET Olm::Olm)
message(FATAL_ERROR "NeoChat requires Quotient with the E2EE feature enabled")
endif()
find_package(cmark) find_package(cmark)
set_package_properties(cmark PROPERTIES set_package_properties(cmark PROPERTIES
TYPE REQUIRED TYPE REQUIRED

View File

@@ -11,7 +11,7 @@ A Qt/QML based Matrix client.
<a href='https://matrix.org'><img src='https://matrix.org/docs/legacy/made-for-matrix.png' alt='Made for Matrix' height=64 target=_blank /></a> <a href='https://matrix.org'><img src='https://matrix.org/docs/legacy/made-for-matrix.png' alt='Made for Matrix' height=64 target=_blank /></a>
<a href='https://flathub.org/apps/details/org.kde.neochat'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a> <a href='https://flathub.org/apps/details/org.kde.neochat'><img width='190px' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-i-en.png'/></a>
<a href='https://snapcraft.io/neochat'><img width='190px' alt='Download on the Snap Store' src='https://apps.kde.org/store_badges/snapstore/en.svg'/></a> <a href='https://snapcraft.io/neochat'><img width='190px' alt='Download on the Snap Store' src='https://snapcraft.io/static/images/badges/en/snap-store-black.svg'/></a>
## Introduction ## Introduction

View File

@@ -5,26 +5,6 @@
"!room_id_1234:localhost:1234": { "!room_id_1234:localhost:1234": {
"state": { "state": {
"events": [ "events": [
{
"content": {
"m.federate": true,
"predecessor": {
"event_id": "$something:example.org",
"room_id": "!oldroom:example.org"
},
"room_version": "11"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "",
"type": "m.room.create",
"unsigned": {
"age": 1234,
"membership": "join"
}
},
{ {
"type": "m.room.member", "type": "m.room.member",
"state_key": "@user:localhost:1234", "state_key": "@user:localhost:1234",
@@ -46,26 +26,6 @@
}, },
"timeline": { "timeline": {
"events": [ "events": [
{
"content": {
"m.federate": true,
"predecessor": {
"event_id": "$something:example.org",
"room_id": "!oldroom:example.org"
},
"room_version": "11"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "",
"type": "m.room.create",
"unsigned": {
"age": 1234,
"membership": "join"
}
},
{ {
"type": "m.room.message", "type": "m.room.message",
"sender": "@user:localhost:1234", "sender": "@user:localhost:1234",

View File

@@ -53,6 +53,12 @@ ecm_add_test(
TEST_NAME messageeventmodeltest TEST_NAME messageeventmodeltest
) )
ecm_add_test(
actionshandlertest.cpp
LINK_LIBRARIES neochat Qt::Test
TEST_NAME actionshandlertest
)
ecm_add_test( ecm_add_test(
windowcontrollertest.cpp windowcontrollertest.cpp
LINK_LIBRARIES neochat Qt::Test LINK_LIBRARIES neochat Qt::Test

View File

@@ -0,0 +1,41 @@
// 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 <QTest>
#include "actionshandler.h"
#include "chatbarcache.h"
#include "testutils.h"
class ActionsHandlerTest : public QObject
{
Q_OBJECT
private:
Quotient::Connection *connection = Quotient::Connection::makeMockConnection(QStringLiteral("@bob:kde.org"));
private Q_SLOTS:
void nullObject();
};
void ActionsHandlerTest::nullObject()
{
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
ActionsHandler::handleMessageEvent(nullptr, nullptr);
auto chatBarCache = new ChatBarCache(this);
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
ActionsHandler::handleMessageEvent(nullptr, chatBarCache);
auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"));
QTest::ignoreMessage(QtWarningMsg, "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
ActionsHandler::handleMessageEvent(room, nullptr);
// The final one should throw no warning so we make sure.
QTest::failOnWarning("ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.");
ActionsHandler::handleMessageEvent(room, chatBarCache);
}
QTEST_GUILESS_MAIN(ActionsHandlerTest)
#include "actionshandlertest.moc"

View File

@@ -54,11 +54,9 @@
<summary xml:lang="ar">دردش على ماتركس</summary> <summary xml:lang="ar">دردش على ماتركس</summary>
<summary xml:lang="ca">Xat a Matrix</summary> <summary xml:lang="ca">Xat a Matrix</summary>
<summary xml:lang="ca-valencia">Xat a Matrix</summary> <summary xml:lang="ca-valencia">Xat a Matrix</summary>
<summary xml:lang="en-GB">Chat on Matrix</summary>
<summary xml:lang="es">Charle en Matrix</summary> <summary xml:lang="es">Charle en Matrix</summary>
<summary xml:lang="eu">Berriketa Matrix-en</summary> <summary xml:lang="eu">Berriketa Matrix-en</summary>
<summary xml:lang="fr">Discuter sur Matrix</summary> <summary xml:lang="fr">Discuter sur Matrix</summary>
<summary xml:lang="gl">Charlar en Matrix</summary>
<summary xml:lang="ia">Conversation en ditecto sur Matrix</summary> <summary xml:lang="ia">Conversation en ditecto sur Matrix</summary>
<summary xml:lang="it">Chat su Matrix</summary> <summary xml:lang="it">Chat su Matrix</summary>
<summary xml:lang="ka">ისაუბრეთ Matrix-ზე</summary> <summary xml:lang="ka">ისაუბრეთ Matrix-ზე</summary>

View File

@@ -87,19 +87,47 @@ GenericName[uk]=Клієнт Matrix
GenericName[x-test]=xxMatrix Clientxx GenericName[x-test]=xxMatrix Clientxx
GenericName[zh_CN]=Matrix 客户端 GenericName[zh_CN]=Matrix 客户端
GenericName[zh_TW]=Matrix 用戶端 GenericName[zh_TW]=Matrix 用戶端
Comment=Chat on Matrix Comment=Client for the Matrix protocol
Comment[ca]=Xat a Matrix Comment[ar]=عميل لميفاق ماتركس
Comment[ca@valencia]=Xat a Matrix Comment[az]=Matrix protokolu üçün müştəri
Comment[es]=Chat en Matrix Comment[ca]=Client per al protocol Matrix
Comment[eu]=Berriketa Matrix-en Comment[ca@valencia]=Client per al protocol Matrix
Comment[fr]=Clavarder sur Matrix Comment[de]=Programm für das Matrix-Protokoll
Comment[gl]=Charle en Matrix Comment[el]=Πελάτης για το πρωτόκολλο Matrix
Comment[hu]=Csevegés Matrixon Comment[en_GB]=Client for the Matrix protocol
Comment[it]= su Matrix Comment[eo]=Kliento por la Matrix-protokolo
Comment[pl]=Rozmawiaj na Matriksie Comment[es]=Cliente para el protocolo Matrix
Comment[sl]=Klepet na Matrixu Comment[eu]=Matrix protokolorako bezeroa
Comment[tr]=Matrix Üzerinde Sohbet Et Comment[fi]=Asiakas Matrix-yhteyskäytännölle
Comment[uk]=Спілкування у Matrix Comment[fr]=Client pour le protocole « Matrix »
Comment[gl]=Cliente para o protocolo Matrix.
Comment[he]=לקוח לפרוטוקול Matrix
Comment[hu]=Kliens a Matrix protokollhoz
Comment[ia]=Cliente per le protocollo de Matrix
Comment[id]=Klien untuk protokol Matrix
Comment[ie]=Un cliente del protocol Matrix
Comment[it]=Client per il protocollo Matrix
Comment[ka]=კლიენტი Matrix-ის პროტოკოლისთვის
Comment[ko]=Matrix 프로토콜용 클라이언트
Comment[lt]=Matrix protokolo kliento programa
Comment[lv]=Klients „Matrix“ protokolam
Comment[nl]=Client voor het Matrix-protocol
Comment[nn]=Klient for Matrix-protokollen
Comment[pa]=ਮੈਟਰਿਕਸ ਪਰੋਟੋਕਾਲ ਲਈ ਕਲਾਈਂਟ ਹੈ
Comment[pl]=Program obsługi protokołu Matriksa
Comment[pt]=Cliente para o protocolo Matrix
Comment[pt_BR]=Cliente para o protocolo Matrix
Comment[ro]=Client pentru protocolul Matrix
Comment[ru]=Клиент для протокола Matrix
Comment[sk]=Klient protokolu Matrix
Comment[sl]=Odjemalec za protokol Matrix
Comment[sv]=Klient för protokollet Matrix
Comment[ta]=Matrix நெறிமுறைக்கான வாங்கி
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; MimeType=x-scheme-handler/matrix;
Exec=neochat %u Exec=neochat %u
Terminal=false Terminal=false

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -92,7 +92,7 @@ parts:
- olm - olm
- qtkeychain - qtkeychain
source: https://github.com/quotient-im/libQuotient.git source: https://github.com/quotient-im/libQuotient.git
source-tag: 0.9.0 source-tag: 0.8.2
source-depth: 1 source-depth: 1
plugin: cmake plugin: cmake
build-packages: build-packages:

View File

@@ -10,6 +10,8 @@ endif()
add_library(neochat STATIC add_library(neochat STATIC
controller.cpp controller.cpp
controller.h controller.h
actionshandler.cpp
actionshandler.h
models/emojimodel.cpp models/emojimodel.cpp
models/emojimodel.h models/emojimodel.h
emojitones.cpp emojitones.cpp

144
src/actionshandler.cpp Normal file
View File

@@ -0,0 +1,144 @@
// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "actionshandler.h"
#include "chatbarcache.h"
#include "models/actionsmodel.h"
#include "neochatconfig.h"
#include "texthandler.h"
using namespace Quotient;
using namespace Qt::StringLiterals;
void ActionsHandler::handleMessageEvent(NeoChatRoom *room, ChatBarCache *chatBarCache)
{
if (room == nullptr || chatBarCache == nullptr) {
qWarning() << "ActionsHandler::handleMessageEvent - called with m_room and/or chatBarCache set to nullptr.";
return;
}
if (!chatBarCache->attachmentPath().isEmpty()) {
QUrl url(chatBarCache->attachmentPath());
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
room->uploadFile(QUrl(path), chatBarCache->text().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : chatBarCache->text());
chatBarCache->setAttachmentPath({});
chatBarCache->setText({});
return;
}
const auto handledText = handleMentions(chatBarCache);
const auto result = handleQuickEdit(room, handledText);
if (!result) {
handleMessage(room, handledText, chatBarCache);
}
}
QString ActionsHandler::handleMentions(ChatBarCache *chatBarCache)
{
const auto mentions = chatBarCache->mentions();
std::sort(mentions->begin(), mentions->end(), [](const auto &a, const auto &b) -> bool {
return a.cursor.anchor() > b.cursor.anchor();
});
auto handledText = chatBarCache->text();
for (const auto &mention : *mentions) {
if (mention.text.isEmpty() || mention.id.isEmpty()) {
continue;
}
handledText = handledText.replace(mention.cursor.anchor(),
mention.cursor.position() - mention.cursor.anchor(),
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text.toHtmlEscaped(), mention.id));
}
mentions->clear();
return handledText;
}
bool ActionsHandler::handleQuickEdit(NeoChatRoom *room, const QString &handledText)
{
if (room == nullptr) {
return false;
}
if (NeoChatConfig::allowQuickEdit()) {
QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$"));
auto match = sed.match(handledText);
if (match.hasMatch()) {
const QString regex = match.captured(1);
const QString replacement = match.captured(2).toHtmlEscaped();
const QString flags = match.captured(3);
for (auto it = room->messageEvents().crbegin(); it != room->messageEvents().crend(); it++) {
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
#if Quotient_VERSION_MINOR > 8
if (event->senderId() == room->localMember().id() && event->has<EventContent::TextContent>()) {
#else
if (event->senderId() == room->localMember().id() && event->hasTextContent()) {
#endif
QString originalString;
if (event->content()) {
#if Quotient_VERSION_MINOR > 8
originalString = event->get<EventContent::TextContent>()->body;
#else
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
#endif
} else {
originalString = event->plainBody();
}
if (flags == "/g"_L1) {
room->postHtmlMessage(handledText, originalString.replace(regex, replacement), event->msgtype(), {}, event->id());
} else {
room->postHtmlMessage(handledText,
originalString.replace(originalString.indexOf(regex), regex.size(), replacement),
event->msgtype(),
{},
event->id());
}
return true;
}
}
}
}
}
return false;
}
void ActionsHandler::handleMessage(NeoChatRoom *room, QString handledText, ChatBarCache *chatBarCache)
{
if (room == nullptr) {
return;
}
auto messageType = RoomMessageEvent::MsgType::Text;
if (handledText.startsWith(QLatin1Char('/'))) {
for (const auto &action : ActionsModel::instance().allActions()) {
if (handledText.indexOf(action.prefix) == 1
&& (handledText.indexOf(" "_ls) == action.prefix.length() + 1 || handledText.length() == action.prefix.length() + 1)) {
handledText = action.handle(handledText.mid(action.prefix.length() + 1).trimmed(), room, chatBarCache);
if (action.messageType.has_value()) {
messageType = *action.messageType;
}
if (action.messageAction) {
break;
} else {
return;
}
}
}
}
TextHandler textHandler;
textHandler.setData(handledText);
handledText = textHandler.handleSendText();
if (handledText.length() == 0) {
return;
}
room->postMessage(chatBarCache->text(), handledText, messageType, chatBarCache->replyId(), chatBarCache->editId(), chatBarCache->threadId());
}
#include "moc_actionshandler.cpp"

43
src/actionshandler.h Normal file
View File

@@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QString>
class ChatBarCache;
class NeoChatRoom;
/**
* @class ActionsHandler
*
* This class contains functions to handle chat messages ready for posting to a room.
*
* Everything that needs to be done to prepare the message for posting in a room
* including:
* - File handling
* - User mentions
* - Quick edits
* - Chat actions
* - Custom emojis
*
* @note A chat action is a message starting with /, resulting in something other
* than a normal message being sent (e.g. /me, /join).
*
* @sa ActionsModel, NeoChatRoom
*/
class ActionsHandler
{
public:
/**
* @brief Pre-process text and send message event.
*/
static void handleMessageEvent(NeoChatRoom *room, ChatBarCache *chatBarCache);
private:
static QString handleMentions(ChatBarCache *chatBarCache);
static bool handleQuickEdit(NeoChatRoom *room, const QString &handledText);
static void handleMessage(NeoChatRoom *room, QString handledText, ChatBarCache *chatBarCache);
};

View File

@@ -251,22 +251,20 @@ QQC2.Control {
} }
} }
Keys.onEnterPressed: event => { Keys.onEnterPressed: event => {
const controlIsPressed = event.modifiers & Qt.ControlModifier;
if (completionMenu.visible) { if (completionMenu.visible) {
completionMenu.complete(); completionMenu.complete();
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile || NeoChatConfig.sendMessageWith === 1 && !controlIsPressed || NeoChatConfig.sendMessageWith === 0 && controlIsPressed) { } else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile) {
textField.insert(cursorPosition, "\n"); textField.insert(cursorPosition, "\n");
} else if (NeoChatConfig.sendMessageWith === 0 && !controlIsPressed || NeoChatConfig.sendMessageWith === 1 && controlIsPressed) { } else {
_private.postMessage(); _private.postMessage();
} }
} }
Keys.onReturnPressed: event => { Keys.onReturnPressed: event => {
const controlIsPressed = event.modifiers & Qt.ControlModifier;
if (completionMenu.visible) { if (completionMenu.visible) {
completionMenu.complete(); completionMenu.complete();
} else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile || NeoChatConfig.sendMessageWith === 1 && !controlIsPressed || NeoChatConfig.sendMessageWith === 0 && controlIsPressed) { } else if (event.modifiers & Qt.ShiftModifier || Kirigami.Settings.isMobile) {
textField.insert(cursorPosition, "\n"); textField.insert(cursorPosition, "\n");
} else if (NeoChatConfig.sendMessageWith === 0 && !controlIsPressed || NeoChatConfig.sendMessageWith === 1 && controlIsPressed) { } else {
_private.postMessage(); _private.postMessage();
} }
} }
@@ -407,6 +405,7 @@ QQC2.Control {
repeatTimer.stop(); repeatTimer.stop();
root.currentRoom.markAllMessagesAsRead(); root.currentRoom.markAllMessagesAsRead();
textField.clear(); textField.clear();
_private.chatBarCache.clearRelations();
messageSent(); messageSent();
} }

View File

@@ -5,11 +5,10 @@
#include <Quotient/roommember.h> #include <Quotient/roommember.h>
#include "actionshandler.h"
#include "chatdocumenthandler.h" #include "chatdocumenthandler.h"
#include "eventhandler.h" #include "eventhandler.h"
#include "models/actionsmodel.h"
#include "neochatroom.h" #include "neochatroom.h"
#include "texthandler.h"
ChatBarCache::ChatBarCache(QObject *parent) ChatBarCache::ChatBarCache(QObject *parent)
: QObject(parent) : QObject(parent)
@@ -30,37 +29,6 @@ void ChatBarCache::setText(const QString &text)
Q_EMIT textChanged(); Q_EMIT textChanged();
} }
QString ChatBarCache::sendText() const
{
if (!attachmentPath().isEmpty()) {
QUrl url(attachmentPath());
auto path = url.isLocalFile() ? url.toLocalFile() : url.toString();
return text().isEmpty() ? path.mid(path.lastIndexOf(u'/') + 1) : text();
}
return formatMentions();
}
QString ChatBarCache::formatMentions() const
{
auto mentions = m_mentions;
std::sort(mentions.begin(), mentions.end(), [](const auto &a, const auto &b) {
return a.cursor.anchor() > b.cursor.anchor();
});
auto formattedText = text();
for (const auto &mention : mentions) {
if (mention.text.isEmpty() || mention.id.isEmpty()) {
continue;
}
formattedText = formattedText.replace(mention.cursor.anchor(),
mention.cursor.position() - mention.cursor.anchor(),
QStringLiteral("[%1](https://matrix.to/#/%2)").arg(mention.text.toHtmlEscaped(), mention.id));
}
return formattedText;
}
bool ChatBarCache::isReplying() const bool ChatBarCache::isReplying() const
{ {
return m_relationType == Reply && !m_relationId.isEmpty(); return m_relationType == Reply && !m_relationId.isEmpty();
@@ -300,35 +268,7 @@ void ChatBarCache::postMessage()
return; return;
} }
if (!attachmentPath().isEmpty()) { ActionsHandler::handleMessageEvent(room, this);
room->uploadFile(QUrl(attachmentPath()), sendText());
clearCache();
return;
}
const auto result = ActionsModel::handleAction(room, this);
if (!result.first.has_value()) {
return;
}
TextHandler textHandler;
textHandler.setData(*std::get<std::optional<QString>>(result));
const auto sendText = textHandler.handleSendText();
if (sendText.length() == 0) {
return;
}
room->postMessage(text(), sendText, *std::get<std::optional<Quotient::RoomMessageEvent::MsgType>>(result), replyId(), editId(), threadId());
clearCache();
}
void ChatBarCache::clearCache()
{
setText({});
m_mentions.clear();
m_savedText = QString();
clearRelations();
} }
#include "moc_chatbarcache.cpp" #include "moc_chatbarcache.cpp"

View File

@@ -153,7 +153,6 @@ public:
explicit ChatBarCache(QObject *parent = nullptr); explicit ChatBarCache(QObject *parent = nullptr);
QString text() const; QString text() const;
QString sendText() const;
void setText(const QString &text); void setText(const QString &text);
bool isReplying() const; bool isReplying() const;
@@ -216,8 +215,6 @@ Q_SIGNALS:
private: private:
QString m_text = QString(); QString m_text = QString();
QString formatMentions() const;
QString m_relationId = QString(); QString m_relationId = QString();
RelationType m_relationType = RelationType::None; RelationType m_relationType = RelationType::None;
QString m_threadId = QString(); QString m_threadId = QString();
@@ -226,6 +223,4 @@ private:
QString m_savedText; QString m_savedText;
QPointer<MessageContentModel> m_relationContentModel; QPointer<MessageContentModel> m_relationContentModel;
void clearCache();
}; };

View File

@@ -63,7 +63,11 @@ Controller::Controller(QObject *parent)
}); });
} else { } else {
auto c = new NeoChatConnection(this); auto c = new NeoChatConnection(this);
#if Quotient_VERSION_MINOR > 8
c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("device_1234"), QStringLiteral("token_1234")); c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("device_1234"), QStringLiteral("token_1234"));
#else
c->assumeIdentity(QStringLiteral("@user:localhost:1234"), QStringLiteral("token_1234"));
#endif
connect(c, &Connection::connected, this, [c, this]() { connect(c, &Connection::connected, this, [c, this]() {
m_accountRegistry.add(c); m_accountRegistry.add(c);
c->syncLoop(); c->syncLoop();
@@ -226,7 +230,11 @@ void Controller::invokeLogin()
Qt::SingleShotConnection); Qt::SingleShotConnection);
} }
}); });
#if Quotient_VERSION_MINOR > 8
connection->assumeIdentity(account.userId(), account.deviceId(), accessToken); connection->assumeIdentity(account.userId(), account.deviceId(), accessToken);
#else
connection->assumeIdentity(account.userId(), accessToken);
#endif
}); });
} }
} }
@@ -433,7 +441,11 @@ void Controller::removeConnection(const QString &userId)
bool Controller::csSupported() const bool Controller::csSupported() const
{ {
#if Quotient_VERSION_MINOR > 8
return true; return true;
#else
return false;
#endif
} }
void Controller::revertToDefaultConfig() void Controller::revertToDefaultConfig()

View File

@@ -4,7 +4,6 @@
import QtQuick import QtQuick
import QtQuick.Controls as QQC2 import QtQuick.Controls as QQC2
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Window
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard import org.kde.kirigamiaddons.formcard as FormCard
@@ -24,7 +23,7 @@ ColumnLayout {
model: root.connection.accountDataEventTypes model: root.connection.accountDataEventTypes
delegate: FormCard.FormButtonDelegate { delegate: FormCard.FormButtonDelegate {
text: modelData text: modelData
onClicked: root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), { onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
sourceText: root.connection.accountDataJsonString(modelData) sourceText: root.connection.accountDataJsonString(modelData)
}, { }, {
title: i18nc("@title:window", "Event Source"), title: i18nc("@title:window", "Event Source"),

View File

@@ -3,7 +3,6 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Window
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard import org.kde.kirigamiaddons.formcard as FormCard
@@ -48,7 +47,7 @@ ColumnLayout {
model: root.room.accountDataEventTypes model: root.room.accountDataEventTypes
delegate: FormCard.FormButtonDelegate { delegate: FormCard.FormButtonDelegate {
text: modelData text: modelData
onClicked: root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), { onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
sourceText: root.room.roomAcountDataJson(text) sourceText: root.room.roomAcountDataJson(text)
}, { }, {
title: i18n("Event Source"), title: i18n("Event Source"),
@@ -78,7 +77,7 @@ ColumnLayout {
if (model.eventCount === 1) { if (model.eventCount === 1) {
openEventSource(model.type, model.stateKey); openEventSource(model.type, model.stateKey);
} else { } else {
root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'StateKeys'), { pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'StateKeys'), {
room: root.room, room: root.room,
eventType: model.type eventType: model.type
}, { }, {
@@ -90,7 +89,7 @@ ColumnLayout {
} }
} }
function openEventSource(type: string, stateKey: string): void { function openEventSource(type: string, stateKey: string): void {
onClicked: root.Window.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), { onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
model: stateModel, model: stateModel,
allowEdit: true, allowEdit: true,
room: root.room, room: root.room,

View File

@@ -225,10 +225,18 @@ QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
{ {
QString body; QString body;
#if Quotient_VERSION_MINOR > 8
if (event.has<EventContent::FileContent>()) { if (event.has<EventContent::FileContent>()) {
#else
if (event.hasFileContent()) {
#endif
// if filename is given or body is equal to filename, // if filename is given or body is equal to filename,
// then body is a caption // then body is a caption
#if Quotient_VERSION_MINOR > 8
QString filename = event.get<EventContent::FileContent>()->originalName; QString filename = event.get<EventContent::FileContent>()->originalName;
#else
QString filename = event.content()->fileInfo()->originalName;
#endif
QString body = event.plainBody(); QString body = event.plainBody();
if (filename.isEmpty() || filename == body) { if (filename.isEmpty() || filename == body) {
return QString(); return QString();
@@ -236,8 +244,13 @@ QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
return body; return body;
} }
#if Quotient_VERSION_MINOR > 8
if (event.has<EventContent::TextContent>() && event.content()) { if (event.has<EventContent::TextContent>() && event.content()) {
body = event.get<EventContent::TextContent>()->body; body = event.get<EventContent::TextContent>()->body;
#else
if (event.hasTextContent() && event.content()) {
body = static_cast<const EventContent::TextContent *>(event.content())->body;
#endif
} else { } else {
body = event.plainBody(); body = event.plainBody();
} }
@@ -464,8 +477,13 @@ QString EventHandler::getMessageBody(const NeoChatRoom *room, const RoomMessageE
{ {
TextHandler textHandler; TextHandler textHandler;
#if Quotient_VERSION_MINOR > 8
if (event.has<EventContent::FileContent>()) { if (event.has<EventContent::FileContent>()) {
QString fileCaption = event.get<EventContent::FileContent>()->originalName; QString fileCaption = event.get<EventContent::FileContent>()->originalName;
#else
if (event.hasFileContent()) {
QString fileCaption = event.content()->fileInfo()->originalName;
#endif
if (fileCaption.isEmpty()) { if (fileCaption.isEmpty()) {
fileCaption = event.plainBody(); fileCaption = event.plainBody();
} else if (fileCaption != event.plainBody()) { } else if (fileCaption != event.plainBody()) {
@@ -476,8 +494,13 @@ QString EventHandler::getMessageBody(const NeoChatRoom *room, const RoomMessageE
} }
QString body; QString body;
#if Quotient_VERSION_MINOR > 8
if (event.has<EventContent::TextContent>() && event.content()) { if (event.has<EventContent::TextContent>() && event.content()) {
body = event.get<EventContent::TextContent>()->body; body = event.get<EventContent::TextContent>()->body;
#else
if (event.hasTextContent() && event.content()) {
body = static_cast<const EventContent::TextContent *>(event.content())->body;
#endif
} else { } else {
body = event.plainBody(); body = event.plainBody();
} }
@@ -692,15 +715,28 @@ QVariantMap EventHandler::getMediaInfoForEvent(const NeoChatRoom *room, const Qu
// Get the file info for the event. // Get the file info for the event.
if (event->is<RoomMessageEvent>()) { if (event->is<RoomMessageEvent>()) {
auto roomMessageEvent = eventCast<const RoomMessageEvent>(event); auto roomMessageEvent = eventCast<const RoomMessageEvent>(event);
#if Quotient_VERSION_MINOR > 8
if (!roomMessageEvent->has<EventContent::FileContentBase>()) { if (!roomMessageEvent->has<EventContent::FileContentBase>()) {
#else
if (!roomMessageEvent->hasFileContent()) {
#endif
return {}; return {};
} }
#if Quotient_VERSION_MINOR > 8
const auto content = roomMessageEvent->get<EventContent::FileContentBase>(); const auto content = roomMessageEvent->get<EventContent::FileContentBase>();
QVariantMap mediaInfo = getMediaInfoFromFileInfo(room, content.get(), eventId, false, false); QVariantMap mediaInfo = getMediaInfoFromFileInfo(room, content.get(), eventId, false, false);
#else
const auto content = static_cast<const EventContent::FileContent *>(roomMessageEvent->content());
QVariantMap mediaInfo = getMediaInfoFromFileInfo(room, content, eventId, false, false);
#endif
// if filename isn't specifically given, it is in body // if filename isn't specifically given, it is in body
// https://spec.matrix.org/latest/client-server-api/#mfile // https://spec.matrix.org/latest/client-server-api/#mfile
#if Quotient_VERSION_MINOR > 8
mediaInfo["filename"_ls] = content->commonInfo().originalName.isEmpty() ? roomMessageEvent->plainBody() : content->commonInfo().originalName; mediaInfo["filename"_ls] = content->commonInfo().originalName.isEmpty() ? roomMessageEvent->plainBody() : content->commonInfo().originalName;
#else
mediaInfo["filename"_ls] = (content->fileInfo()->originalName.isEmpty()) ? roomMessageEvent->plainBody() : content->fileInfo()->originalName;
#endif
return mediaInfo; return mediaInfo;
} else if (event->is<StickerEvent>()) { } else if (event->is<StickerEvent>()) {
@@ -714,7 +750,11 @@ QVariantMap EventHandler::getMediaInfoForEvent(const NeoChatRoom *room, const Qu
} }
QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room, QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
#if Quotient_VERSION_MINOR > 8
const Quotient::EventContent::FileContentBase *fileContent, const Quotient::EventContent::FileContentBase *fileContent,
#else
const Quotient::EventContent::TypedBase *fileContent,
#endif
const QString &eventId, const QString &eventId,
bool isThumbnail, bool isThumbnail,
bool isSticker) bool isSticker)
@@ -722,10 +762,18 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
QVariantMap mediaInfo; QVariantMap mediaInfo;
// Get the mxc URL for the media. // Get the mxc URL for the media.
#if Quotient_VERSION_MINOR > 8
if (!fileContent->url().isValid() || fileContent->url().scheme() != QStringLiteral("mxc") || eventId.isEmpty()) { if (!fileContent->url().isValid() || fileContent->url().scheme() != QStringLiteral("mxc") || eventId.isEmpty()) {
#else
if (!fileContent->fileInfo()->url().isValid() || fileContent->fileInfo()->url().scheme() != QStringLiteral("mxc") || eventId.isEmpty()) {
#endif
mediaInfo["source"_ls] = QUrl(); mediaInfo["source"_ls] = QUrl();
} else { } else {
#if Quotient_VERSION_MINOR > 8
QUrl source = room->makeMediaUrl(eventId, fileContent->url()); QUrl source = room->makeMediaUrl(eventId, fileContent->url());
#else
QUrl source = room->makeMediaUrl(eventId, fileContent->fileInfo()->url());
#endif
if (source.isValid()) { if (source.isValid()) {
mediaInfo["source"_ls] = source; mediaInfo["source"_ls] = source;
@@ -742,15 +790,25 @@ QVariantMap EventHandler::getMediaInfoFromFileInfo(const NeoChatRoom *room,
mediaInfo["mimeIcon"_ls] = mimeType.iconName(); mediaInfo["mimeIcon"_ls] = mimeType.iconName();
// Add media size if available. // Add media size if available.
#if Quotient_VERSION_MINOR > 8
mediaInfo["size"_ls] = fileContent->commonInfo().payloadSize; mediaInfo["size"_ls] = fileContent->commonInfo().payloadSize;
#else
mediaInfo["size"_ls] = static_cast<const EventContent::FileContent *>(fileContent)->fileInfo()->payloadSize;
#endif
mediaInfo["isSticker"_ls] = isSticker; mediaInfo["isSticker"_ls] = isSticker;
// Add parameter depending on media type. // Add parameter depending on media type.
if (mimeType.name().contains(QStringLiteral("image"))) { if (mimeType.name().contains(QStringLiteral("image"))) {
if (auto castInfo = static_cast<const EventContent::ImageContent *>(fileContent)) { if (auto castInfo = static_cast<const EventContent::ImageContent *>(fileContent)) {
#if Quotient_VERSION_MINOR > 8
mediaInfo["width"_ls] = castInfo->imageSize.width(); mediaInfo["width"_ls] = castInfo->imageSize.width();
mediaInfo["height"_ls] = castInfo->imageSize.height(); mediaInfo["height"_ls] = castInfo->imageSize.height();
#else
const auto imageInfo = static_cast<const EventContent::ImageInfo *>(castInfo->fileInfo());
mediaInfo["width"_ls] = imageInfo->imageSize.width();
mediaInfo["height"_ls] = imageInfo->imageSize.height();
#endif
// TODO: Images in certain formats (e.g. WebP) will be erroneously marked as animated, even if they are static. // TODO: Images in certain formats (e.g. WebP) will be erroneously marked as animated, even if they are static.
mediaInfo["animated"_ls] = QMovie::supportedFormats().contains(mimeType.preferredSuffix().toUtf8()); mediaInfo["animated"_ls] = QMovie::supportedFormats().contains(mimeType.preferredSuffix().toUtf8());

View File

@@ -290,7 +290,11 @@ private:
static QVariantMap getMediaInfoForEvent(const NeoChatRoom *room, const Quotient::RoomEvent *event); static QVariantMap getMediaInfoForEvent(const NeoChatRoom *room, const Quotient::RoomEvent *event);
QVariantMap static getMediaInfoFromFileInfo(const NeoChatRoom *room, QVariantMap static getMediaInfoFromFileInfo(const NeoChatRoom *room,
#if Quotient_VERSION_MINOR > 8
const Quotient::EventContent::FileContentBase *fileContent, const Quotient::EventContent::FileContentBase *fileContent,
#else
const Quotient::EventContent::TypedBase *fileContent,
#endif
const QString &eventId, const QString &eventId,
bool isThumbnail = false, bool isThumbnail = false,
bool isSticker = false); bool isSticker = false);

View File

@@ -3,6 +3,7 @@
#include "imagepackevent.h" #include "imagepackevent.h"
#include <QJsonObject> #include <QJsonObject>
#include <Quotient/omittable.h>
using namespace Quotient; using namespace Quotient;
@@ -10,10 +11,10 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
{ {
if (json.contains(QStringLiteral("pack"))) { if (json.contains(QStringLiteral("pack"))) {
pack = ImagePackEventContent::Pack{ pack = ImagePackEventContent::Pack{
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["display_name"_ls]), fromJson<Omittable<QString>>(json["pack"_ls].toObject()["display_name"_ls]),
fromJson<std::optional<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]), fromJson<Omittable<QUrl>>(json["pack"_ls].toObject()["avatar_url"_ls]),
fromJson<std::optional<QStringList>>(json["pack"_ls].toObject()["usage"_ls]), fromJson<Omittable<QStringList>>(json["pack"_ls].toObject()["usage"_ls]),
fromJson<std::optional<QString>>(json["pack"_ls].toObject()["attribution"_ls]), fromJson<Omittable<QString>>(json["pack"_ls].toObject()["attribution"_ls]),
}; };
} else { } else {
pack = std::nullopt; pack = std::nullopt;
@@ -30,9 +31,9 @@ ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
images += ImagePackImage{ images += ImagePackImage{
k, k,
fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()), fromJson<QUrl>(json["images"_ls][k]["url"_ls].toString()),
fromJson<std::optional<QString>>(json["images"_ls][k]["body"_ls]), fromJson<Omittable<QString>>(json["images"_ls][k]["body"_ls]),
info, info,
fromJson<std::optional<QStringList>>(json["images"_ls][k]["usage"_ls]), fromJson<Omittable<QStringList>>(json["images"_ls][k]["usage"_ls]),
}; };
} }
} }

View File

@@ -7,10 +7,13 @@
#include <Quotient/accountregistry.h> #include <Quotient/accountregistry.h>
#include <Quotient/e2ee/sssshandler.h> #include <Quotient/e2ee/sssshandler.h>
#include <Quotient/keyimport.h>
#include <Quotient/keyverificationsession.h> #include <Quotient/keyverificationsession.h>
#include <Quotient/roommember.h> #include <Quotient/roommember.h>
#if Quotient_VERSION_MINOR > 8
#include <Quotient/keyimport.h>
#endif
#include "controller.h" #include "controller.h"
#include "neochatconfig.h" #include "neochatconfig.h"
@@ -40,9 +43,11 @@ struct ForeignSSSSHandler {
QML_NAMED_ELEMENT(SSSSHandler) QML_NAMED_ELEMENT(SSSSHandler)
}; };
#if Quotient_VERSION_MINOR > 8
struct ForeignKeyImport { struct ForeignKeyImport {
Q_GADGET Q_GADGET
QML_SINGLETON QML_SINGLETON
QML_FOREIGN(Quotient::KeyImport) QML_FOREIGN(Quotient::KeyImport)
QML_NAMED_ELEMENT(KeyImport) QML_NAMED_ELEMENT(KeyImport)
}; };
#endif

View File

@@ -5,7 +5,7 @@
using namespace Quotient; using namespace Quotient;
NeochatAdd3PIdJob::NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const std::optional<QJsonObject> &auth) NeochatAdd3PIdJob::NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Omittable<QJsonObject> &auth)
: BaseJob(HttpVerb::Post, QStringLiteral("Add3PIDJob"), makePath("/_matrix/client/v3", "/account/3pid/add")) : BaseJob(HttpVerb::Post, QStringLiteral("Add3PIDJob"), makePath("/_matrix/client/v3", "/account/3pid/add"))
{ {
QJsonObject _dataJson; QJsonObject _dataJson;

View File

@@ -4,9 +4,10 @@
#pragma once #pragma once
#include <Quotient/jobs/basejob.h> #include <Quotient/jobs/basejob.h>
#include <Quotient/omittable.h>
class NeochatAdd3PIdJob : public Quotient::BaseJob class NeochatAdd3PIdJob : public Quotient::BaseJob
{ {
public: public:
explicit NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const std::optional<QJsonObject> &auth = {}); explicit NeochatAdd3PIdJob(const QString &clientSecret, const QString &sid, const Quotient::Omittable<QJsonObject> &auth = {});
}; };

View File

@@ -5,7 +5,7 @@
using namespace Quotient; using namespace Quotient;
NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth) NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Omittable<QJsonObject> &auth)
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), "/_matrix/client/r0/account/password") : BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"), "/_matrix/client/r0/account/password")
{ {
QJsonObject _data; QJsonObject _data;

View File

@@ -5,8 +5,10 @@
#include <Quotient/jobs/basejob.h> #include <Quotient/jobs/basejob.h>
#include <Quotient/omittable.h>
class NeochatChangePasswordJob : public Quotient::BaseJob class NeochatChangePasswordJob : public Quotient::BaseJob
{ {
public: public:
explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const std::optional<QJsonObject> &auth = {}); explicit NeochatChangePasswordJob(const QString &newPassword, bool logoutDevices, const Quotient::Omittable<QJsonObject> &auth = {});
}; };

View File

@@ -5,7 +5,7 @@
using namespace Quotient; using namespace Quotient;
NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth) NeoChatDeactivateAccountJob::NeoChatDeactivateAccountJob(const Omittable<QJsonObject> &auth)
: BaseJob(HttpVerb::Post, QStringLiteral("DisableDeviceJob"), "_matrix/client/v3/account/deactivate") : BaseJob(HttpVerb::Post, QStringLiteral("DisableDeviceJob"), "_matrix/client/v3/account/deactivate")
{ {
QJsonObject data; QJsonObject data;

View File

@@ -4,9 +4,10 @@
#pragma once #pragma once
#include <Quotient/jobs/basejob.h> #include <Quotient/jobs/basejob.h>
#include <Quotient/omittable.h>
class NeoChatDeactivateAccountJob : public Quotient::BaseJob class NeoChatDeactivateAccountJob : public Quotient::BaseJob
{ {
public: public:
explicit NeoChatDeactivateAccountJob(const std::optional<QJsonObject> &auth = {}); explicit NeoChatDeactivateAccountJob(const Quotient::Omittable<QJsonObject> &auth = {});
}; };

View File

@@ -5,7 +5,7 @@
using namespace Quotient; using namespace Quotient;
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth) NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Omittable<QJsonObject> &auth)
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId).toLatin1()) : BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId).toLatin1())
{ {
QJsonObject _data; QJsonObject _data;

View File

@@ -4,9 +4,10 @@
#pragma once #pragma once
#include <Quotient/jobs/basejob.h> #include <Quotient/jobs/basejob.h>
#include <Quotient/omittable.h>
class NeochatDeleteDeviceJob : public Quotient::BaseJob class NeochatDeleteDeviceJob : public Quotient::BaseJob
{ {
public: public:
explicit NeochatDeleteDeviceJob(const QString &deviceId, const std::optional<QJsonObject> &auth = {}); explicit NeochatDeleteDeviceJob(const QString &deviceId, const Quotient::Omittable<QJsonObject> &auth = {});
}; };

View File

@@ -4,6 +4,7 @@
#pragma once #pragma once
#include <Quotient/jobs/basejob.h> #include <Quotient/jobs/basejob.h>
#include <Quotient/omittable.h>
// TODO: Upstream to libQuotient // TODO: Upstream to libQuotient
class NeochatGetCommonRoomsJob : public Quotient::BaseJob class NeochatGetCommonRoomsJob : public Quotient::BaseJob

View File

@@ -140,7 +140,7 @@ int main(int argc, char *argv[])
KAboutData about(QStringLiteral("neochat"), KAboutData about(QStringLiteral("neochat"),
i18n("NeoChat"), i18n("NeoChat"),
QStringLiteral(NEOCHAT_VERSION_STRING), QStringLiteral(NEOCHAT_VERSION_STRING),
i18n("Chat on Matrix"), i18n("Matrix client"),
KAboutLicense::GPL_V3, KAboutLicense::GPL_V3,
i18n("© 2018-2020 Black Hat, 2020-2024 KDE Community")); i18n("© 2018-2020 Black Hat, 2020-2024 KDE Community"));
about.addAuthor(i18n("Carl Schwan"), about.addAuthor(i18n("Carl Schwan"),

View File

@@ -163,7 +163,11 @@ void AccountEmoticonModel::setEmoticonImage(int index, const QUrl &source)
QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl source) QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl source)
{ {
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString()); auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
#if Quotient_VERSION_MINOR > 8
co_await qCoro(job.get(), &BaseJob::finished); co_await qCoro(job.get(), &BaseJob::finished);
#else
co_await qCoro(job, &BaseJob::finished);
#endif
if (job->error() != BaseJob::NoError) { if (job->error() != BaseJob::NoError) {
co_return; co_return;
} }
@@ -185,7 +189,11 @@ QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl sourc
QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString shortcode, QString description, QString type) QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString shortcode, QString description, QString type)
{ {
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString()); auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
#if Quotient_VERSION_MINOR > 8
co_await qCoro(job.get(), &BaseJob::finished); co_await qCoro(job.get(), &BaseJob::finished);
#else
co_await qCoro(job, &BaseJob::finished);
#endif
if (job->error() != BaseJob::NoError) { if (job->error() != BaseJob::NoError) {
co_return; co_return;
} }

View File

@@ -5,7 +5,6 @@
#include "chatbarcache.h" #include "chatbarcache.h"
#include "enums/messagetype.h" #include "enums/messagetype.h"
#include "neochatconfig.h"
#include "neochatconnection.h" #include "neochatconnection.h"
#include "neochatroom.h" #include "neochatroom.h"
#include "roommanager.h" #include "roommanager.h"
@@ -18,7 +17,6 @@
using Action = ActionsModel::Action; using Action = ActionsModel::Action;
using namespace Quotient; using namespace Quotient;
using namespace Qt::StringLiterals;
QStringList rainbowColors{"#ff2b00"_ls, "#ff5500"_ls, "#ff8000"_ls, "#ffaa00"_ls, "#ffd500"_ls, "#ffff00"_ls, "#d4ff00"_ls, "#aaff00"_ls, "#80ff00"_ls, QStringList rainbowColors{"#ff2b00"_ls, "#ff5500"_ls, "#ff8000"_ls, "#ffaa00"_ls, "#ffd500"_ls, "#ffff00"_ls, "#d4ff00"_ls, "#aaff00"_ls, "#80ff00"_ls,
"#55ff00"_ls, "#2bff00"_ls, "#00ff00"_ls, "#00ff2b"_ls, "#00ff55"_ls, "#00ff80"_ls, "#00ffaa"_ls, "#00ffd5"_ls, "#00ffff"_ls, "#55ff00"_ls, "#2bff00"_ls, "#00ff00"_ls, "#00ff2b"_ls, "#00ff55"_ls, "#00ff80"_ls, "#00ffaa"_ls, "#00ffd5"_ls, "#00ffff"_ls,
@@ -576,73 +574,3 @@ QList<Action> &ActionsModel::allActions() const
{ {
return actions; return actions;
} }
bool ActionsModel::handleQuickEditAction(NeoChatRoom *room, const QString &messageText)
{
if (room == nullptr) {
return false;
}
if (NeoChatConfig::allowQuickEdit()) {
QRegularExpression sed(QStringLiteral("^s/([^/]*)/([^/]*)(/g)?$"));
auto match = sed.match(messageText);
if (match.hasMatch()) {
const QString regex = match.captured(1);
const QString replacement = match.captured(2).toHtmlEscaped();
const QString flags = match.captured(3);
for (auto it = room->messageEvents().crbegin(); it != room->messageEvents().crend(); it++) {
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
if (event->senderId() == room->localMember().id() && event->has<EventContent::TextContent>()) {
QString originalString;
if (event->content()) {
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content().get())->body;
} else {
originalString = event->plainBody();
}
if (flags == "/g"_L1) {
room->postHtmlMessage(messageText, originalString.replace(regex, replacement), event->msgtype(), {}, event->id());
} else {
room->postHtmlMessage(messageText,
originalString.replace(originalString.indexOf(regex), regex.size(), replacement),
event->msgtype(),
{},
event->id());
}
return true;
}
}
}
}
}
return false;
}
std::pair<std::optional<QString>, std::optional<Quotient::RoomMessageEvent::MsgType>> ActionsModel::handleAction(NeoChatRoom *room, ChatBarCache *chatBarCache)
{
auto sendText = chatBarCache->sendText();
const auto edited = handleQuickEditAction(room, sendText);
if (edited) {
return std::make_pair(std::nullopt, std::nullopt);
}
std::optional<Quotient::RoomMessageEvent::MsgType> messageType = std::nullopt;
if (sendText.startsWith(QLatin1Char('/'))) {
for (const auto &action : ActionsModel::instance().allActions()) {
if (sendText.indexOf(action.prefix) == 1
&& (sendText.indexOf(" "_ls) == action.prefix.length() + 1 || sendText.length() == action.prefix.length() + 1)) {
sendText = action.handle(sendText.mid(action.prefix.length() + 1).trimmed(), room, chatBarCache);
if (action.messageType.has_value()) {
messageType = action.messageType;
}
if (action.messageAction) {
break;
} else {
return std::make_pair(std::nullopt, std::nullopt);
}
}
}
}
return std::make_pair(sendText, messageType);
}

View File

@@ -90,21 +90,6 @@ public:
*/ */
QList<Action> &allActions() const; QList<Action> &allActions() const;
/**
* @brief Handle special sed style edit action.
*
* @return True if the message has a sed edit which was actioned. False otherwise.
*/
static bool handleQuickEditAction(NeoChatRoom *room, const QString &messageText);
/**
* @brief Handle any action within the message contained in the given ChatBarCache.
*
* @return A modified or unmodified string that needs to be sent or an empty string if
* the handled action replaces sending a normal message.
*/
static std::pair<std::optional<QString>, std::optional<Quotient::RoomMessageEvent::MsgType>> handleAction(NeoChatRoom *room, ChatBarCache *chatBarCache);
private: private:
ActionsModel() = default; ActionsModel() = default;
}; };

View File

@@ -129,7 +129,11 @@ void DevicesModel::logout(const QString &deviceId, const QString &password)
QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, m_connection->user()->id()}}; QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, m_connection->user()->id()}};
authData["identifier"_ls] = identifier; authData["identifier"_ls] = identifier;
auto innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData); auto innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
#if Quotient_VERSION_MINOR > 8
connect(innerJob.get(), &BaseJob::success, this, onSuccess); connect(innerJob.get(), &BaseJob::success, this, onSuccess);
#else
connect(innerJob, &BaseJob::success, this, onSuccess);
#endif
} else { } else {
onSuccess(); onSuccess();
} }

View File

@@ -522,10 +522,19 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
auto fileTransferInfo = m_room->cachedFileTransferInfo(event); auto fileTransferInfo = m_room->cachedFileTransferInfo(event);
#ifndef Q_OS_ANDROID #ifndef Q_OS_ANDROID
#if Quotient_VERSION_MINOR > 8
Q_ASSERT(roomMessageEvent->content() != nullptr && roomMessageEvent->has<EventContent::FileContent>()); Q_ASSERT(roomMessageEvent->content() != nullptr && roomMessageEvent->has<EventContent::FileContent>());
const QMimeType mimeType = roomMessageEvent->get<EventContent::FileContent>()->mimeType; const QMimeType mimeType = roomMessageEvent->get<EventContent::FileContent>()->mimeType;
#else
Q_ASSERT(roomMessageEvent->content() != nullptr && roomMessageEvent->hasFileContent());
const QMimeType mimeType = roomMessageEvent->content()->fileInfo()->mimeType;
#endif
if (mimeType.name() == QStringLiteral("text/plain") || mimeType.parentMimeTypes().contains(QStringLiteral("text/plain"))) { if (mimeType.name() == QStringLiteral("text/plain") || mimeType.parentMimeTypes().contains(QStringLiteral("text/plain"))) {
#if Quotient_VERSION_MINOR > 8
QString originalName = roomMessageEvent->get<EventContent::FileContent>()->originalName; QString originalName = roomMessageEvent->get<EventContent::FileContent>()->originalName;
#else
QString originalName = roomMessageEvent->content()->fileInfo()->originalName;
#endif
if (originalName.isEmpty()) { if (originalName.isEmpty()) {
originalName = roomMessageEvent->plainBody(); originalName = roomMessageEvent->plainBody();
} }
@@ -635,7 +644,7 @@ QList<MessageComponent> MessageContentModel::addLinkPreviews(QList<MessageCompon
void MessageContentModel::closeLinkPreview(int row) void MessageContentModel::closeLinkPreview(int row)
{ {
if (row < 0 || row >= m_components.size()) { if (row < 0 || row > m_components.size()) {
qWarning() << "closeLinkPreview() called with row" << row << "which does not exist. m_components.size() =" << m_components.size(); qWarning() << "closeLinkPreview() called with row" << row << "which does not exist. m_components.size() =" << m_components.size();
return; return;
} }
@@ -645,7 +654,6 @@ void MessageContentModel::closeLinkPreview(int row)
m_removedLinkPreviews += m_components[row].attributes["link"_ls].toUrl(); m_removedLinkPreviews += m_components[row].attributes["link"_ls].toUrl();
m_components.remove(row); m_components.remove(row);
m_components.squeeze(); m_components.squeeze();
endResetModel();
resetContent(); resetContent();
} }
} }
@@ -658,7 +666,11 @@ void MessageContentModel::updateItineraryModel()
} }
if (auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event)) { if (auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event)) {
#if Quotient_VERSION_MINOR > 8
if (roomMessageEvent->has<EventContent::FileContent>()) { if (roomMessageEvent->has<EventContent::FileContent>()) {
#else
if (roomMessageEvent->hasFileContent()) {
#endif
auto filePath = m_room->cachedFileTransferInfo(event).localPath; auto filePath = m_room->cachedFileTransferInfo(event).localPath;
if (filePath.isEmpty() && m_itineraryModel != nullptr) { if (filePath.isEmpty() && m_itineraryModel != nullptr) {
delete m_itineraryModel; delete m_itineraryModel;

View File

@@ -505,7 +505,11 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
if (role == ProgressInfoRole) { if (role == ProgressInfoRole) {
if (auto e = eventCast<const RoomMessageEvent>(&evt)) { if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
#if Quotient_VERSION_MINOR > 8
if (e->has<EventContent::FileContent>()) { if (e->has<EventContent::FileContent>()) {
#else
if (e->hasFileContent()) {
#endif
return QVariant::fromValue(m_currentRoom->cachedFileTransferInfo(&evt)); return QVariant::fromValue(m_currentRoom->cachedFileTransferInfo(&evt));
} }
} }

View File

@@ -311,7 +311,12 @@ void PushRuleModel::addKeyword(const QString &keyword, const QString &roomId)
pushConditions.append(keywordCondition); pushConditions.append(keywordCondition);
} }
#if Quotient_VERSION_MINOR > 8
auto job = m_connection->callApi<Quotient::SetPushRuleJob>(PushRuleKind::kindString(kind), auto job = m_connection->callApi<Quotient::SetPushRuleJob>(PushRuleKind::kindString(kind),
#else
auto job = m_connection->callApi<Quotient::SetPushRuleJob>(QLatin1String("global"),
PushRuleKind::kindString(kind),
#endif
keyword, keyword,
actions, actions,
QString(), QString(),
@@ -336,7 +341,11 @@ void PushRuleModel::removeKeyword(const QString &keyword)
} }
auto kind = PushRuleKind::kindString(m_rules[index].kind); auto kind = PushRuleKind::kindString(m_rules[index].kind);
#if Quotient_VERSION_MINOR > 8
auto job = m_connection->callApi<Quotient::DeletePushRuleJob>(kind, m_rules[index].id); auto job = m_connection->callApi<Quotient::DeletePushRuleJob>(kind, m_rules[index].id);
#else
auto job = m_connection->callApi<Quotient::DeletePushRuleJob>(QStringLiteral("global"), kind, m_rules[index].id);
#endif
connect(job, &Quotient::BaseJob::failure, this, [this, job, index]() { connect(job, &Quotient::BaseJob::failure, this, [this, job, index]() {
qWarning() << QLatin1String("Unable to remove push rule for keyword %1: ").arg(m_rules[index].id) << job->errorString(); qWarning() << QLatin1String("Unable to remove push rule for keyword %1: ").arg(m_rules[index].id) << job->errorString();
}); });
@@ -344,10 +353,18 @@ void PushRuleModel::removeKeyword(const QString &keyword)
void PushRuleModel::setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled) void PushRuleModel::setNotificationRuleEnabled(const QString &kind, const QString &ruleId, bool enabled)
{ {
#if Quotient_VERSION_MINOR > 8
auto job = m_connection->callApi<Quotient::IsPushRuleEnabledJob>(kind, ruleId); auto job = m_connection->callApi<Quotient::IsPushRuleEnabledJob>(kind, ruleId);
#else
auto job = m_connection->callApi<Quotient::IsPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId);
#endif
connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled, this]() { connect(job, &Quotient::BaseJob::success, this, [job, kind, ruleId, enabled, this]() {
if (job->enabled() != enabled) { if (job->enabled() != enabled) {
#if Quotient_VERSION_MINOR > 8
m_connection->callApi<Quotient::SetPushRuleEnabledJob>(kind, ruleId, enabled); m_connection->callApi<Quotient::SetPushRuleEnabledJob>(kind, ruleId, enabled);
#else
m_connection->callApi<Quotient::SetPushRuleEnabledJob>(QStringLiteral("global"), kind, ruleId, enabled);
#endif
} }
}); });
} }
@@ -361,7 +378,11 @@ void PushRuleModel::setNotificationRuleActions(const QString &kind, const QStrin
actions = actionToVariant(action); actions = actionToVariant(action);
} }
#if Quotient_VERSION_MINOR > 8
m_connection->callApi<Quotient::SetPushRuleActionsJob>(kind, ruleId, actions); m_connection->callApi<Quotient::SetPushRuleActionsJob>(kind, ruleId, actions);
#else
m_connection->callApi<Quotient::SetPushRuleActionsJob>(QStringLiteral("global"), kind, ruleId, actions);
#endif
} }
PushRuleAction::Action PushRuleModel::variantToAction(const QList<QVariant> &actions, bool enabled) PushRuleAction::Action PushRuleModel::variantToAction(const QList<QVariant> &actions, bool enabled)

View File

@@ -286,7 +286,6 @@ QHash<int, QByteArray> RoomTreeModel::roleNames() const
roles[IconRole] = "icon"; roles[IconRole] = "icon";
roles[AttentionRole] = "attention"; roles[AttentionRole] = "attention";
roles[FavouriteRole] = "favourite"; roles[FavouriteRole] = "favourite";
roles[RoomTypeRole] = "roomType";
return roles; return roles;
} }
@@ -386,11 +385,6 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
if (role == FavouriteRole) { if (role == FavouriteRole) {
return room->isFavourite(); return room->isFavourite();
} }
if (role == RoomTypeRole) {
if (room->creation()) {
return room->creation()->contentPart<QString>("type"_L1);
}
}
return {}; return {};
} }

View File

@@ -50,7 +50,6 @@ public:
IconRole, IconRole,
AttentionRole, /**< Whether there are any notifications. */ AttentionRole, /**< Whether there are any notifications. */
FavouriteRole, /**< Whether the room is favourited. */ FavouriteRole, /**< Whether the room is favourited. */
RoomTypeRole, /**< The room's type. */
}; };
Q_ENUM(EventRoles) Q_ENUM(EventRoles)
explicit RoomTreeModel(QObject *parent = nullptr); explicit RoomTreeModel(QObject *parent = nullptr);

View File

@@ -157,11 +157,6 @@ bool SortFilterRoomTreeModel::filterAcceptsRow(int source_row, const QModelIndex
return false; return false;
} }
// Hide rooms with defined types, assuming that data-holding rooms have a defined type
if (!sourceModel()->data(index, RoomTreeModel::RoomTypeRole).toString().isEmpty()) {
return false;
}
static auto config = NeoChatConfig::self(); static auto config = NeoChatConfig::self();
if (config->allRoomsInHome() && RoomManager::instance().currentSpace().isEmpty()) { if (config->allRoomsInHome() && RoomManager::instance().currentSpace().isEmpty()) {
return acceptRoom; return acceptRoom;

View File

@@ -93,7 +93,11 @@ void SpaceChildrenModel::refreshModel()
}); });
} }
#if Quotient_VERSION_MINOR >= 9
void SpaceChildrenModel::insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::SpaceHierarchyRoomsChunk> children, const QModelIndex &parent) void SpaceChildrenModel::insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::SpaceHierarchyRoomsChunk> children, const QModelIndex &parent)
#else
void SpaceChildrenModel::insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::ChildRoomsChunk> children, const QModelIndex &parent)
#endif
{ {
SpaceTreeItem *parentItem = getItem(parent); SpaceTreeItem *parentItem = getItem(parent);

View File

@@ -144,5 +144,9 @@ private:
void refreshModel(); void refreshModel();
#if Quotient_VERSION_MINOR >= 9
void insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::SpaceHierarchyRoomsChunk> children, const QModelIndex &parent = QModelIndex()); void insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::SpaceHierarchyRoomsChunk> children, const QModelIndex &parent = QModelIndex());
#else
void insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::ChildRoomsChunk> children, const QModelIndex &parent = QModelIndex());
#endif
}; };

View File

@@ -6,6 +6,7 @@
#include <Quotient/events/event.h> #include <Quotient/events/event.h>
#include <Quotient/events/stickerevent.h> #include <Quotient/events/stickerevent.h>
#include <Quotient/jobs/basejob.h> #include <Quotient/jobs/basejob.h>
#include <Quotient/omittable.h>
#include <memory> #include <memory>
#include "chatbarcache.h" #include "chatbarcache.h"

View File

@@ -87,7 +87,11 @@ QVariant UserListModel::data(const QModelIndex &index, int role) const
return memberId; return memberId;
} }
if (role == AvatarRole) { if (role == AvatarRole) {
#if Quotient_VERSION_MINOR > 8
return m_currentRoom->member(memberId).avatarUrl(); return m_currentRoom->member(memberId).avatarUrl();
#else
return m_currentRoom->memberAvatar(memberId).url();
#endif
} }
if (role == ObjectRole) { if (role == ObjectRole) {
return QVariant::fromValue(memberId); return QVariant::fromValue(memberId);
@@ -172,7 +176,11 @@ void UserListModel::refreshAllMembers()
if (m_currentRoom != nullptr) { if (m_currentRoom != nullptr) {
m_members = m_currentRoom->joinedMemberIds(); m_members = m_currentRoom->joinedMemberIds();
#if Quotient_VERSION_MINOR > 8
MemberSorter sorter; MemberSorter sorter;
#else
MemberSorter sorter(m_currentRoom);
#endif
std::sort(m_members.begin(), m_members.end(), [&sorter, this](const auto &left, const auto &right) { std::sort(m_members.begin(), m_members.end(), [&sorter, this](const auto &left, const auto &right) {
const auto leftPl = m_currentRoom->getUserPowerLevel(left); const auto leftPl = m_currentRoom->getUserPowerLevel(left);
const auto rightPl = m_currentRoom->getUserPowerLevel(right); const auto rightPl = m_currentRoom->getUserPowerLevel(right);

View File

@@ -261,7 +261,7 @@ Action=Popup
Name=Share Name=Share
Name[ar]=شارك Name[ar]=شارك
Name[ca]=Compartició Name[ca]=Compartició
Name[ca@valencia]=Compartiu Name[ca@valencia]=Compartició
Name[cs]=Sdílet Name[cs]=Sdílet
Name[de]=Teilen Name[de]=Teilen
Name[el]=Κοινοποίηση Name[el]=Κοινοποίηση

View File

@@ -27,18 +27,6 @@
<label>Use s/text/replacement syntax to edit your last message.</label> <label>Use s/text/replacement syntax to edit your last message.</label>
<default>false</default> <default>false</default>
</entry> </entry>
<entry name="SendMessageWith" type="Enum">
<label>Key combination to send a message</label>
<choices>
<choice name="Enter">
<label>Enter</label>
</choice>
<choice name="CtrlEnter">
<label>Ctrl+Enter</label>
</choice>
<default>Enter</default>
</choices>
</entry>
<entry name="ShowLocalMessagesOnRight" type="bool"> <entry name="ShowLocalMessagesOnRight" type="bool">
<label>"Show your messages on the right</label> <label>"Show your messages on the right</label>
<default>true</default> <default>true</default>

View File

@@ -533,6 +533,7 @@ LinkPreviewer *NeoChatConnection::previewerForLink(const QUrl &link)
return previewer; return previewer;
} }
#if Quotient_VERSION_MINOR > 8
KeyImport::Error NeoChatConnection::exportMegolmSessions(const QString &passphrase, const QString &path) KeyImport::Error NeoChatConnection::exportMegolmSessions(const QString &passphrase, const QString &path)
{ {
KeyImport keyImport; KeyImport keyImport;
@@ -547,5 +548,6 @@ KeyImport::Error NeoChatConnection::exportMegolmSessions(const QString &passphra
file.close(); file.close();
return KeyImport::Success; return KeyImport::Success;
} }
#endif
#include "moc_neochatconnection.cpp" #include "moc_neochatconnection.cpp"

View File

@@ -10,7 +10,9 @@
#include <QCoroTask> #include <QCoroTask>
#include <Quotient/connection.h> #include <Quotient/connection.h>
#if Quotient_VERSION_MINOR > 8
#include <Quotient/keyimport.h> #include <Quotient/keyimport.h>
#endif
#include "enums/messagetype.h" #include "enums/messagetype.h"
#include "linkpreviewer.h" #include "linkpreviewer.h"
@@ -158,7 +160,9 @@ public:
*/ */
Q_INVOKABLE QString accountDataJsonString(const QString &type) const; Q_INVOKABLE QString accountDataJsonString(const QString &type) const;
#if Quotient_VERSION_MINOR > 8
Q_INVOKABLE Quotient::KeyImport::Error exportMegolmSessions(const QString &passphrase, const QString &path); Q_INVOKABLE Quotient::KeyImport::Error exportMegolmSessions(const QString &passphrase, const QString &path);
#endif
qsizetype directChatNotifications() const; qsizetype directChatNotifications() const;
bool directChatsHaveHighlightNotifications() const; bool directChatsHaveHighlightNotifications() const;

View File

@@ -74,8 +74,13 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
const auto m_event = evtIt->viewAs<RoomEvent>(); const auto m_event = evtIt->viewAs<RoomEvent>();
QString mxcUrl; QString mxcUrl;
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) { if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
#if Quotient_VERSION_MINOR > 8
if (event->has<EventContent::FileContentBase>()) { if (event->has<EventContent::FileContentBase>()) {
mxcUrl = event->get<EventContent::FileContentBase>()->url().toString(); mxcUrl = event->get<EventContent::FileContentBase>()->url().toString();
#else
if (event->hasFileContent()) {
mxcUrl = event->content()->fileInfo()->url().toString();
#endif
} }
} else if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) { } else if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) {
mxcUrl = event->image().url().toString(); mxcUrl = event->image().url().toString();
@@ -216,7 +221,11 @@ QCoro::Task<void> NeoChatRoom::doUploadFile(QUrl url, QString body)
auto mime = QMimeDatabase().mimeTypeForUrl(url); auto mime = QMimeDatabase().mimeTypeForUrl(url);
url.setScheme("file"_ls); url.setScheme("file"_ls);
QFileInfo fileInfo(url.isLocalFile() ? url.toLocalFile() : url.toString()); QFileInfo fileInfo(url.isLocalFile() ? url.toLocalFile() : url.toString());
#if Quotient_VERSION_MINOR > 8
EventContent::FileContentBase *content; EventContent::FileContentBase *content;
#else
EventContent::TypedBase *content;
#endif
if (mime.name().startsWith("image/"_ls)) { if (mime.name().startsWith("image/"_ls)) {
QImage image(url.toLocalFile()); QImage image(url.toLocalFile());
content = new EventContent::ImageContent(url, fileInfo.size(), mime, image.size(), fileInfo.fileName()); content = new EventContent::ImageContent(url, fileInfo.size(), mime, image.size(), fileInfo.fileName());
@@ -231,7 +240,11 @@ QCoro::Task<void> NeoChatRoom::doUploadFile(QUrl url, QString body)
} else { } else {
content = new EventContent::FileContent(url, fileInfo.size(), mime, fileInfo.fileName()); content = new EventContent::FileContent(url, fileInfo.size(), mime, fileInfo.fileName());
} }
#if Quotient_VERSION_MINOR > 8
QString txnId = postFile(body.isEmpty() ? url.fileName() : body, std::unique_ptr<EventContent::FileContentBase>(content)); QString txnId = postFile(body.isEmpty() ? url.fileName() : body, std::unique_ptr<EventContent::FileContentBase>(content));
#else
QString txnId = postFile(body.isEmpty() ? url.fileName() : body, content);
#endif
setHasFileUploading(true); setHasFileUploading(true);
connect(this, &Room::fileTransferCompleted, [this, txnId](const QString &id, FileSourceInfo) { connect(this, &Room::fileTransferCompleted, [this, txnId](const QString &id, FileSourceInfo) {
if (id == txnId) { if (id == txnId) {
@@ -363,8 +376,13 @@ bool NeoChatRoom::lastEventIsSpoiler() const
{ {
if (auto event = lastEvent()) { if (auto event = lastEvent()) {
if (auto e = eventCast<const RoomMessageEvent>(event)) { if (auto e = eventCast<const RoomMessageEvent>(event)) {
#if Quotient_VERSION_MINOR > 8
if (e->has<EventContent::TextContent>() && e->content() && e->mimeType().name() == "text/html"_ls) { if (e->has<EventContent::TextContent>() && e->content() && e->mimeType().name() == "text/html"_ls) {
auto htmlBody = e->get<EventContent::TextContent>()->body; auto htmlBody = e->get<EventContent::TextContent>()->body;
#else
if (e->hasTextContent() && e->content() && e->mimeType().name() == "text/html"_ls) {
auto htmlBody = static_cast<const Quotient::EventContent::TextContent *>(e->content())->body;
#endif
return htmlBody.contains("data-mx-spoiler"_ls); return htmlBody.contains("data-mx-spoiler"_ls);
} }
} }
@@ -896,7 +914,11 @@ QCoro::Task<void> NeoChatRoom::doDeleteMessagesByUser(const QString &user, QStri
} }
for (const auto &e : events) { for (const auto &e : events) {
auto job = connection()->callApi<RedactEventJob>(id(), QString::fromLatin1(QUrl::toPercentEncoding(e)), connection()->generateTxnId(), reason); auto job = connection()->callApi<RedactEventJob>(id(), QString::fromLatin1(QUrl::toPercentEncoding(e)), connection()->generateTxnId(), reason);
#if Quotient_VERSION_MINOR > 8
co_await qCoro(job.get(), &BaseJob::finished); co_await qCoro(job.get(), &BaseJob::finished);
#else
co_await qCoro(job, &BaseJob::finished);
#endif
if (job->error() != BaseJob::Success) { if (job->error() != BaseJob::Success) {
qWarning() << "Error: \"" << job->error() << "\" while deleting messages. Aborting"; qWarning() << "Error: \"" << job->error() << "\" while deleting messages. Aborting";
break; break;
@@ -1195,7 +1217,11 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
for (const auto &i : roomRuleArray) { for (const auto &i : roomRuleArray) {
QJsonObject roomRule = i.toObject(); QJsonObject roomRule = i.toObject();
if (roomRule["rule_id"_ls] == id()) { if (roomRule["rule_id"_ls] == id()) {
#if Quotient_VERSION_MINOR > 8
connection()->callApi<DeletePushRuleJob>("room"_ls, id()); connection()->callApi<DeletePushRuleJob>("room"_ls, id());
#else
connection()->callApi<DeletePushRuleJob>(QLatin1String("global"), "room"_ls, id());
#endif
} }
} }
} }
@@ -1206,7 +1232,11 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
for (const auto &i : overrideRuleArray) { for (const auto &i : overrideRuleArray) {
QJsonObject overrideRule = i.toObject(); QJsonObject overrideRule = i.toObject();
if (overrideRule["rule_id"_ls] == id()) { if (overrideRule["rule_id"_ls] == id()) {
#if Quotient_VERSION_MINOR > 8
connection()->callApi<DeletePushRuleJob>("override"_ls, id()); connection()->callApi<DeletePushRuleJob>("override"_ls, id());
#else
connection()->callApi<DeletePushRuleJob>("global"_ls, "override"_ls, id());
#endif
} }
} }
} }
@@ -1242,9 +1272,17 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
const QList<PushCondition> conditions = {pushCondition}; const QList<PushCondition> conditions = {pushCondition};
// Add new override rule and make sure it's enabled // Add new override rule and make sure it's enabled
#if Quotient_VERSION_MINOR > 8
auto job = connection()->callApi<SetPushRuleJob>("override"_ls, id(), actions, QString(), QString(), conditions, QString()); auto job = connection()->callApi<SetPushRuleJob>("override"_ls, id(), actions, QString(), QString(), conditions, QString());
#else
auto job = connection()->callApi<SetPushRuleJob>("global"_ls, "override"_ls, id(), actions, QString(), QString(), conditions, QString());
#endif
connect(job, &BaseJob::success, this, [this]() { connect(job, &BaseJob::success, this, [this]() {
#if Quotient_VERSION_MINOR > 8
auto enableJob = connection()->callApi<SetPushRuleEnabledJob>("override"_ls, id(), true); auto enableJob = connection()->callApi<SetPushRuleEnabledJob>("override"_ls, id(), true);
#else
auto enableJob = connection()->callApi<SetPushRuleEnabledJob>("global"_ls, "override"_ls, id(), true);
#endif
connect(enableJob, &BaseJob::success, this, [this]() { connect(enableJob, &BaseJob::success, this, [this]() {
m_pushNotificationStateUpdating = false; m_pushNotificationStateUpdating = false;
}); });
@@ -1268,9 +1306,17 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
// No conditions for a room rule // No conditions for a room rule
const QList<PushCondition> conditions; const QList<PushCondition> conditions;
#if Quotient_VERSION_MINOR > 8
auto setJob = connection()->callApi<SetPushRuleJob>("room"_ls, id(), actions, QString(), QString(), conditions, QString()); auto setJob = connection()->callApi<SetPushRuleJob>("room"_ls, id(), actions, QString(), QString(), conditions, QString());
#else
auto setJob = connection()->callApi<SetPushRuleJob>("global"_ls, "room"_ls, id(), actions, QString(), QString(), conditions, QString());
#endif
connect(setJob, &BaseJob::success, this, [this]() { connect(setJob, &BaseJob::success, this, [this]() {
#if Quotient_VERSION_MINOR > 8
auto enableJob = connection()->callApi<SetPushRuleEnabledJob>("room"_ls, id(), true); auto enableJob = connection()->callApi<SetPushRuleEnabledJob>("room"_ls, id(), true);
#else
auto enableJob = connection()->callApi<SetPushRuleEnabledJob>("global"_ls, "room"_ls, id(), true);
#endif
connect(enableJob, &BaseJob::success, this, [this]() { connect(enableJob, &BaseJob::success, this, [this]() {
m_pushNotificationStateUpdating = false; m_pushNotificationStateUpdating = false;
}); });
@@ -1299,9 +1345,17 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
const QList<PushCondition> conditions; const QList<PushCondition> conditions;
// Add new room rule and make sure enabled // Add new room rule and make sure enabled
#if Quotient_VERSION_MINOR > 8
auto setJob = connection()->callApi<SetPushRuleJob>("room"_ls, id(), actions, QString(), QString(), conditions, QString()); auto setJob = connection()->callApi<SetPushRuleJob>("room"_ls, id(), actions, QString(), QString(), conditions, QString());
#else
auto setJob = connection()->callApi<SetPushRuleJob>("global"_ls, "room"_ls, id(), actions, QString(), QString(), conditions, QString());
#endif
connect(setJob, &BaseJob::success, this, [this]() { connect(setJob, &BaseJob::success, this, [this]() {
#if Quotient_VERSION_MINOR > 8
auto enableJob = connection()->callApi<SetPushRuleEnabledJob>("room"_ls, id(), true); auto enableJob = connection()->callApi<SetPushRuleEnabledJob>("room"_ls, id(), true);
#else
auto enableJob = connection()->callApi<SetPushRuleEnabledJob>("global"_ls, "room"_ls, id(), true);
#endif
connect(enableJob, &BaseJob::success, this, [this]() { connect(enableJob, &BaseJob::success, this, [this]() {
m_pushNotificationStateUpdating = false; m_pushNotificationStateUpdating = false;
}); });
@@ -1392,7 +1446,11 @@ void NeoChatRoom::openEventMediaExternally(const QString &eventId)
const auto evtIt = findInTimeline(eventId); const auto evtIt = findInTimeline(eventId);
if (evtIt != messageEvents().rend() && is<RoomMessageEvent>(**evtIt)) { if (evtIt != messageEvents().rend() && is<RoomMessageEvent>(**evtIt)) {
const auto event = evtIt->viewAs<RoomMessageEvent>(); const auto event = evtIt->viewAs<RoomMessageEvent>();
#if Quotient_VERSION_MINOR > 8
if (event->has<EventContent::FileContent>()) { if (event->has<EventContent::FileContent>()) {
#else
if (event->hasFileContent()) {
#endif
const auto transferInfo = cachedFileTransferInfo(event); const auto transferInfo = cachedFileTransferInfo(event);
if (transferInfo.completed()) { if (transferInfo.completed()) {
UrlHelper helper; UrlHelper helper;
@@ -1425,7 +1483,11 @@ void NeoChatRoom::copyEventMedia(const QString &eventId)
const auto evtIt = findInTimeline(eventId); const auto evtIt = findInTimeline(eventId);
if (evtIt != messageEvents().rend() && is<RoomMessageEvent>(**evtIt)) { if (evtIt != messageEvents().rend() && is<RoomMessageEvent>(**evtIt)) {
const auto event = evtIt->viewAs<RoomMessageEvent>(); const auto event = evtIt->viewAs<RoomMessageEvent>();
#if Quotient_VERSION_MINOR > 8
if (event->has<EventContent::FileContent>()) { if (event->has<EventContent::FileContent>()) {
#else
if (event->hasFileContent()) {
#endif
const auto transferInfo = fileTransferInfo(eventId); const auto transferInfo = fileTransferInfo(eventId);
if (transferInfo.completed()) { if (transferInfo.completed()) {
Clipboard clipboard; Clipboard clipboard;
@@ -1458,8 +1520,13 @@ FileTransferInfo NeoChatRoom::cachedFileTransferInfo(const Quotient::RoomEvent *
QString mxcUrl; QString mxcUrl;
int total = 0; int total = 0;
if (auto evt = eventCast<const Quotient::RoomMessageEvent>(event)) { if (auto evt = eventCast<const Quotient::RoomMessageEvent>(event)) {
#if Quotient_VERSION_MINOR > 8
if (evt->has<EventContent::FileContent>()) { if (evt->has<EventContent::FileContent>()) {
const auto fileContent = evt->get<EventContent::FileContent>(); const auto fileContent = evt->get<EventContent::FileContent>();
#else
if (evt->hasFileContent()) {
const auto fileContent = evt->content()->fileInfo();
#endif
mxcUrl = fileContent->url().toString(); mxcUrl = fileContent->url().toString();
total = fileContent->payloadSize; total = fileContent->payloadSize;
@@ -1817,4 +1884,13 @@ void NeoChatRoom::setRoomState(const QString &type, const QString &stateKey, con
setState(type, stateKey, QJsonDocument::fromJson(content).object()); setState(type, stateKey, QJsonDocument::fromJson(content).object());
} }
#if Quotient_VERSION_MINOR == 8
QList<RoomMember> NeoChatRoom::otherMembersTyping() const
{
auto memberTyping = membersTyping();
memberTyping.removeAll(localMember());
return memberTyping;
}
#endif
#include "moc_neochatroom.cpp" #include "moc_neochatroom.cpp"

View File

@@ -208,6 +208,10 @@ class NeoChatRoom : public Quotient::Room
*/ */
Q_PROPERTY(ChatBarCache *threadCache READ threadCache CONSTANT) Q_PROPERTY(ChatBarCache *threadCache READ threadCache CONSTANT)
#if Quotient_VERSION_MINOR == 8
Q_PROPERTY(QList<Quotient::RoomMember> otherMembersTyping READ otherMembersTyping NOTIFY typingChanged)
#endif
public: public:
explicit NeoChatRoom(Quotient::Connection *connection, QString roomId, Quotient::JoinState joinState = {}); explicit NeoChatRoom(Quotient::Connection *connection, QString roomId, Quotient::JoinState joinState = {});
@@ -619,6 +623,10 @@ private:
void cleanupExtraEventRange(Quotient::RoomEventsRange events); void cleanupExtraEventRange(Quotient::RoomEventsRange events);
void cleanupExtraEvent(const QString &eventId); void cleanupExtraEvent(const QString &eventId);
#if Quotient_VERSION_MINOR == 8
QList<Quotient::RoomMember> otherMembersTyping() const;
#endif
private Q_SLOTS: private Q_SLOTS:
void updatePushNotificationState(QString type); void updatePushNotificationState(QString type);

View File

@@ -73,7 +73,11 @@ QString NeochatRoomMember::displayName() const
} }
const auto memberObject = m_room->member(m_memberId); const auto memberObject = m_room->member(m_memberId);
#if Quotient_VERSION_MINOR > 8
return memberObject.isEmpty() ? id() : memberObject.displayName(); return memberObject.isEmpty() ? id() : memberObject.displayName();
#else
return memberObject.id().isEmpty() ? id() : memberObject.displayName();
#endif
} }
QString NeochatRoomMember::htmlSafeDisplayName() const QString NeochatRoomMember::htmlSafeDisplayName() const
@@ -83,7 +87,11 @@ QString NeochatRoomMember::htmlSafeDisplayName() const
} }
const auto memberObject = m_room->member(m_memberId); const auto memberObject = m_room->member(m_memberId);
#if Quotient_VERSION_MINOR > 8
return memberObject.isEmpty() ? id() : memberObject.htmlSafeDisplayName(); return memberObject.isEmpty() ? id() : memberObject.htmlSafeDisplayName();
#else
return memberObject.id().isEmpty() ? id() : memberObject.htmlSafeDisplayName();
#endif
} }
QString NeochatRoomMember::fullName() const QString NeochatRoomMember::fullName() const
@@ -93,7 +101,11 @@ QString NeochatRoomMember::fullName() const
} }
const auto memberObject = m_room->member(m_memberId); const auto memberObject = m_room->member(m_memberId);
#if Quotient_VERSION_MINOR > 8
return memberObject.isEmpty() ? id() : memberObject.fullName(); return memberObject.isEmpty() ? id() : memberObject.fullName();
#else
return memberObject.id().isEmpty() ? id() : memberObject.fullName();
#endif
} }
QString NeochatRoomMember::htmlSafeFullName() const QString NeochatRoomMember::htmlSafeFullName() const
@@ -103,7 +115,11 @@ QString NeochatRoomMember::htmlSafeFullName() const
} }
const auto memberObject = m_room->member(m_memberId); const auto memberObject = m_room->member(m_memberId);
#if Quotient_VERSION_MINOR > 8
return memberObject.isEmpty() ? id() : memberObject.htmlSafeFullName(); return memberObject.isEmpty() ? id() : memberObject.htmlSafeFullName();
#else
return memberObject.id().isEmpty() ? id() : memberObject.htmlSafeFullName();
#endif
} }
QString NeochatRoomMember::disambiguatedName() const QString NeochatRoomMember::disambiguatedName() const
@@ -113,7 +129,11 @@ QString NeochatRoomMember::disambiguatedName() const
} }
const auto memberObject = m_room->member(m_memberId); const auto memberObject = m_room->member(m_memberId);
#if Quotient_VERSION_MINOR > 8
return memberObject.isEmpty() ? id() : memberObject.disambiguatedName(); return memberObject.isEmpty() ? id() : memberObject.disambiguatedName();
#else
return memberObject.id().isEmpty() ? id() : memberObject.disambiguatedName();
#endif
} }
QString NeochatRoomMember::htmlSafeDisambiguatedName() const QString NeochatRoomMember::htmlSafeDisambiguatedName() const
@@ -123,7 +143,11 @@ QString NeochatRoomMember::htmlSafeDisambiguatedName() const
} }
const auto memberObject = m_room->member(m_memberId); const auto memberObject = m_room->member(m_memberId);
#if Quotient_VERSION_MINOR > 8
return memberObject.isEmpty() ? id() : memberObject.htmlSafeDisambiguatedName(); return memberObject.isEmpty() ? id() : memberObject.htmlSafeDisambiguatedName();
#else
return memberObject.id().isEmpty() ? id() : memberObject.htmlSafeDisambiguatedName();
#endif
} }
int NeochatRoomMember::hue() const int NeochatRoomMember::hue() const

View File

@@ -148,7 +148,11 @@ void NotificationsManager::processNotificationJob(QPointer<NeoChatConnection> co
QImage avatar_image; QImage avatar_image;
if (!sender.avatarUrl().isEmpty()) { if (!sender.avatarUrl().isEmpty()) {
#if Quotient_VERSION_MINOR > 8
avatar_image = room->member(sender.id()).avatar(128, 128, {}); avatar_image = room->member(sender.id()).avatar(128, 128, {});
#else
avatar_image = room->memberAvatar(sender.id()).get(connection, 128, {});
#endif
} else { } else {
avatar_image = room->avatar(128); avatar_image = room->avatar(128);
} }
@@ -294,7 +298,11 @@ void NotificationsManager::doPostInviteNotification(QPointer<NeoChatRoom> room)
QImage avatar_image; QImage avatar_image;
if (roomMemberEvent && !room->member(roomMemberEvent->senderId()).avatarUrl().isEmpty()) { if (roomMemberEvent && !room->member(roomMemberEvent->senderId()).avatarUrl().isEmpty()) {
#if Quotient_VERSION_MINOR > 8
avatar_image = room->member(roomMemberEvent->senderId()).avatar(128, 128, {}); avatar_image = room->member(roomMemberEvent->senderId()).avatar(128, 128, {});
#else
avatar_image = room->memberAvatar(roomMemberEvent->senderId()).get(room->connection(), 128, [] {});
#endif
} else { } else {
qWarning() << "using this room's avatar"; qWarning() << "using this room's avatar";
avatar_image = room->avatar(128); avatar_image = room->avatar(128);

View File

@@ -30,7 +30,6 @@ class PollHandler : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("Use NeoChatRoom::poll")
/** /**
* @brief The question for the poll. * @brief The question for the poll.
@@ -92,7 +91,7 @@ Q_SIGNALS:
void hasEndedChanged(); void hasEndedChanged();
private: private:
const Quotient::PollStartEvent *m_pollStartEvent = nullptr; const Quotient::PollStartEvent *m_pollStartEvent;
void updatePoll(Quotient::RoomEventsRange events); void updatePoll(Quotient::RoomEventsRange events);

View File

@@ -26,7 +26,6 @@
"Name[nn]": "Tobias Fella", "Name[nn]": "Tobias Fella",
"Name[pl]": "Tobias Fella", "Name[pl]": "Tobias Fella",
"Name[ru]": "Tobias Fella", "Name[ru]": "Tobias Fella",
"Name[sk]": "Tobias Fella",
"Name[sl]": "Tobias Fella", "Name[sl]": "Tobias Fella",
"Name[sv]": "Tobias Fella", "Name[sv]": "Tobias Fella",
"Name[ta]": "டோபியாஸ் ஃபெல்லா", "Name[ta]": "டோபியாஸ் ஃபெல்லா",
@@ -94,7 +93,6 @@
"Name[nn]": "NeoChat", "Name[nn]": "NeoChat",
"Name[pl]": "NeoChat", "Name[pl]": "NeoChat",
"Name[ru]": "NeoChat", "Name[ru]": "NeoChat",
"Name[sk]": "NeoChat",
"Name[sl]": "NeoChat", "Name[sl]": "NeoChat",
"Name[sv]": "NeoChat", "Name[sv]": "NeoChat",
"Name[ta]": "நியோச்சாட்", "Name[ta]": "நியோச்சாட்",

View File

@@ -87,21 +87,13 @@ SearchPage {
} }
listHeaderDelegate: Delegates.RoundedItemDelegate { listHeaderDelegate: Delegates.RoundedItemDelegate {
id: delegate
onClicked: _private.openManualRoomDialog() onClicked: _private.openManualRoomDialog()
activeFocusOnTab: false // We handle moving to this item via up/down arrows, otherwise the tab order is wacky activeFocusOnTab: false // We handle moving to this item via up/down arrows, otherwise the tab order is wacky
text: i18n("Enter a Room Manually") text: i18n("Enter a room address")
icon.name: "compass" icon.name: "compass"
icon.width: Kirigami.Units.gridUnit * 2 icon.width: Kirigami.Units.gridUnit * 2
icon.height: Kirigami.Units.gridUnit * 2 icon.height: Kirigami.Units.gridUnit * 2
contentItem: Kirigami.IconTitleSubtitle {
icon: icon.fromControlsIcon(delegate.icon)
title: delegate.text
subtitle: i18n("If you already know a room's address or alias, and it isn't shown here.")
}
} }
listFooterDelegate: QQC2.ProgressBar { listFooterDelegate: QQC2.ProgressBar {

View File

@@ -23,7 +23,7 @@ Kirigami.Dialog {
*/ */
signal roomSelected(string roomId, string displayName, url avatarUrl, string alias, string topic, int memberCount, bool isJoined) signal roomSelected(string roomId, string displayName, url avatarUrl, string alias, string topic, int memberCount, bool isJoined)
title: i18nc("@title", "Manually Enter a Room") title: i18nc("@title", "Room ID or Alias")
width: Math.min(root.Window.window.width, Kirigami.Units.gridUnit * 24) width: Math.min(root.Window.window.width, Kirigami.Units.gridUnit * 24)
leftPadding: 0 leftPadding: 0

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