Compare commits
41 Commits
work/ngrah
...
v25.08.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5a4b2a50a | ||
|
|
17fdad3afd | ||
|
|
64bc2691cb | ||
|
|
c7df34a9c8 | ||
|
|
1525c74b10 | ||
|
|
58b85622c5 | ||
|
|
796470d0e0 | ||
|
|
3a43d99575 | ||
|
|
a62798ef1e | ||
|
|
349d0c5f5f | ||
|
|
c917fc0166 | ||
|
|
a4f2d8fca1 | ||
|
|
fd18f88adf | ||
|
|
546694b08e | ||
|
|
699026fc2f | ||
|
|
c61c2d7437 | ||
|
|
56babbc1c5 | ||
|
|
74b3e703c1 | ||
|
|
f620221113 | ||
|
|
896c001430 | ||
|
|
defee77c96 | ||
|
|
4328ab8e89 | ||
|
|
54b081abba | ||
|
|
29686608e1 | ||
|
|
b720ecf29d | ||
|
|
fc859d679a | ||
|
|
3595ad9293 | ||
|
|
73f8ebc54e | ||
|
|
19cf534acd | ||
|
|
9b86088e26 | ||
|
|
a93117fcd6 | ||
|
|
ee20c90498 | ||
|
|
860a2267d5 | ||
|
|
cb9b2648ca | ||
|
|
1e798b6c15 | ||
|
|
124ffba5e0 | ||
|
|
3aaaa610df | ||
|
|
18e883834c | ||
|
|
6acbd2dffd | ||
|
|
dc5c27aa2d | ||
|
|
26774bbe56 |
@@ -1,2 +0,0 @@
|
|||||||
[General]
|
|
||||||
disableUnqualifiedAccess = "i18nc,xi18nc,i18ncp"
|
|
||||||
@@ -20,16 +20,8 @@
|
|||||||
"--talk-name=org.kde.kwalletd5",
|
"--talk-name=org.kde.kwalletd5",
|
||||||
"--talk-name=org.kde.StatusNotifierWatcher",
|
"--talk-name=org.kde.StatusNotifierWatcher",
|
||||||
"--talk-name=org.freedesktop.secrets",
|
"--talk-name=org.freedesktop.secrets",
|
||||||
"--talk-name=org.kde.kuiserver",
|
|
||||||
"--own-name=org.kde.StatusNotifierItem-2-2"
|
"--own-name=org.kde.StatusNotifierItem-2-2"
|
||||||
],
|
],
|
||||||
"cleanup": [
|
|
||||||
"/include",
|
|
||||||
"/lib/*.a",
|
|
||||||
"/lib/cmake",
|
|
||||||
"/lib/pkgconfig",
|
|
||||||
"/share/ndk-modules"
|
|
||||||
],
|
|
||||||
"modules": [
|
"modules": [
|
||||||
{
|
{
|
||||||
"name": "kirigamiaddons",
|
"name": "kirigamiaddons",
|
||||||
@@ -90,8 +82,8 @@
|
|||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.7.tar.xz",
|
"url": "https://download.gnome.org/sources/libsecret/0.21/libsecret-0.21.6.tar.xz",
|
||||||
"sha256": "6b452e4750590a2b5617adc40026f28d2f4903de15f1250e1d1c40bfd68ed55e",
|
"sha256": "747b8c175be108c880d3adfb9c3537ea66e520e4ad2dccf5dce58003aeeca090",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "gnome",
|
"type": "gnome",
|
||||||
"name": "libsecret",
|
"name": "libsecret",
|
||||||
@@ -164,13 +156,13 @@
|
|||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://download.kde.org/stable/release-service/25.04.3/src/kunifiedpush-25.04.3.tar.xz",
|
"url": "https://download.kde.org/stable/kunifiedpush/kunifiedpush-1.0.0.tar.xz",
|
||||||
"sha256": "a16ffe4117b14baa02f3b8ae7de9e509a17359c1b67dcd851aef4f3c3661a1df",
|
"sha256": "2ddeba21306d0307114ec50a2c38159ec62359f9fc6cdd58da30a369fbd550cf",
|
||||||
"x-checker-data": {
|
"x-checker-data": {
|
||||||
"type": "anitya",
|
"type": "anitya",
|
||||||
"project-id": 8763,
|
"project-id": 375055,
|
||||||
"stable-only": true,
|
"stable-only": true,
|
||||||
"url-template": "https://download.kde.org/stable/release-service/$version/src/kunifiedpush-$version.tar.xz"
|
"url-template": "https://download.kde.org/stable/kunifiedpush/kunifiedpush-$version.tar.xz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ 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 "25")
|
set(RELEASE_SERVICE_VERSION_MAJOR "25")
|
||||||
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
set(RELEASE_SERVICE_VERSION_MINOR "08")
|
||||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
set(RELEASE_SERVICE_VERSION_MICRO "0")
|
||||||
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})
|
||||||
|
|
||||||
set(KF_MIN_VERSION "6.16")
|
set(KF_MIN_VERSION "6.12")
|
||||||
set(QT_MIN_VERSION "6.5")
|
set(QT_MIN_VERSION "6.5")
|
||||||
|
|
||||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||||
|
|||||||
@@ -88,9 +88,3 @@ path = "memorytests/memtest-sync.json"
|
|||||||
precedence = "aggregate"
|
precedence = "aggregate"
|
||||||
SPDX-FileCopyrightText = "2024 James Graham <james.h.graham@protonmail.com>"
|
SPDX-FileCopyrightText = "2024 James Graham <james.h.graham@protonmail.com>"
|
||||||
SPDX-License-Identifier = "BSD-2-Clause"
|
SPDX-License-Identifier = "BSD-2-Clause"
|
||||||
|
|
||||||
[[annotations]]
|
|
||||||
path = ".contextProperties.ini"
|
|
||||||
precedence = "aggregate"
|
|
||||||
SPDX-FileCopyrightText = "2025 Tobias Fella <tobias.fella@kde.org>"
|
|
||||||
SPDX-License-Identifier = "BSD-2-Clause"
|
|
||||||
|
|||||||
@@ -92,9 +92,3 @@ ecm_add_test(
|
|||||||
LINK_LIBRARIES neochat Qt::Test neochat_server
|
LINK_LIBRARIES neochat Qt::Test neochat_server
|
||||||
TEST_NAME actionstest
|
TEST_NAME actionstest
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_add_test(
|
|
||||||
roommanagertest.cpp
|
|
||||||
LINK_LIBRARIES neochat Qt::Test neochat_server
|
|
||||||
TEST_NAME roommanagertest
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
|
||||||
#include <QSignalSpy>
|
|
||||||
#include <Quotient/roommember.h>
|
#include <Quotient/roommember.h>
|
||||||
#include <Quotient/syncdata.h>
|
#include <Quotient/syncdata.h>
|
||||||
#include <qtestcase.h>
|
#include <qtestcase.h>
|
||||||
@@ -33,7 +32,6 @@ private Q_SLOTS:
|
|||||||
void noRoom();
|
void noRoom();
|
||||||
void badParent();
|
void badParent();
|
||||||
void reply();
|
void reply();
|
||||||
void replyMissingUser();
|
|
||||||
void edit();
|
void edit();
|
||||||
void attachment();
|
void attachment();
|
||||||
};
|
};
|
||||||
@@ -104,33 +102,6 @@ void ChatBarCacheTest::reply()
|
|||||||
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
|
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
|
||||||
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
|
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
||||||
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatBarCacheTest::replyMissingUser()
|
|
||||||
{
|
|
||||||
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
|
|
||||||
chatBarCache->setText(u"some text"_s);
|
|
||||||
chatBarCache->setAttachmentPath(u"some/path"_s);
|
|
||||||
chatBarCache->setReplyId(u"$153456789:example.org"_s);
|
|
||||||
|
|
||||||
QCOMPARE(chatBarCache->text(), u"some text"_s);
|
|
||||||
QCOMPARE(chatBarCache->isReplying(), true);
|
|
||||||
QCOMPARE(chatBarCache->replyId(), u"$153456789:example.org"_s);
|
|
||||||
QCOMPARE(chatBarCache->isEditing(), false);
|
|
||||||
QCOMPARE(chatBarCache->editId(), QString());
|
|
||||||
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
|
|
||||||
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
|
|
||||||
QCOMPARE(chatBarCache->attachmentPath(), QString());
|
|
||||||
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
|
|
||||||
|
|
||||||
QSignalSpy relationAuthorIsPresentSpy(chatBarCache.get(), &ChatBarCache::relationAuthorIsPresentChanged);
|
|
||||||
|
|
||||||
// sync again, which will simulate the reply user leaving the room
|
|
||||||
room->syncNewEvents(u"test-min-sync-extra-sync.json"_s);
|
|
||||||
|
|
||||||
QTRY_COMPARE(relationAuthorIsPresentSpy.count(), 1);
|
|
||||||
QCOMPARE(chatBarCache->relationAuthorIsPresent(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatBarCacheTest::edit()
|
void ChatBarCacheTest::edit()
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"state": {
|
|
||||||
"events": [
|
|
||||||
{
|
|
||||||
"content": {
|
|
||||||
"membership": "leave"
|
|
||||||
},
|
|
||||||
"event_id": "$1432735824666PhrSA:example.org",
|
|
||||||
"origin_server_ts": 1432735824666,
|
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
|
||||||
"sender": "@example:example.org",
|
|
||||||
"state_key": "@example:example.org",
|
|
||||||
"type": "m.room.member",
|
|
||||||
"unsigned": {
|
|
||||||
"replaces_state": "$143273582443PhrSn:example.org"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <Quotient/roommember.h>
|
#include <Quotient/roommember.h>
|
||||||
#include <Quotient/syncdata.h>
|
#include <Quotient/syncdata.h>
|
||||||
|
|
||||||
#include "models/eventmessagecontentmodel.h"
|
#include "models/messagecontentmodel.h"
|
||||||
|
|
||||||
#include "neochatconnection.h"
|
#include "neochatconnection.h"
|
||||||
#include "testutils.h"
|
#include "testutils.h"
|
||||||
@@ -39,13 +39,13 @@ void MessageContentModelTest::initTestCase()
|
|||||||
void MessageContentModelTest::missingEvent()
|
void MessageContentModelTest::missingEvent()
|
||||||
{
|
{
|
||||||
auto room = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
auto room = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
||||||
auto model1 = EventMessageContentModel(room, u"$153456789:example.org"_s);
|
auto model1 = MessageContentModel(room, u"$153456789:example.org"_s);
|
||||||
|
|
||||||
QCOMPARE(model1.rowCount(), 1);
|
QCOMPARE(model1.rowCount(), 1);
|
||||||
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
QCOMPARE(model1.data(model1.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
||||||
QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading"_s);
|
QCOMPARE(model1.data(model1.index(0), MessageContentModel::DisplayRole), u"Loading"_s);
|
||||||
|
|
||||||
auto model2 = EventMessageContentModel(room, u"$153456789:example.org"_s, true);
|
auto model2 = MessageContentModel(room, u"$153456789:example.org"_s, true);
|
||||||
|
|
||||||
QCOMPARE(model2.rowCount(), 1);
|
QCOMPARE(model2.rowCount(), 1);
|
||||||
QCOMPARE(model2.data(model2.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
QCOMPARE(model2.data(model2.index(0), MessageContentModel::ComponentTypeRole), MessageComponentType::Loading);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include <Quotient/events/roommessageevent.h>
|
#include <Quotient/events/roommessageevent.h>
|
||||||
|
|
||||||
#include "models/eventmessagecontentmodel.h"
|
#include "models/messagecontentmodel.h"
|
||||||
#include "testutils.h"
|
#include "testutils.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -21,7 +21,7 @@ class ReactionModelTest : public QObject
|
|||||||
private:
|
private:
|
||||||
Connection *connection = nullptr;
|
Connection *connection = nullptr;
|
||||||
TestUtils::TestRoom *room = nullptr;
|
TestUtils::TestRoom *room = nullptr;
|
||||||
EventMessageContentModel *parentModel;
|
MessageContentModel *parentModel;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
@@ -34,7 +34,7 @@ void ReactionModelTest::initTestCase()
|
|||||||
{
|
{
|
||||||
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
connection = Connection::makeMockConnection(u"@bob:kde.org"_s);
|
||||||
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-reactionmodel-sync.json"_s);
|
room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-reactionmodel-sync.json"_s);
|
||||||
parentModel = new EventMessageContentModel(room, "123456"_L1);
|
parentModel = new MessageContentModel(room, "123456"_L1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReactionModelTest::basicReaction()
|
void ReactionModelTest::basicReaction()
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QSignalSpy>
|
|
||||||
#include <QTest>
|
|
||||||
#include <QVariantList>
|
|
||||||
|
|
||||||
#include "accountmanager.h"
|
|
||||||
#include "models/actionsmodel.h"
|
|
||||||
#include "roommanager.h"
|
|
||||||
|
|
||||||
#include "server.h"
|
|
||||||
#include "testutils.h"
|
|
||||||
|
|
||||||
using namespace Quotient;
|
|
||||||
|
|
||||||
class RoomManagerTest : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
private:
|
|
||||||
NeoChatConnection *connection = nullptr;
|
|
||||||
NeoChatRoom *room = nullptr;
|
|
||||||
|
|
||||||
Server server;
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void initTestCase();
|
|
||||||
void testMaximizeMedia();
|
|
||||||
};
|
|
||||||
|
|
||||||
void RoomManagerTest::initTestCase()
|
|
||||||
{
|
|
||||||
Connection::setRoomType<NeoChatRoom>();
|
|
||||||
server.start();
|
|
||||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
|
||||||
auto accountManager = new AccountManager(true);
|
|
||||||
QSignalSpy spy(accountManager, &AccountManager::connectionAdded);
|
|
||||||
connection = dynamic_cast<NeoChatConnection *>(accountManager->accounts()->front());
|
|
||||||
QVERIFY(connection);
|
|
||||||
auto roomId = server.createRoom(u"@user:localhost:1234"_s);
|
|
||||||
|
|
||||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
|
||||||
// We need to wait for two syncs, as the next one won't have the changes yet
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
room = dynamic_cast<NeoChatRoom *>(connection->room(roomId));
|
|
||||||
QVERIFY(room);
|
|
||||||
RoomManager::instance().setConnection(connection);
|
|
||||||
QSignalSpy roomSpy(&RoomManager::instance(), &RoomManager::currentRoomChanged);
|
|
||||||
RoomManager::instance().resolveResource(room->id());
|
|
||||||
QVERIFY(roomSpy.size() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoomManagerTest::testMaximizeMedia()
|
|
||||||
{
|
|
||||||
QSignalSpy spy(&RoomManager::instance(), &RoomManager::showMaximizedMedia);
|
|
||||||
QSignalSpy syncSpy(connection, &Connection::syncDone);
|
|
||||||
|
|
||||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Tried to open media for empty event id");
|
|
||||||
RoomManager::instance().maximizeMedia(QString());
|
|
||||||
QVERIFY(!spy.wait(10));
|
|
||||||
|
|
||||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Tried to open media for unknown event id \"Doesn't exist\"");
|
|
||||||
RoomManager::instance().maximizeMedia(u"Doesn't exist"_s);
|
|
||||||
QVERIFY(!spy.wait(10));
|
|
||||||
|
|
||||||
const auto eventWithoutMedia = server.sendEvent(room->id(),
|
|
||||||
u"m.room.message"_s,
|
|
||||||
QJsonObject({
|
|
||||||
{u"body"_s, u"Foo"_s},
|
|
||||||
{u"format"_s, u"org.matrix.custom.html"_s},
|
|
||||||
{u"formatted_body"_s, u"Foo"_s},
|
|
||||||
{u"msgtype"_s, u"m.text"_s},
|
|
||||||
}));
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, u"Tried to open media for unknown event id \"%1\""_s.arg(eventWithoutMedia).toLatin1().data());
|
|
||||||
RoomManager::instance().maximizeMedia(eventWithoutMedia);
|
|
||||||
QVERIFY(!spy.wait(10));
|
|
||||||
|
|
||||||
// NOTE: This is supposed to test that maximizing pending media works correctly. This probably doesn't work in the UI yet, but at least the backend supports
|
|
||||||
// it. If the server ever learns how to process events, this becomes pointless and we need to find a way of preventing *these* events from arriving
|
|
||||||
auto pendingEventWithoutMedia = room->postText(u"Hello"_s);
|
|
||||||
QTest::ignoreMessage(QtMsgType::QtWarningMsg, u"Tried to open media for unknown event id \"%1\""_s.arg(pendingEventWithoutMedia).toLatin1().data());
|
|
||||||
RoomManager::instance().maximizeMedia(pendingEventWithoutMedia);
|
|
||||||
QVERIFY(!spy.wait(10));
|
|
||||||
|
|
||||||
const auto eventWithMedia = server.sendEvent(room->id(),
|
|
||||||
u"m.room.message"_s,
|
|
||||||
QJsonObject({
|
|
||||||
{u"body"_s, u"Foo"_s},
|
|
||||||
{u"filename"_s, u"foo.jpg"_s},
|
|
||||||
{u"info"_s,
|
|
||||||
QJsonObject{
|
|
||||||
{u"h"_s, 1000},
|
|
||||||
{u"w"_s, 2000},
|
|
||||||
{u"size"_s, 10000},
|
|
||||||
{u"mimetype"_s, u"image/png"_s},
|
|
||||||
}},
|
|
||||||
{u"msgtype"_s, u"m.image"_s},
|
|
||||||
{u"url"_s, u"mxc://foo.bar/asdf"_s},
|
|
||||||
}));
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
QVERIFY(syncSpy.wait());
|
|
||||||
RoomManager::instance().maximizeMedia(eventWithMedia);
|
|
||||||
QVERIFY(spy.size() == 1);
|
|
||||||
QVERIFY(spy[0][0] == 0);
|
|
||||||
|
|
||||||
auto pendingEventWithMedia = room->postJson(u"m.room.message"_s,
|
|
||||||
QJsonObject({
|
|
||||||
{u"body"_s, u"Foo"_s},
|
|
||||||
{u"filename"_s, u"foo.jpg"_s},
|
|
||||||
{u"info"_s,
|
|
||||||
QJsonObject{
|
|
||||||
{u"h"_s, 1000},
|
|
||||||
{u"w"_s, 2000},
|
|
||||||
{u"size"_s, 10000},
|
|
||||||
{u"mimetype"_s, u"image/png"_s},
|
|
||||||
}},
|
|
||||||
{u"msgtype"_s, u"m.image"_s},
|
|
||||||
{u"url"_s, u"mxc://foo.bar/asdf"_s},
|
|
||||||
}));
|
|
||||||
RoomManager::instance().maximizeMedia(pendingEventWithMedia);
|
|
||||||
QVERIFY(spy.size() == 2);
|
|
||||||
QVERIFY(spy[1][0] == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
QTEST_MAIN(RoomManagerTest)
|
|
||||||
#include "roommanagertest.moc"
|
|
||||||
@@ -115,36 +115,28 @@ void Server::start()
|
|||||||
|
|
||||||
m_server.route(u"/_matrix/client/r0/sync"_s, QHttpServerRequest::Method::Get, [this](QHttpServerResponder &responder) {
|
m_server.route(u"/_matrix/client/r0/sync"_s, QHttpServerRequest::Method::Get, [this](QHttpServerResponder &responder) {
|
||||||
QMap<QString, QJsonArray> stateEvents;
|
QMap<QString, QJsonArray> stateEvents;
|
||||||
QMap<QString, QJsonArray> roomAccountData;
|
|
||||||
|
|
||||||
for (const auto &roomData : m_roomsToCreate) {
|
for (const auto &[roomId, matrixId] : m_roomsToCreate) {
|
||||||
stateEvents[roomData.id] += QJsonObject{
|
stateEvents[roomId] += QJsonObject{
|
||||||
{u"content"_s, QJsonObject{{u"room_version"_s, u"11"_s}}},
|
{u"content"_s, QJsonObject{{u"room_version"_s, u"11"_s}}},
|
||||||
{u"event_id"_s, generateEventId()},
|
{u"event_id"_s, generateEventId()},
|
||||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
||||||
{u"room_id"_s, roomData.id},
|
{u"room_id"_s, roomId},
|
||||||
{u"sender"_s, roomData.members[0]},
|
{u"sender"_s, matrixId},
|
||||||
{u"state_key"_s, QString()},
|
{u"state_key"_s, QString()},
|
||||||
{u"type"_s, u"m.room.create"_s},
|
{u"type"_s, u"m.room.create"_s},
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
||||||
};
|
};
|
||||||
for (const auto &member : roomData.members) {
|
stateEvents[roomId] += QJsonObject{
|
||||||
stateEvents[roomData.id] += QJsonObject{
|
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
|
||||||
{u"content"_s, QJsonObject{{u"displayname"_s, u"User"_s}, {u"membership"_s, u"join"_s}}},
|
{u"event_id"_s, generateEventId()},
|
||||||
{u"event_id"_s, generateEventId()},
|
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
||||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
{u"room_id"_s, roomId},
|
||||||
{u"room_id"_s, roomData.id},
|
{u"sender"_s, matrixId},
|
||||||
{u"sender"_s, member},
|
{u"state_key"_s, matrixId},
|
||||||
{u"state_key"_s, member},
|
{u"type"_s, u"m.room.member"_s},
|
||||||
{u"type"_s, u"m.room.member"_s},
|
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
||||||
{u"unsigned"_s, QJsonObject{{u"age"_s, 1234}}},
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
QJsonObject tags;
|
|
||||||
for (const auto &tag : roomData.tags) {
|
|
||||||
tags[tag] = QJsonObject();
|
|
||||||
}
|
|
||||||
roomAccountData[roomData.id] += QJsonObject{{u"type"_s, u"m.tag"_s}, {u"content"_s, QJsonObject{{u"tags"_s, tags}}}};
|
|
||||||
}
|
}
|
||||||
m_roomsToCreate.clear();
|
m_roomsToCreate.clear();
|
||||||
for (const auto &roomId : m_invitedUsers.keys()) {
|
for (const auto &roomId : m_invitedUsers.keys()) {
|
||||||
@@ -199,18 +191,11 @@ void Server::start()
|
|||||||
m_joinedUsers.clear();
|
m_joinedUsers.clear();
|
||||||
|
|
||||||
QJsonObject rooms;
|
QJsonObject rooms;
|
||||||
auto keys = stateEvents.keys() + m_events.keys();
|
for (const auto &roomId : stateEvents.keys()) {
|
||||||
for (const auto &roomId : QSet(keys.begin(), keys.end())) {
|
rooms[roomId] = QJsonObject{{u"state"_s, QJsonObject{{u"events"_s, stateEvents[roomId]}}}};
|
||||||
rooms[roomId] = QJsonObject{
|
|
||||||
{u"state"_s, QJsonObject{{u"events"_s, stateEvents[roomId]}}},
|
|
||||||
{u"account_data"_s, QJsonObject{{u"events"_s, roomAccountData[roomId]}}},
|
|
||||||
{u"timeline"_s, QJsonObject{{u"events"_s, m_events[roomId]}}},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
m_events.clear();
|
|
||||||
|
|
||||||
auto json = QJsonObject{{u"rooms"_s, QJsonObject{{u"join"_s, rooms}}}};
|
responder.write(QJsonDocument(QJsonObject{{u"rooms"_s, QJsonObject{{u"join"_s, rooms}}}}), QHttpServerResponder::StatusCode::Ok);
|
||||||
responder.write(QJsonDocument(json), QHttpServerResponder::StatusCode::Ok);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
QSslConfiguration config;
|
QSslConfiguration config;
|
||||||
@@ -230,11 +215,7 @@ void Server::start()
|
|||||||
QString Server::createRoom(const QString &matrixId)
|
QString Server::createRoom(const QString &matrixId)
|
||||||
{
|
{
|
||||||
auto roomId = generateRoomId();
|
auto roomId = generateRoomId();
|
||||||
m_roomsToCreate += RoomData{
|
m_roomsToCreate += {roomId, matrixId};
|
||||||
.members = {matrixId},
|
|
||||||
.id = roomId,
|
|
||||||
.tags = {},
|
|
||||||
};
|
|
||||||
return roomId;
|
return roomId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,23 +233,3 @@ void Server::joinUser(const QString &roomId, const QString &matrixId)
|
|||||||
{
|
{
|
||||||
m_joinedUsers[roomId] += matrixId;
|
m_joinedUsers[roomId] += matrixId;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Server::createServerNoticesRoom(const QString &matrixId)
|
|
||||||
{
|
|
||||||
auto roomId = createRoom(matrixId);
|
|
||||||
m_roomsToCreate.last().tags = {u"m.server_notice"_s};
|
|
||||||
return roomId;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Server::sendEvent(const QString &roomId, const QString &eventType, const QJsonObject &content)
|
|
||||||
{
|
|
||||||
const auto eventId = generateEventId();
|
|
||||||
m_events[roomId] += QJsonObject{
|
|
||||||
{u"type"_s, eventType},
|
|
||||||
{u"content"_s, content},
|
|
||||||
{u"sender"_s, u"@foo:server.com"_s},
|
|
||||||
{u"event_id"_s, eventId},
|
|
||||||
{u"origin_server_ts"_s, QDateTime::currentMSecsSinceEpoch()},
|
|
||||||
};
|
|
||||||
return eventId;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
#include <QHttpServer>
|
#include <QHttpServer>
|
||||||
#include <QSslServer>
|
#include <QSslServer>
|
||||||
|
|
||||||
struct RoomData {
|
|
||||||
QStringList members;
|
|
||||||
QString id;
|
|
||||||
QStringList tags;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Server
|
class Server
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -27,12 +21,6 @@ public:
|
|||||||
void banUser(const QString &roomId, const QString &matrixId);
|
void banUser(const QString &roomId, const QString &matrixId);
|
||||||
void joinUser(const QString &roomId, const QString &matrixId);
|
void joinUser(const QString &roomId, const QString &matrixId);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a server notices room.
|
|
||||||
*/
|
|
||||||
QString createServerNoticesRoom(const QString &matrixId);
|
|
||||||
QString sendEvent(const QString &roomId, const QString &eventType, const QJsonObject &content);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHttpServer m_server;
|
QHttpServer m_server;
|
||||||
QSslServer m_sslServer;
|
QSslServer m_sslServer;
|
||||||
@@ -41,6 +29,5 @@ private:
|
|||||||
QHash<QString, QList<QString>> m_bannedUsers;
|
QHash<QString, QList<QString>> m_bannedUsers;
|
||||||
QHash<QString, QList<QString>> m_joinedUsers;
|
QHash<QString, QList<QString>> m_joinedUsers;
|
||||||
|
|
||||||
QList<RoomData> m_roomsToCreate;
|
QList<std::pair<QString, QString>> m_roomsToCreate;
|
||||||
QMap<QString, QJsonArray> m_events;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -120,7 +120,7 @@
|
|||||||
<p xml:lang="x-test">xxNeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.xx</p>
|
<p xml:lang="x-test">xxNeoChat is a chat app that lets you take full advantage of the Matrix network. It provides you with a secure way to send text messages, videos and audio files to your family, colleagues and friends.xx</p>
|
||||||
<p xml:lang="zh-TW">NeoChat 是一個讓您能夠完全利用 Matrix 網路的聊天應用程式。它讓您安全地傳送文字訊息、影片或音訊檔給家人、同事或朋友等等。</p>
|
<p xml:lang="zh-TW">NeoChat 是一個讓您能夠完全利用 Matrix 網路的聊天應用程式。它讓您安全地傳送文字訊息、影片或音訊檔給家人、同事或朋友等等。</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>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="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">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="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="de">NeoChat versucht eine vollumfängliche Anwendung für die Spezifikation von Matrix zu sein. Damit wird alles der aktuellen stabilen Spezifikation mit den erwähnenswerten Ausnahmen von VoIP, Diskussionsfäden und ein paar Teilen der Ende-zu-Ende-Verschlüsselung unterstützt. Zudem sind andere kleinere Auslassungen vorhanden, da sich die Matrixspezifikation ständig weiterentwickelt. Nichtsdestotrotz soll letztendlich die gesamte Spezifikation unterstützt werden.</p>
|
<p xml:lang="de">NeoChat versucht eine vollumfängliche Anwendung für die Spezifikation von Matrix zu sein. Damit wird alles der aktuellen stabilen Spezifikation mit den erwähnenswerten Ausnahmen von VoIP, Diskussionsfäden und ein paar Teilen der Ende-zu-Ende-Verschlüsselung unterstützt. Zudem sind andere kleinere Auslassungen vorhanden, da sich die Matrixspezifikation ständig weiterentwickelt. Nichtsdestotrotz soll letztendlich die gesamte Spezifikation unterstützt werden.</p>
|
||||||
@@ -306,8 +306,8 @@
|
|||||||
<keyword>Matrix</keyword>
|
<keyword>Matrix</keyword>
|
||||||
<keyword>Kirigami</keyword>
|
<keyword>Kirigami</keyword>
|
||||||
</keywords>
|
</keywords>
|
||||||
<developer id="org.kde">
|
<developer id="kde.org">
|
||||||
<name translate="no">KDE</name>
|
<name>The KDE Community</name>
|
||||||
<url>https://kde.org</url>
|
<url>https://kde.org</url>
|
||||||
</developer>
|
</developer>
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
|||||||
1529
po/ar/neochat.po
1529
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
1266
po/ast/neochat.po
1266
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
1461
po/az/neochat.po
1461
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1357
po/ca/neochat.po
1357
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1556
po/cs/neochat.po
1556
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1428
po/da/neochat.po
1428
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1549
po/de/neochat.po
1549
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1486
po/el/neochat.po
1486
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1536
po/en_GB/neochat.po
1536
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1548
po/eo/neochat.po
1548
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
1303
po/es/neochat.po
1303
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1402
po/eu/neochat.po
1402
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1550
po/fi/neochat.po
1550
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1532
po/fr/neochat.po
1532
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1562
po/gl/neochat.po
1562
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
1360
po/he/neochat.po
1360
po/he/neochat.po
File diff suppressed because it is too large
Load Diff
1543
po/hi/neochat.po
1543
po/hi/neochat.po
File diff suppressed because it is too large
Load Diff
1556
po/hu/neochat.po
1556
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1580
po/ia/neochat.po
1580
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1516
po/id/neochat.po
1516
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1421
po/ie/neochat.po
1421
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1457
po/it/neochat.po
1457
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1266
po/ja/neochat.po
1266
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1374
po/ka/neochat.po
1374
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1529
po/ko/neochat.po
1529
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1266
po/lt/neochat.po
1266
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
1562
po/lv/neochat.po
1562
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
1370
po/nl/neochat.po
1370
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
1439
po/nn/neochat.po
1439
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1442
po/pa/neochat.po
1442
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
1552
po/pl/neochat.po
1552
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1516
po/pt/neochat.po
1516
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
1454
po/pt_BR/neochat.po
1454
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
1524
po/ru/neochat.po
1524
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1543
po/sa/neochat.po
1543
po/sa/neochat.po
File diff suppressed because it is too large
Load Diff
1477
po/sk/neochat.po
1477
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
1400
po/sl/neochat.po
1400
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
1379
po/sv/neochat.po
1379
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1561
po/ta/neochat.po
1561
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1414
po/tok/neochat.po
1414
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
1392
po/tr/neochat.po
1392
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
1367
po/uk/neochat.po
1367
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
1300
po/zh_CN/neochat.po
1300
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
1500
po/zh_TW/neochat.po
1500
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -104,7 +104,6 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
|||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
QtCore
|
QtCore
|
||||||
QtQuick
|
QtQuick
|
||||||
com.github.quotient_im.libquotient
|
|
||||||
IMPORTS
|
IMPORTS
|
||||||
org.kde.neochat.libneochat
|
org.kde.neochat.libneochat
|
||||||
org.kde.neochat.rooms
|
org.kde.neochat.rooms
|
||||||
@@ -116,15 +115,13 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
|||||||
org.kde.neochat.devtools
|
org.kde.neochat.devtools
|
||||||
org.kde.neochat.login
|
org.kde.neochat.login
|
||||||
org.kde.neochat.chatbar
|
org.kde.neochat.chatbar
|
||||||
org.kde.config
|
|
||||||
org.kde.purpose
|
|
||||||
org.kde.syntaxhighlighting
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT ANDROID AND NOT WIN32)
|
if(NOT ANDROID AND NOT WIN32)
|
||||||
qt_target_qml_sources(neochat QML_FILES
|
qt_target_qml_sources(neochat QML_FILES
|
||||||
qml/ShareAction.qml
|
qml/ShareAction.qml
|
||||||
qml/GlobalMenu.qml
|
qml/GlobalMenu.qml
|
||||||
|
qml/EditMenu.qml
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
qt_target_qml_sources(neochat QML_FILES
|
qt_target_qml_sources(neochat QML_FILES
|
||||||
@@ -341,6 +338,10 @@ if(TARGET KF6::DBusAddons AND NOT WIN32)
|
|||||||
target_compile_definitions(neochat PUBLIC -DHAVE_KDBUSADDONS)
|
target_compile_definitions(neochat PUBLIC -DHAVE_KDBUSADDONS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (TARGET KF6::KIOWidgets)
|
||||||
|
target_compile_definitions(neochat PUBLIC -DHAVE_KIO)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (TARGET KUnifiedPush)
|
if (TARGET KUnifiedPush)
|
||||||
target_compile_definitions(neochat PUBLIC -DHAVE_KUNIFIEDPUSH)
|
target_compile_definitions(neochat PUBLIC -DHAVE_KUNIFIEDPUSH)
|
||||||
target_link_libraries(neochat PUBLIC KUnifiedPush)
|
target_link_libraries(neochat PUBLIC KUnifiedPush)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
|
|
||||||
#include <Quotient/connection.h>
|
#include <Quotient/connection.h>
|
||||||
|
#include <qt6keychain/keychain.h>
|
||||||
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <Quotient/csapi/notifications.h>
|
||||||
#include <Quotient/events/roommemberevent.h>
|
#include <Quotient/events/roommemberevent.h>
|
||||||
#include <Quotient/qt_connection_util.h>
|
#include <Quotient/qt_connection_util.h>
|
||||||
#include <Quotient/settings.h>
|
#include <Quotient/settings.h>
|
||||||
@@ -22,6 +24,7 @@
|
|||||||
#include "mediasizehelper.h"
|
#include "mediasizehelper.h"
|
||||||
#include "models/actionsmodel.h"
|
#include "models/actionsmodel.h"
|
||||||
#include "models/messagemodel.h"
|
#include "models/messagemodel.h"
|
||||||
|
#include "models/pushrulemodel.h"
|
||||||
#include "models/roomlistmodel.h"
|
#include "models/roomlistmodel.h"
|
||||||
#include "models/roomtreemodel.h"
|
#include "models/roomtreemodel.h"
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
||||||
#include "neochatconnection.h"
|
#include "neochatconnection.h"
|
||||||
|
#include "neochatroom.h"
|
||||||
|
|
||||||
#include <Quotient/events/roommessageevent.h>
|
#include <Quotient/events/roommessageevent.h>
|
||||||
#include <Quotient/roommember.h>
|
#include <Quotient/roommember.h>
|
||||||
@@ -24,7 +25,11 @@ class CommonRoomsModel : public QAbstractListModel
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
enum Roles {
|
enum Roles {
|
||||||
RoomIdRole = Qt::DisplayRole,
|
TextRole = Qt::DisplayRole,
|
||||||
|
LongitudeRole,
|
||||||
|
LatitudeRole,
|
||||||
|
AssetRole,
|
||||||
|
AuthorRole,
|
||||||
};
|
};
|
||||||
Q_ENUM(Roles)
|
Q_ENUM(Roles)
|
||||||
|
|
||||||
|
|||||||
@@ -189,10 +189,6 @@
|
|||||||
<label>Don't hide any events in the timeline</label>
|
<label>Don't hide any events in the timeline</label>
|
||||||
<default>false</default>
|
<default>false</default>
|
||||||
</entry>
|
</entry>
|
||||||
<entry name="RelateAnyEvent" type="bool">
|
|
||||||
<label>Send relations to any event, including state events and events normally hidden.</label>
|
|
||||||
<default>false</default>
|
|
||||||
</entry>
|
|
||||||
<entry name="AlwaysVerifyDevice" type="bool">
|
<entry name="AlwaysVerifyDevice" type="bool">
|
||||||
<label>Always allow device verification</label>
|
<label>Always allow device verification</label>
|
||||||
<default>false</default>
|
<default>false</default>
|
||||||
|
|||||||
@@ -433,7 +433,7 @@ QPixmap NotificationsManager::createNotificationImage(const QImage &icon, NeoCha
|
|||||||
|
|
||||||
if (room != nullptr) {
|
if (room != nullptr) {
|
||||||
const QImage roomAvatar = room->avatar(imageRect.width(), imageRect.height());
|
const QImage roomAvatar = room->avatar(imageRect.width(), imageRect.height());
|
||||||
if (!roomAvatar.isNull() && icon != roomAvatar) {
|
if (icon != roomAvatar) {
|
||||||
const QRect lowerQuarter{imageRect.center(), imageRect.size() / 2};
|
const QRect lowerQuarter{imageRect.center(), imageRect.size() / 2};
|
||||||
|
|
||||||
painter.setBrush(Qt::white);
|
painter.setBrush(Qt::white);
|
||||||
|
|||||||
@@ -93,3 +93,4 @@ X-Plasma-API=DBus
|
|||||||
X-Plasma-DBusRunner-Service=org.kde.neochat
|
X-Plasma-DBusRunner-Service=org.kde.neochat
|
||||||
X-Plasma-DBusRunner-Path=/RoomRunner
|
X-Plasma-DBusRunner-Path=/RoomRunner
|
||||||
X-Plasma-Request-Actions-Once=true
|
X-Plasma-Request-Actions-Once=true
|
||||||
|
X-Plasma-Runner-Min-Letter-Count=3
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
|
// SPDX-FileCopyrightText: 2022 James Graham <james.h.graham@protonmail.com>
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
import org.kde.kirigamiaddons.components as KirigamiComponents
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
import org.kde.neochat.settings
|
import org.kde.neochat.settings
|
||||||
|
import org.kde.neochat.devtools
|
||||||
|
|
||||||
KirigamiComponents.ConvergentContextMenu {
|
KirigamiComponents.ConvergentContextMenu {
|
||||||
id: root
|
id: root
|
||||||
@@ -18,17 +18,21 @@ KirigamiComponents.ConvergentContextMenu {
|
|||||||
required property NeoChatConnection connection
|
required property NeoChatConnection connection
|
||||||
required property Kirigami.ApplicationWindow window
|
required property Kirigami.ApplicationWindow window
|
||||||
|
|
||||||
Kirigami.Action {
|
QQC2.Action {
|
||||||
text: i18nc("@action:button", "Show QR Code")
|
text: i18nc("@action:button", "Show QR Code")
|
||||||
icon.name: "view-barcode-qr-symbolic"
|
icon.name: "view-barcode-qr-symbolic"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
(Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
let qrMax = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||||
text: "https://matrix.to/#/" + root.connection.localUser.id,
|
text: "https://matrix.to/#/" + root.connection.localUser.id,
|
||||||
title: root.connection.localUser.displayName,
|
title: root.connection.localUser.displayName,
|
||||||
subtitle: root.connection.localUser.id,
|
subtitle: root.connection.localUser.id,
|
||||||
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl.
|
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl.
|
||||||
avatarSource: root.connection.localUser.avatarUrl.toString().length > 0 ? root.connection.makeMediaUrl(root.connection.localUser.avatarUrl) : ""
|
avatarSource: root.connection.localUser.avatarUrl.toString().length > 0 ? root.connection.makeMediaUrl(root.connection.localUser.avatarUrl) : ""
|
||||||
}) as QrCodeMaximizeComponent).open();
|
});
|
||||||
|
if (typeof root.closeDialog === "function") {
|
||||||
|
root.closeDialog();
|
||||||
|
}
|
||||||
|
qrMax.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,27 +40,26 @@ KirigamiComponents.ConvergentContextMenu {
|
|||||||
text: i18nc("@action:inmenu", "Switch Account")
|
text: i18nc("@action:inmenu", "Switch Account")
|
||||||
icon.name: "system-switch-user"
|
icon.name: "system-switch-user"
|
||||||
shortcut: "Ctrl+U"
|
shortcut: "Ctrl+U"
|
||||||
onTriggered: (Qt.createComponent("org.kde.neochat", "AccountSwitchDialog").createObject(QQC2.Overlay.overlay, {
|
onTriggered: accountSwitchDialog.createObject(QQC2.Overlay.overlay, {
|
||||||
connection: root.connection
|
connection: root.connection
|
||||||
}) as Kirigami.Dialog).open();
|
}).open();
|
||||||
}
|
}
|
||||||
|
QQC2.Action {
|
||||||
Kirigami.Action {
|
text: i18n("Edit This Account")
|
||||||
text: i18nc("@action:inmenu", "Edit This Account")
|
|
||||||
icon.name: "document-edit"
|
icon.name: "document-edit"
|
||||||
onTriggered: NeoChatSettingsView.openWithInitialProperties("accounts", {initialAccount: root.connection});
|
onTriggered: NeoChatSettingsView.openWithInitialProperties("accounts", {initialAccount: root.connection});
|
||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.Action {
|
QQC2.Action {
|
||||||
text: i18nc("@action:inmenu", "Notification Settings")
|
text: i18n("Notification Settings")
|
||||||
icon.name: "notifications"
|
icon.name: "notifications"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
NeoChatSettingsView.open('notifications');
|
NeoChatSettingsView.open('notifications');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.Action {
|
QQC2.Action {
|
||||||
text: i18nc("@action:inmenu", "Devices")
|
text: i18n("Devices")
|
||||||
icon.name: "computer-symbolic"
|
icon.name: "computer-symbolic"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
NeoChatSettingsView.open('devices');
|
NeoChatSettingsView.open('devices');
|
||||||
@@ -64,10 +67,10 @@ KirigamiComponents.ConvergentContextMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
text: i18nc("@action:inmenu", "Open Developer Tools")
|
text: i18n("Open Developer Tools")
|
||||||
icon.name: "tools"
|
icon.name: "tools"
|
||||||
visible: NeoChatConfig.developerTools
|
visible: NeoChatConfig.developerTools
|
||||||
onTriggered: root.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'DevtoolsPage'), {
|
onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.devtools', 'DevtoolsPage'), {
|
||||||
connection: root.connection
|
connection: root.connection
|
||||||
}, {
|
}, {
|
||||||
title: i18nc("@title:window", "Developer Tools"),
|
title: i18nc("@title:window", "Developer Tools"),
|
||||||
@@ -85,10 +88,9 @@ KirigamiComponents.ConvergentContextMenu {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.Action {
|
QQC2.Action {
|
||||||
text: i18nc("@action:inmenu", "Verify This Device")
|
text: i18nc("@action:inmenu", "Verify This Device")
|
||||||
icon.name: "security-low"
|
icon.name: "security-low"
|
||||||
visible: !root.connection.isVerifiedSession()
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.connection.startSelfVerification();
|
root.connection.startSelfVerification();
|
||||||
const dialog = Qt.createComponent("org.kde.kirigami", "PromptDialog").createObject(QQC2.Overlay.overlay, {
|
const dialog = Qt.createComponent("org.kde.kirigami", "PromptDialog").createObject(QQC2.Overlay.overlay, {
|
||||||
@@ -97,17 +99,19 @@ KirigamiComponents.ConvergentContextMenu {
|
|||||||
standardButtons: Kirigami.Dialog.Ok
|
standardButtons: Kirigami.Dialog.Ok
|
||||||
})
|
})
|
||||||
dialog.open();
|
dialog.open();
|
||||||
root.connection.newKeyVerificationSession.connect(() => {
|
root.connection.onNewKeyVerificationSession.connect(() => {
|
||||||
dialog.close();
|
dialog.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.Action {
|
QQC2.Action {
|
||||||
text: i18nc("@action:inmenu", "Logout…")
|
text: i18n("Logout")
|
||||||
icon.name: "im-kick-user"
|
icon.name: "im-kick-user"
|
||||||
onTriggered: (Qt.createComponent("org.kde.neochat", "ConfirmLogoutDialog").createObject(QQC2.Overlay.overlay, {
|
onTriggered: confirmLogoutDialogComponent.createObject(root).open()
|
||||||
connection: root.connection
|
}
|
||||||
}) as Kirigami.Dialog).open()
|
|
||||||
|
readonly property Component confirmLogoutDialogComponent: ConfirmLogoutDialog {
|
||||||
|
connection: root.connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
@@ -19,6 +16,8 @@ Kirigami.Dialog {
|
|||||||
|
|
||||||
required property NeoChatConnection connection
|
required property NeoChatConnection connection
|
||||||
|
|
||||||
|
parent: applicationWindow().overlay
|
||||||
|
|
||||||
leftPadding: 0
|
leftPadding: 0
|
||||||
rightPadding: 0
|
rightPadding: 0
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
@@ -26,7 +25,7 @@ Kirigami.Dialog {
|
|||||||
|
|
||||||
standardButtons: Kirigami.Dialog.NoButton
|
standardButtons: Kirigami.Dialog.NoButton
|
||||||
|
|
||||||
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24)
|
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
|
||||||
title: i18nc("@title: dialog to switch between logged in accounts", "Switch Account")
|
title: i18nc("@title: dialog to switch between logged in accounts", "Switch Account")
|
||||||
|
|
||||||
onVisibleChanged: if (visible) {
|
onVisibleChanged: if (visible) {
|
||||||
@@ -54,8 +53,8 @@ Kirigami.Dialog {
|
|||||||
}
|
}
|
||||||
text: i18nc("@button: login to or register a new account.", "Add Account")
|
text: i18nc("@button: login to or register a new account.", "Add Account")
|
||||||
contentItem: Delegates.SubtitleContentItem {
|
contentItem: Delegates.SubtitleContentItem {
|
||||||
itemDelegate: addDelegate
|
itemDelegate: parent
|
||||||
subtitle: i18nc("@info", "Log in or create a new account")
|
subtitle: i18n("Log in or create a new account")
|
||||||
labelItem.textFormat: Text.PlainText
|
labelItem.textFormat: Text.PlainText
|
||||||
subtitleItem.textFormat: Text.PlainText
|
subtitleItem.textFormat: Text.PlainText
|
||||||
}
|
}
|
||||||
@@ -95,8 +94,8 @@ Kirigami.Dialog {
|
|||||||
accountView.decrementCurrentIndex();
|
accountView.decrementCurrentIndex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Keys.onEnterPressed: (accountView.currentItem as Delegates.RoundedItemDelegate).clicked()
|
Keys.onEnterPressed: accountView.currentItem.clicked()
|
||||||
Keys.onReturnPressed: (accountView.currentItem as Delegates.RoundedItemDelegate).clicked()
|
Keys.onReturnPressed: accountView.currentItem.clicked()
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
for (let i = 0; i < accountView.count; i++) {
|
for (let i = 0; i < accountView.count; i++) {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import QtQuick.Controls as QQC2
|
|||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
||||||
|
import org.kde.neochat
|
||||||
|
|
||||||
Kirigami.Dialog {
|
Kirigami.Dialog {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -18,7 +20,7 @@ Kirigami.Dialog {
|
|||||||
title: i18nc("@title:dialog", "Start a chat")
|
title: i18nc("@title:dialog", "Start a chat")
|
||||||
|
|
||||||
contentItem: QQC2.Label {
|
contentItem: QQC2.Label {
|
||||||
text: i18nc("@info", "Do you want to start a chat with %1?", root.user.displayName)
|
text: i18n("Do you want to start a chat with %1?", root.user.displayName)
|
||||||
textFormat: Text.PlainText
|
textFormat: Text.PlainText
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
horizontalAlignment: Qt.AlignHCenter
|
horizontalAlignment: Qt.AlignHCenter
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
id: editImageButton
|
id: editImageButton
|
||||||
visible: root.hasImage
|
visible: hasImage
|
||||||
icon.name: "document-edit"
|
icon.name: "document-edit"
|
||||||
text: i18n("Edit")
|
text: i18n("Edit")
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
@@ -46,9 +46,9 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
let imageEditor = (Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(imageEditorPage);
|
let imageEditor = applicationWindow().pageStack.pushDialogLayer(imageEditorPage);
|
||||||
imageEditor.newPathChanged.connect(function (newPath) {
|
imageEditor.newPathChanged.connect(function (newPath) {
|
||||||
imageEditor.closeDialog();
|
applicationWindow().pageStack.layers.pop();
|
||||||
root.attachmentPath = newPath;
|
root.attachmentPath = newPath;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -58,18 +58,14 @@ ColumnLayout {
|
|||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
id: cancelAttachmentButton
|
id: cancelAttachmentButton
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
text: i18nc("@action:button", "Cancel sending attachment")
|
action: Kirigami.Action {
|
||||||
icon.name: "dialog-close"
|
text: i18n("Cancel sending attachment")
|
||||||
onClicked: root.attachmentCancelled()
|
icon.name: "dialog-close"
|
||||||
|
onTriggered: attachmentCancelled()
|
||||||
|
shortcut: "Escape"
|
||||||
|
}
|
||||||
QQC2.ToolTip.text: text
|
QQC2.ToolTip.text: text
|
||||||
QQC2.ToolTip.visible: hovered
|
QQC2.ToolTip.visible: hovered
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
|
||||||
|
|
||||||
Kirigami.Action {
|
|
||||||
shortcut: "Escape"
|
|
||||||
onTriggered: cancelAttachmentButton.clicked()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,8 +75,8 @@ ColumnLayout {
|
|||||||
|
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
cache: false // Cache is not needed. Images will rarely be shown repeatedly.
|
cache: false // Cache is not needed. Images will rarely be shown repeatedly.
|
||||||
source: root.hasImage ? root.attachmentPath : ""
|
source: hasImage ? root.attachmentPath : ""
|
||||||
visible: root.hasImage
|
visible: hasImage
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
|
|
||||||
onSourceChanged: {
|
onSourceChanged: {
|
||||||
@@ -118,11 +114,11 @@ ColumnLayout {
|
|||||||
id: mimetypeIcon
|
id: mimetypeIcon
|
||||||
implicitWidth: Kirigami.Units.iconSizes.smallMedium
|
implicitWidth: Kirigami.Units.iconSizes.smallMedium
|
||||||
implicitHeight: Kirigami.Units.iconSizes.smallMedium
|
implicitHeight: Kirigami.Units.iconSizes.smallMedium
|
||||||
source: root.attachmentMimetype.iconName
|
source: attachmentMimetype.iconName
|
||||||
}
|
}
|
||||||
QQC2.Label {
|
QQC2.Label {
|
||||||
id: fileLabel
|
id: fileLabel
|
||||||
text: root.baseFileName
|
text: baseFileName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,12 @@
|
|||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Templates as T
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.delegates as Delegates
|
import org.kde.kirigamiaddons.delegates as Delegates
|
||||||
|
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
||||||
|
|
||||||
Delegates.RoundedItemDelegate {
|
Delegates.RoundedItemDelegate {
|
||||||
id: root
|
id: root
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import QtQml.Models
|
|||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
||||||
|
import org.kde.kitemmodels
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
|
|
||||||
|
|||||||
86
src/app/qml/EditMenu.qml
Normal file
86
src/app/qml/EditMenu.qml
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com>
|
||||||
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
|
||||||
|
import Qt.labs.platform as Labs
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Labs.Menu {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Item field
|
||||||
|
|
||||||
|
Labs.MenuItem {
|
||||||
|
enabled: root.field !== null && root.field.canUndo
|
||||||
|
text: i18nc("text editing menu action", "Undo")
|
||||||
|
shortcut: StandardKey.Undo
|
||||||
|
onTriggered: {
|
||||||
|
root.field.undo();
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Labs.MenuItem {
|
||||||
|
enabled: root.field !== null && root.field.canRedo
|
||||||
|
text: i18nc("text editing menu action", "Redo")
|
||||||
|
shortcut: StandardKey.Redo
|
||||||
|
onTriggered: {
|
||||||
|
root.field.undo();
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Labs.MenuSeparator {}
|
||||||
|
|
||||||
|
Labs.MenuItem {
|
||||||
|
enabled: root.field !== null && root.field.selectedText
|
||||||
|
text: i18nc("text editing menu action", "Cut")
|
||||||
|
shortcut: StandardKey.Cut
|
||||||
|
onTriggered: {
|
||||||
|
root.field.cut();
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Labs.MenuItem {
|
||||||
|
enabled: root.field !== null && root.field.selectedText
|
||||||
|
text: i18nc("text editing menu action", "Copy")
|
||||||
|
shortcut: StandardKey.Copy
|
||||||
|
onTriggered: {
|
||||||
|
root.field.copy();
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Labs.MenuItem {
|
||||||
|
enabled: root.field !== null && root.field.canPaste
|
||||||
|
text: i18nc("text editing menu action", "Paste")
|
||||||
|
shortcut: StandardKey.Paste
|
||||||
|
onTriggered: {
|
||||||
|
root.field.paste();
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Labs.MenuItem {
|
||||||
|
enabled: root.field !== null && root.field.selectedText !== ""
|
||||||
|
text: i18nc("text editing menu action", "Delete")
|
||||||
|
shortcut: ""
|
||||||
|
onTriggered: {
|
||||||
|
root.field.remove(root.field.selectionStart, root.field.selectionEnd);
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Labs.MenuSeparator {}
|
||||||
|
|
||||||
|
Labs.MenuItem {
|
||||||
|
enabled: root.field !== null
|
||||||
|
text: i18nc("text editing menu action", "Select All")
|
||||||
|
shortcut: StandardKey.SelectAll
|
||||||
|
onTriggered: {
|
||||||
|
root.field.selectAll();
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import Qt.labs.platform as Labs
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Window
|
import QtQuick.Window
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
||||||
@@ -15,50 +16,12 @@ Labs.MenuBar {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property NeoChatConnection connection
|
required property NeoChatConnection connection
|
||||||
required property Kirigami.ApplicationWindow appWindow
|
|
||||||
|
|
||||||
Labs.Menu {
|
Labs.Menu {
|
||||||
title: i18nc("menu", "File")
|
title: i18nc("menu", "NeoChat")
|
||||||
|
|
||||||
Labs.MenuItem {
|
Labs.MenuItem {
|
||||||
icon.name: "list-add-user"
|
enabled: pageStack.layers.currentItem.title !== i18n("Configure NeoChat…")
|
||||||
text: i18nc("@action:inmenu", "Find your Friends")
|
|
||||||
enabled: root.connection
|
|
||||||
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UserSearchPage'), {
|
|
||||||
connection: root.connection
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title", "Find your friends")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Labs.MenuItem {
|
|
||||||
icon.name: "system-users-symbolic"
|
|
||||||
text: i18nc("@action:inmenu", "Create a Room…")
|
|
||||||
enabled: root.connection
|
|
||||||
shortcut: StandardKey.New
|
|
||||||
onTriggered: {
|
|
||||||
Qt.createComponent('org.kde.neochat', 'CreateRoomDialog').createObject(root.appWindow, {
|
|
||||||
connection: root.connection
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title", "Create a Room")
|
|
||||||
}).open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Labs.MenuItem {
|
|
||||||
icon.name: "compass-symbolic"
|
|
||||||
text: i18nc("@action:inmenu", "Explore Rooms")
|
|
||||||
enabled: root.connection
|
|
||||||
onTriggered: {
|
|
||||||
let dialog = root.appWindow.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
|
|
||||||
connection: root.connection
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title", "Explore Rooms")
|
|
||||||
});
|
|
||||||
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
|
|
||||||
RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, isJoined ? "" : "join");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Labs.MenuItem {
|
|
||||||
text: i18nc("menu", "Configure NeoChat…")
|
text: i18nc("menu", "Configure NeoChat…")
|
||||||
|
|
||||||
shortcut: StandardKey.Preferences
|
shortcut: StandardKey.Preferences
|
||||||
@@ -71,15 +34,58 @@ Labs.MenuBar {
|
|||||||
onTriggered: Qt.quit()
|
onTriggered: Qt.quit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Labs.Menu {
|
||||||
|
title: i18nc("menu", "File")
|
||||||
|
|
||||||
|
Labs.MenuItem {
|
||||||
|
icon.name: "list-add-user"
|
||||||
|
text: i18nc("@action:inmenu", "Find your Friends")
|
||||||
|
enabled: pageStack.layers.currentItem.title !== i18n("Find your friends") && AccountRegistry.accountCount > 0
|
||||||
|
onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UserSearchPage'), {
|
||||||
|
connection: root.connection
|
||||||
|
}, {
|
||||||
|
title: i18nc("@title", "Find your friends")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Labs.MenuItem {
|
||||||
|
icon.name: "system-users-symbolic"
|
||||||
|
text: i18nc("@action:inmenu", "Create a Room…")
|
||||||
|
enabled: pageStack.layers.currentItem.title !== i18n("Find your friends") && AccountRegistry.accountCount > 0
|
||||||
|
shortcut: StandardKey.New
|
||||||
|
onTriggered: {
|
||||||
|
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'CreateRoomDialog'), {
|
||||||
|
connection: root.connection
|
||||||
|
}, {
|
||||||
|
title: i18nc("@title", "Create a Room")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Labs.MenuItem {
|
||||||
|
icon.name: "compass-symbolic"
|
||||||
|
text: i18nc("@action:inmenu", "Explore Rooms")
|
||||||
|
onTriggered: {
|
||||||
|
let dialog = pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
|
||||||
|
connection: root.connection
|
||||||
|
}, {
|
||||||
|
title: i18nc("@title", "Explore Rooms")
|
||||||
|
});
|
||||||
|
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
|
||||||
|
RoomManager.resolveResource(roomId.length > 0 ? roomId : alias, isJoined ? "" : "join");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EditMenu {
|
||||||
|
title: i18nc("menu", "Edit")
|
||||||
|
field: (root.activeFocusItem instanceof TextEdit || root.activeFocusItem instanceof TextInput) ? root.activeFocusItem : null
|
||||||
|
}
|
||||||
Labs.Menu {
|
Labs.Menu {
|
||||||
title: i18nc("menu", "View")
|
title: i18nc("menu", "View")
|
||||||
|
|
||||||
Labs.MenuItem {
|
Labs.MenuItem {
|
||||||
icon.name: "search-symbolic"
|
icon.name: "search-symbolic"
|
||||||
enabled: root.connection
|
|
||||||
text: i18nc("@action:inmenu opens a UI element called the 'Quick Switcher', which offers a fast keyboard-based interface for switching in between chats.", "Search Rooms")
|
text: i18nc("@action:inmenu opens a UI element called the 'Quick Switcher', which offers a fast keyboard-based interface for switching in between chats.", "Search Rooms")
|
||||||
onTriggered: (root.appWindow as Main).quickSwitcher.open()
|
onTriggered: quickSwitcher.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Labs.Menu {
|
Labs.Menu {
|
||||||
@@ -87,8 +93,8 @@ Labs.MenuBar {
|
|||||||
|
|
||||||
Labs.MenuItem {
|
Labs.MenuItem {
|
||||||
icon.name: "view-fullscreen-symbolic"
|
icon.name: "view-fullscreen-symbolic"
|
||||||
text: root.appWindow.visibility === Window.FullScreen ? i18nc("menu", "Exit Full Screen") : i18nc("menu", "Enter Full Screen")
|
text: root.visibility === Window.FullScreen ? i18nc("menu", "Exit Full Screen") : i18nc("menu", "Enter Full Screen")
|
||||||
onTriggered: root.appWindow.visibility === Window.FullScreen ? root.appWindow.showNormal() : root.appWindow.showFullScreen()
|
onTriggered: root.visibility === Window.FullScreen ? root.showNormal() : root.showFullScreen()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Labs.Menu {
|
Labs.Menu {
|
||||||
@@ -97,12 +103,12 @@ Labs.MenuBar {
|
|||||||
Labs.MenuItem {
|
Labs.MenuItem {
|
||||||
icon.name: "help-about-symbolic"
|
icon.name: "help-about-symbolic"
|
||||||
text: i18nc("menu", "About NeoChat")
|
text: i18nc("menu", "About NeoChat")
|
||||||
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutPage"))
|
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutPage"))
|
||||||
}
|
}
|
||||||
Labs.MenuItem {
|
Labs.MenuItem {
|
||||||
icon.name: "kde-symbolic"
|
icon.name: "kde-symbolic"
|
||||||
text: i18nc("menu", "About KDE")
|
text: i18nc("menu", "About KDE")
|
||||||
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDEPage"))
|
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDEPage"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,15 +52,6 @@ ColumnLayout {
|
|||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.SelectableLabel {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
font: Kirigami.Theme.smallFont
|
|
||||||
textFormat: TextEdit.PlainText
|
|
||||||
visible: root.currentRoom && root.currentRoom.canonicalAlias
|
|
||||||
text: root.currentRoom && root.currentRoom.canonicalAlias ? root.currentRoom.canonicalAlias : ""
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
}
|
|
||||||
|
|
||||||
Kirigami.Heading {
|
Kirigami.Heading {
|
||||||
text: root.currentRoom.displayName
|
text: root.currentRoom.displayName
|
||||||
|
|
||||||
@@ -79,14 +70,7 @@ ColumnLayout {
|
|||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
Kirigami.Heading {
|
Kirigami.Heading {
|
||||||
text: root.invitingMember.displayName
|
text: root.currentRoom.displayName
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Label {
|
|
||||||
text: root.invitingMember.id
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
}
|
}
|
||||||
@@ -175,7 +159,7 @@ ColumnLayout {
|
|||||||
|
|
||||||
QQC2.Label {
|
QQC2.Label {
|
||||||
color: Kirigami.Theme.disabledTextColor
|
color: Kirigami.Theme.disabledTextColor
|
||||||
text: xi18nc("@info:label Ensure you are referring to the same translation used for that settings page", "You can reject invitations from unknown users under the <interface>Security & Safety</interface> settings.")
|
text: i18nc("@info:label", "You can reject invitations from unknown users under Security settings.")
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
|
|
||||||
// + 5 to prevent it from wrapping unnecessarily
|
// + 5 to prevent it from wrapping unnecessarily
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import QtQuick.Layouts
|
|||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
import org.kde.kirigamiaddons.components as KirigamiComponents
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
|
import org.kde.prison
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ Kirigami.Dialog {
|
|||||||
|
|
||||||
standardButtons: Kirigami.Dialog.NoButton
|
standardButtons: Kirigami.Dialog.NoButton
|
||||||
|
|
||||||
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24)
|
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
|
||||||
title: i18nc("@title:dialog", "Join Room")
|
title: i18nc("@title:dialog", "Join Room")
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Controls as QQC2
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.config as KConfig
|
import org.kde.config as KConfig
|
||||||
@@ -19,11 +20,6 @@ Kirigami.ApplicationWindow {
|
|||||||
|
|
||||||
property bool initialized: false
|
property bool initialized: false
|
||||||
|
|
||||||
readonly property QuickSwitcher quickSwitcher: QuickSwitcher {
|
|
||||||
connection: root.connection
|
|
||||||
window: root
|
|
||||||
}
|
|
||||||
|
|
||||||
title: {
|
title: {
|
||||||
if (NeoChatConfig.windowTitleFocus) {
|
if (NeoChatConfig.windowTitleFocus) {
|
||||||
return activeFocusItem + " " + (activeFocusItem ? activeFocusItem.Accessible.name : "");
|
return activeFocusItem + " " + (activeFocusItem ? activeFocusItem.Accessible.name : "");
|
||||||
@@ -87,7 +83,6 @@ Kirigami.ApplicationWindow {
|
|||||||
active: Kirigami.Settings.hasPlatformMenuBar && !Kirigami.Settings.isMobile
|
active: Kirigami.Settings.hasPlatformMenuBar && !Kirigami.Settings.isMobile
|
||||||
sourceComponent: GlobalMenu {
|
sourceComponent: GlobalMenu {
|
||||||
connection: root.connection
|
connection: root.connection
|
||||||
appWindow: root
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,12 +90,19 @@ Kirigami.ApplicationWindow {
|
|||||||
configGroupName: "MainWindow"
|
configGroupName: "MainWindow"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QuickSwitcher {
|
||||||
|
id: quickSwitcher
|
||||||
|
connection: root.connection
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: RoomManager
|
target: RoomManager
|
||||||
|
|
||||||
function onCurrentRoomChanged() {
|
function onCurrentRoomChanged() {
|
||||||
if (RoomManager.currentRoom && root.pageStack.depth <= 1 && root.initialized && Kirigami.Settings.isMobile) {
|
if (RoomManager.currentRoom && pageStack.depth <= 1 && root.initialized && Kirigami.Settings.isMobile) {
|
||||||
let roomPage = root.pageStack.layers.push(Qt.createComponent('org.kde.neochat', 'RoomPage'));
|
let roomPage = pageStack.layers.push(Qt.createComponent('org.kde.neochat', 'RoomPage'), {
|
||||||
|
connection: root.connection
|
||||||
|
});
|
||||||
roomPage.backRequested.connect(event => {
|
roomPage.backRequested.connect(event => {
|
||||||
RoomManager.clearCurrentRoom();
|
RoomManager.clearCurrentRoom();
|
||||||
});
|
});
|
||||||
@@ -108,26 +110,33 @@ Kirigami.ApplicationWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onAskJoinRoom(room) {
|
function onAskJoinRoom(room) {
|
||||||
(Qt.createComponent("org.kde.neochat", "JoinRoomDialog").createObject(root, {
|
Qt.createComponent("org.kde.neochat", "JoinRoomDialog").createObject(root, {
|
||||||
room: room,
|
room: room,
|
||||||
connection: root.connection
|
connection: root.connection
|
||||||
}) as JoinRoomDialog).open();
|
}).open();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onShowUserDetail(user, room) {
|
function onShowUserDetail(user, room) {
|
||||||
root.showUserDetail(user, room);
|
root.showUserDetail(user, room);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goToEvent(event) {
|
||||||
|
if (event.length > 0) {
|
||||||
|
roomItem.goToEvent(event);
|
||||||
|
}
|
||||||
|
roomItem.forceActiveFocus();
|
||||||
|
}
|
||||||
|
|
||||||
function onAskDirectChatConfirmation(user) {
|
function onAskDirectChatConfirmation(user) {
|
||||||
(Qt.createComponent("org.kde.neochat", "AskDirectChatConfirmation").createObject(this, {
|
Qt.createComponent("org.kde.neochat", "AskDirectChatConfirmation").createObject(this, {
|
||||||
user: user
|
user: user
|
||||||
}) as AskDirectChatConfirmation).open();
|
}).open();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onExternalUrl(url) {
|
function onExternalUrl(url) {
|
||||||
(Qt.createComponent("org.kde.neochat", "ConfirmUrlDialog").createObject(this, {
|
let dialog = Qt.createComponent("org.kde.neochat", "ConfirmUrlDialog").createObject(this);
|
||||||
link: url
|
dialog.link = url;
|
||||||
}) as ConfirmUrlDialog).open();
|
dialog.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +200,7 @@ Kirigami.ApplicationWindow {
|
|||||||
dim = false;
|
dim = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enabled: RoomManager.hasOpenRoom && root.pageStack.layers.depth < 2 && root.pageStack.depth < 3 && (root.pageStack.visibleItems.length > 1 || root.pageStack.currentIndex > 0) && !Kirigami.Settings.isMobile && root.pageStack.wideMode
|
enabled: RoomManager.hasOpenRoom && pageStack.layers.depth < 2 && pageStack.depth < 3 && (pageStack.visibleItems.length > 1 || pageStack.currentIndex > 0) && !Kirigami.Settings.isMobile && root.pageStack.wideMode
|
||||||
handleVisible: enabled
|
handleVisible: enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,10 +222,10 @@ Kirigami.ApplicationWindow {
|
|||||||
Connections {
|
Connections {
|
||||||
target: NeoChatConfig
|
target: NeoChatConfig
|
||||||
function onBlurChanged() {
|
function onBlurChanged() {
|
||||||
WindowController.setBlur(root.pageStack, NeoChatConfig.blur && !NeoChatConfig.compactLayout);
|
WindowController.setBlur(pageStack, NeoChatConfig.blur && !NeoChatConfig.compactLayout);
|
||||||
}
|
}
|
||||||
function onCompactLayoutChanged() {
|
function onCompactLayoutChanged() {
|
||||||
WindowController.setBlur(root.pageStack, NeoChatConfig.blur && !NeoChatConfig.compactLayout);
|
WindowController.setBlur(pageStack, NeoChatConfig.blur && !NeoChatConfig.compactLayout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,8 +280,8 @@ Kirigami.ApplicationWindow {
|
|||||||
target: AccountRegistry
|
target: AccountRegistry
|
||||||
function onRowsRemoved() {
|
function onRowsRemoved() {
|
||||||
if (AccountRegistry.rowCount() === 0) {
|
if (AccountRegistry.rowCount() === 0) {
|
||||||
root.pageStack.clear();
|
pageStack.clear();
|
||||||
root.pageStack.push(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'));
|
pageStack.push(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,7 +290,7 @@ Kirigami.ApplicationWindow {
|
|||||||
target: Controller
|
target: Controller
|
||||||
|
|
||||||
function onErrorOccured(error) {
|
function onErrorOccured(error) {
|
||||||
root.showPassiveNotification(error, "short");
|
showPassiveNotification(error, "short");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,9 +305,9 @@ Kirigami.ApplicationWindow {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function onUserConsentRequired(url) {
|
function onUserConsentRequired(url) {
|
||||||
(Qt.createComponent("org.kde.neochat", "ConsentDialog").createObject(this, {
|
Qt.createComponent("org.kde.neochat", "ConsentDialog").createObject(this, {
|
||||||
url: url
|
url: url
|
||||||
}) as ConsentDialog).open();
|
}).open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,7 +338,7 @@ Kirigami.ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function handleShare(): void {
|
function handleShare(): void {
|
||||||
const dialog = root.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), {
|
const dialog = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), {
|
||||||
connection: root.connection
|
connection: root.connection
|
||||||
}, {
|
}, {
|
||||||
title: i18nc("@title", "Share"),
|
title: i18nc("@title", "Share"),
|
||||||
@@ -346,7 +355,7 @@ Kirigami.ApplicationWindow {
|
|||||||
room: room,
|
room: room,
|
||||||
user: user,
|
user: user,
|
||||||
connection: root.connection,
|
connection: root.connection,
|
||||||
}) as UserDetailDialog;
|
});
|
||||||
dialog.parent = QmlUtils.focusedWindowItem(); // Kirigami Dialogs overwrite the parent, so we need to set it again
|
dialog.parent = QmlUtils.focusedWindowItem(); // Kirigami Dialogs overwrite the parent, so we need to set it again
|
||||||
dialog.open();
|
dialog.open();
|
||||||
}
|
}
|
||||||
@@ -356,7 +365,9 @@ Kirigami.ApplicationWindow {
|
|||||||
RoomManager.loadInitialRoom();
|
RoomManager.loadInitialRoom();
|
||||||
|
|
||||||
if (!Kirigami.Settings.isMobile) {
|
if (!Kirigami.Settings.isMobile) {
|
||||||
let roomPage = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage'));
|
let roomPage = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage'), {
|
||||||
|
connection: root.connection
|
||||||
|
});
|
||||||
roomPage.forceActiveFocus();
|
roomPage.forceActiveFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ Kirigami.Page {
|
|||||||
icon.name: "document-edit"
|
icon.name: "document-edit"
|
||||||
visible: root.allowEdit
|
visible: root.allowEdit
|
||||||
enabled: room.canSendState(root.type) && (!root.stateKey.startsWith("@") || root.stateKey === root.room.connection.localUserId) && root.type !== "m.room.create"
|
enabled: room.canSendState(root.type) && (!root.stateKey.startsWith("@") || root.stateKey === root.room.connection.localUserId) && root.type !== "m.room.create"
|
||||||
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "EditStateDialog"), {
|
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "EditStateDialog.qml"), {
|
||||||
room: root.room,
|
room: root.room,
|
||||||
type: root.type,
|
type: root.type,
|
||||||
stateKey: root.stateKey,
|
stateKey: root.stateKey,
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
|
// SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
|
||||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -10,8 +8,11 @@ import QtQuick.Layouts
|
|||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
|
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
|
||||||
import org.kde.kirigamiaddons.delegates as Delegates
|
import org.kde.kirigamiaddons.delegates as Delegates
|
||||||
|
|
||||||
|
import Quotient
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
|
|
||||||
Kirigami.Dialog {
|
Kirigami.Dialog {
|
||||||
@@ -33,7 +34,7 @@ Kirigami.Dialog {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24)
|
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
|
||||||
title: i18nc("@title: create new poll in the room", "Create Poll")
|
title: i18nc("@title: create new poll in the room", "Create Poll")
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
@@ -42,22 +43,22 @@ Kirigami.Dialog {
|
|||||||
FormCard.FormComboBoxDelegate {
|
FormCard.FormComboBoxDelegate {
|
||||||
id: pollTypeCombo
|
id: pollTypeCombo
|
||||||
|
|
||||||
text: i18nc("@label", "Poll type:")
|
text: i18n("Poll type:")
|
||||||
currentIndex: 0
|
currentIndex: 0
|
||||||
textRole: "text"
|
textRole: "text"
|
||||||
valueRole: "value"
|
valueRole: "value"
|
||||||
model: [
|
model: [
|
||||||
{ value: PollKind.Disclosed, text: i18nc("@item:inlistbox", "Open poll") },
|
{ value: PollKind.Disclosed, text: i18n("Open poll") },
|
||||||
{ value: PollKind.Undisclosed, text: i18nc("@item:inlistbox", "Closed poll") }
|
{ value: PollKind.Undisclosed, text: i18n("Closed poll") }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
FormCard.FormTextDelegate {
|
FormCard.FormTextDelegate {
|
||||||
verticalPadding: 0
|
verticalPadding: 0
|
||||||
text: pollTypeCombo.currentValue == 0 ? i18nc("@info", "Voters can see the result as soon as they have voted") : i18nc("@info", "Results are revealed only after the poll has closed")
|
text: pollTypeCombo.currentValue == 0 ? i18n("Voters can see the result as soon as they have voted") : i18n("Results are revealed only after the poll has closed")
|
||||||
}
|
}
|
||||||
FormCard.FormTextFieldDelegate {
|
FormCard.FormTextFieldDelegate {
|
||||||
id: questionTextField
|
id: questionTextField
|
||||||
label: i18nc("@label", "Question:")
|
label: i18n("Question:")
|
||||||
}
|
}
|
||||||
Repeater {
|
Repeater {
|
||||||
id: optionRepeater
|
id: optionRepeater
|
||||||
@@ -120,12 +121,16 @@ Kirigami.Dialog {
|
|||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
text: i18nc("@action:button", "Remove option")
|
action: Kirigami.Action {
|
||||||
icon.name: "edit-delete-remove"
|
id: removeOptionAction
|
||||||
onClicked: optionModel.remove(optionDelegate.index)
|
text: i18nc("@action:button", "Remove option")
|
||||||
QQC2.ToolTip.text: text
|
icon.name: "edit-delete-remove"
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
onTriggered: optionModel.remove(optionDelegate.index)
|
||||||
QQC2.ToolTip.visible: hovered
|
}
|
||||||
|
QQC2.ToolTip {
|
||||||
|
text: removeOptionAction.text
|
||||||
|
delay: Kirigami.Units.toolTipDelay
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ FileDialog {
|
|||||||
|
|
||||||
signal chosen(string path)
|
signal chosen(string path)
|
||||||
|
|
||||||
title: i18nc("@title:dialog", "Select a File")
|
title: i18n("Select a File")
|
||||||
onAccepted: root.chosen(selectedFile)
|
onAccepted: root.chosen(selectedFile)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ QQC2.Popup {
|
|||||||
contentItem: Flow {
|
contentItem: Flow {
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
icon.name: "format-text-bold"
|
icon.name: "format-text-bold"
|
||||||
text: i18nc("@action:button", "Bold")
|
text: i18n("Bold")
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
@@ -28,7 +29,7 @@ QQC2.Popup {
|
|||||||
end: "**",
|
end: "**",
|
||||||
extra: ""
|
extra: ""
|
||||||
};
|
};
|
||||||
root.formattingSelected(format, root.selectionStart, root.selectionEnd);
|
formattingSelected(format, selectionStart, selectionEnd);
|
||||||
root.close();
|
root.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ QQC2.Popup {
|
|||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
icon.name: "format-text-italic"
|
icon.name: "format-text-italic"
|
||||||
text: i18nc("@action:button", "Italic")
|
text: i18n("Italic")
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
@@ -47,7 +48,7 @@ QQC2.Popup {
|
|||||||
end: "*",
|
end: "*",
|
||||||
extra: ""
|
extra: ""
|
||||||
};
|
};
|
||||||
root.formattingSelected(format, root.selectionStart, root.selectionEnd);
|
formattingSelected(format, selectionStart, selectionEnd);
|
||||||
root.close();
|
root.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ QQC2.Popup {
|
|||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
icon.name: "format-text-strikethrough"
|
icon.name: "format-text-strikethrough"
|
||||||
text: i18nc("@action:button", "Strikethrough")
|
text: i18n("Strikethrough")
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
@@ -66,7 +67,7 @@ QQC2.Popup {
|
|||||||
end: "~~",
|
end: "~~",
|
||||||
extra: ""
|
extra: ""
|
||||||
};
|
};
|
||||||
root.formattingSelected(format, root.selectionStart, root.selectionEnd);
|
formattingSelected(format, selectionStart, selectionEnd);
|
||||||
root.close();
|
root.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ QQC2.Popup {
|
|||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
icon.name: "view-hidden-symbolic"
|
icon.name: "view-hidden-symbolic"
|
||||||
text: i18nc("@action:button", "Spoiler")
|
text: i18n("Spoiler")
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
@@ -85,7 +86,7 @@ QQC2.Popup {
|
|||||||
end: "||",
|
end: "||",
|
||||||
extra: ""
|
extra: ""
|
||||||
};
|
};
|
||||||
root.formattingSelected(format, root.selectionStart, root.selectionEnd);
|
formattingSelected(format, selectionStart, selectionEnd);
|
||||||
root.close();
|
root.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ QQC2.Popup {
|
|||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
icon.name: "format-text-code"
|
icon.name: "format-text-code"
|
||||||
text: i18nc("@action:button", "Code block")
|
text: i18n("Code block")
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
@@ -104,7 +105,7 @@ QQC2.Popup {
|
|||||||
end: "`",
|
end: "`",
|
||||||
extra: ""
|
extra: ""
|
||||||
};
|
};
|
||||||
root.formattingSelected(format, root.selectionStart, root.selectionEnd);
|
formattingSelected(format, selectionStart, selectionEnd);
|
||||||
root.close();
|
root.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,16 +115,16 @@ QQC2.Popup {
|
|||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
icon.name: "format-text-blockquote"
|
icon.name: "format-text-blockquote"
|
||||||
text: i18nc("@action:button", "Quote")
|
text: i18n("Quote")
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const format = {
|
const format = {
|
||||||
start: root.selectionStart == 0 ? ">" : "\n>",
|
start: selectionStart == 0 ? ">" : "\n>",
|
||||||
end: "\n\n",
|
end: "\n\n",
|
||||||
extra: ""
|
extra: ""
|
||||||
};
|
};
|
||||||
root.formattingSelected(format, root.selectionStart, root.selectionEnd);
|
formattingSelected(format, selectionStart, selectionEnd);
|
||||||
root.close();
|
root.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +134,7 @@ QQC2.Popup {
|
|||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
icon.name: "link"
|
icon.name: "link"
|
||||||
text: i18nc("@action:button", "Insert link")
|
text: i18n("Insert link")
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
@@ -142,7 +143,7 @@ QQC2.Popup {
|
|||||||
end: "](",
|
end: "](",
|
||||||
extra: ")"
|
extra: ")"
|
||||||
};
|
};
|
||||||
root.formattingSelected(format, root.selectionStart, root.selectionEnd);
|
formattingSelected(format, selectionStart, selectionEnd);
|
||||||
root.close();
|
root.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
import org.kde.kitemmodels
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
|
|
||||||
@@ -14,15 +14,14 @@ Kirigami.SearchDialog {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property NeoChatConnection connection
|
required property NeoChatConnection connection
|
||||||
required property Kirigami.ApplicationWindow window
|
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Ctrl+K"
|
sequence: "Ctrl+K"
|
||||||
onActivated: if (root.connection) root.open()
|
onActivated: root.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
onAccepted: if (currentItem) {
|
onAccepted: if (currentItem) {
|
||||||
(currentItem as QQC2.ItemDelegate).clicked();
|
currentItem.clicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
onTextChanged: RoomManager.sortFilterRoomListModel.filterText = text
|
onTextChanged: RoomManager.sortFilterRoomListModel.filterText = text
|
||||||
@@ -34,7 +33,7 @@ Kirigami.SearchDialog {
|
|||||||
icon.name: "compass"
|
icon.name: "compass"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.close()
|
root.close()
|
||||||
let dialog = root.window.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
|
let dialog = pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
|
||||||
connection: root.connection
|
connection: root.connection
|
||||||
}, {
|
}, {
|
||||||
title: i18nc("@title", "Explore Rooms")
|
title: i18nc("@title", "Explore Rooms")
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import QtQuick.Layouts
|
|||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
||||||
|
import org.kde.neochat
|
||||||
|
|
||||||
Kirigami.Page {
|
Kirigami.Page {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ Kirigami.Dialog {
|
|||||||
|
|
||||||
property var connection
|
property var connection
|
||||||
|
|
||||||
|
parent: applicationWindow().overlay
|
||||||
|
|
||||||
leftPadding: 0
|
leftPadding: 0
|
||||||
rightPadding: 0
|
rightPadding: 0
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
@@ -22,7 +24,7 @@ Kirigami.Dialog {
|
|||||||
|
|
||||||
title: i18nc("@title Join <name of a space>", "Join %1", SpaceHierarchyCache.recommendedSpaceDisplayName)
|
title: i18nc("@title Join <name of a space>", "Join %1", SpaceHierarchyCache.recommendedSpaceDisplayName)
|
||||||
|
|
||||||
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24)
|
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
FormCard.AbstractFormDelegate {
|
FormCard.AbstractFormDelegate {
|
||||||
|
|||||||
@@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuick.Window
|
import QtQuick.Window
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
import org.kde.kitemmodels
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
|
|
||||||
@@ -62,18 +64,18 @@ Kirigami.Page {
|
|||||||
|
|
||||||
actions: [
|
actions: [
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
visible: Kirigami.Settings.isMobile || !(root.Kirigami.PageStack.pageStack as Kirigami.PageRow).wideMode
|
visible: Kirigami.Settings.isMobile || !applicationWindow().pageStack.wideMode
|
||||||
icon.name: "view-right-new"
|
icon.name: "view-right-new"
|
||||||
onTriggered: (root.QQC2.ApplicationWindow.window as Main).openRoomDrawer()
|
onTriggered: applicationWindow().openRoomDrawer()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
KeyNavigation.left: (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).get(0)
|
KeyNavigation.left: pageStack.get(0)
|
||||||
|
|
||||||
onCurrentRoomChanged: {
|
onCurrentRoomChanged: {
|
||||||
banner.visible = false;
|
banner.visible = false;
|
||||||
if (!Kirigami.Settings.isMobile && chatBarLoader.item) {
|
if (!Kirigami.Settings.isMobile && chatBarLoader.item) {
|
||||||
(chatBarLoader.item as ChatBar).forceActiveFocus();
|
chatBarLoader.item.forceActiveFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +83,7 @@ Kirigami.Page {
|
|||||||
target: root.currentRoom.connection
|
target: root.currentRoom.connection
|
||||||
function onIsOnlineChanged() {
|
function onIsOnlineChanged() {
|
||||||
if (!root.currentRoom.connection.isOnline) {
|
if (!root.currentRoom.connection.isOnline) {
|
||||||
banner.text = i18nc("@info:status", "NeoChat is offline. Please check your network connection.");
|
banner.text = i18n("NeoChat is offline. Please check your network connection.");
|
||||||
banner.visible = true;
|
banner.visible = true;
|
||||||
banner.type = Kirigami.MessageType.Error;
|
banner.type = Kirigami.MessageType.Error;
|
||||||
} else {
|
} else {
|
||||||
@@ -136,8 +138,8 @@ Kirigami.Page {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
sourceComponent: Kirigami.PlaceholderMessage {
|
sourceComponent: Kirigami.PlaceholderMessage {
|
||||||
icon.name: "org.kde.neochat"
|
icon.name: "org.kde.neochat"
|
||||||
text: i18nc("@title", "Welcome to NeoChat")
|
text: i18n("Welcome to NeoChat")
|
||||||
explanation: i18nc("@info:usagetip", "Select or join a room to get started")
|
explanation: i18n("Select or join a room to get started")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,10 +186,10 @@ Kirigami.Page {
|
|||||||
Keys.onPressed: event => {
|
Keys.onPressed: event => {
|
||||||
if (event.key === Qt.Key_PageUp) {
|
if (event.key === Qt.Key_PageUp) {
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
(timelineViewLoader.item as TimelineView).pageUp();
|
timelineViewLoader.item.pageUp();
|
||||||
} else if (event.key === Qt.Key_PageDown) {
|
} else if (event.key === Qt.Key_PageDown) {
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
(timelineViewLoader.item as TimelineView).pageDown();
|
timelineViewLoader.item.pageDown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,10 +203,10 @@ Kirigami.Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onShowEventSource(eventId) {
|
function onShowEventSource(eventId) {
|
||||||
(root.Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'MessageSourceSheet'), {
|
||||||
sourceText: root.currentRoom.getEventJsonSource(eventId)
|
sourceText: root.currentRoom.getEventJsonSource(eventId)
|
||||||
}, {
|
}, {
|
||||||
title: i18nc("@title:dialog", "Message Source"),
|
title: i18n("Message Source"),
|
||||||
width: Kirigami.Units.gridUnit * 25
|
width: Kirigami.Units.gridUnit * 25
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,14 +67,10 @@ QQC2.ComboBox {
|
|||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
visible: serverItem.isAddServerDelegate || serverItem.isDeletable
|
visible: serverItem.isAddServerDelegate || serverItem.isDeletable
|
||||||
icon.name: serverItem.isAddServerDelegate ? "list-add" : "dialog-close"
|
icon.name: serverItem.isAddServerDelegate ? "list-add" : "dialog-close"
|
||||||
text: serverItem.isAddServerDelegate ? i18nc("@action:button", "Add new server") : i18nc("@action:button", "Remove server")
|
text: i18nc("@action:button", "Add new server")
|
||||||
Accessible.name: text
|
Accessible.name: text
|
||||||
display: QQC2.AbstractButton.IconOnly
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
QQC2.ToolTip.text: text
|
|
||||||
QQC2.ToolTip.visible: hovered
|
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.currentIndex === serverItem.index && serverItem.isDeletable) {
|
if (root.currentIndex === serverItem.index && serverItem.isDeletable) {
|
||||||
root.currentIndex = 0;
|
root.currentIndex = 0;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu>
|
// SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu>
|
||||||
// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.purpose as Purpose
|
import org.kde.purpose as Purpose
|
||||||
@@ -21,8 +20,10 @@ Kirigami.Action {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
icon.name: "emblem-shared-symbolic"
|
icon.name: "emblem-shared-symbolic"
|
||||||
text: i18nc("@action:button", "Share")
|
text: i18n("Share")
|
||||||
tooltip: i18nc("@info:tooltip", "Share the selected media")
|
tooltip: i18n("Share the selected media")
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This property holds the input data for purpose.
|
* This property holds the input data for purpose.
|
||||||
@@ -48,21 +49,18 @@ Kirigami.Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delegate: Kirigami.Action {
|
delegate: Kirigami.Action {
|
||||||
required property int index
|
property int index
|
||||||
required property string display
|
text: model.display
|
||||||
required property string iconName
|
icon.name: model.iconName
|
||||||
|
|
||||||
text: display
|
|
||||||
icon.name: iconName
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.room.download(root.eventId, root.inputData.urls[0]);
|
root.room.download(root.eventId, root.inputData.urls[0]);
|
||||||
root.room.fileTransferCompleted.connect(share);
|
root.room.fileTransferCompleted.connect(share);
|
||||||
}
|
}
|
||||||
function share(id: string): void {
|
function share(id) {
|
||||||
if (id != root.eventId) {
|
if (id != root.eventId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "ShareDialog"), {
|
applicationWindow().pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "ShareDialog"), {
|
||||||
title: root.text,
|
title: root.text,
|
||||||
index: index,
|
index: index,
|
||||||
model: root._instantiator.model
|
model: root._instantiator.model
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
|
|
||||||
import org.kde.purpose as Purpose
|
import org.kde.purpose as Purpose
|
||||||
@@ -23,7 +24,7 @@ Kirigami.Page {
|
|||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
|
|
||||||
property alias index: jobView.index
|
property alias index: jobView.index
|
||||||
required property var model
|
property alias model: jobView.model
|
||||||
|
|
||||||
QQC2.Action {
|
QQC2.Action {
|
||||||
shortcut: 'Escape'
|
shortcut: 'Escape'
|
||||||
@@ -33,7 +34,7 @@ Kirigami.Page {
|
|||||||
Notification {
|
Notification {
|
||||||
id: sharingFailed
|
id: sharingFailed
|
||||||
eventId: "Share"
|
eventId: "Share"
|
||||||
text: i18nc("@info:status", "Sharing failed")
|
text: i18n("Sharing failed")
|
||||||
urgency: Notification.NormalUrgency
|
urgency: Notification.NormalUrgency
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,12 +51,11 @@ Kirigami.Page {
|
|||||||
Purpose.JobView {
|
Purpose.JobView {
|
||||||
id: jobView
|
id: jobView
|
||||||
|
|
||||||
model: root.model
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onStateChanged: {
|
onStateChanged: {
|
||||||
if (state === Purpose.PurposeJobController.Finished) {
|
if (state === Purpose.PurposeJobController.Finished) {
|
||||||
if (jobView.job?.output?.url?.length > 0) {
|
if (jobView.job?.output?.url?.length > 0) {
|
||||||
sharingSuccess.text = i18nc("@info", "Shared url for image is <a href='%1'>%1</a>", jobView.job.output.url);
|
sharingSuccess.text = i18n("Shared url for image is <a href='%1'>%1</a>", jobView.job.output.url);
|
||||||
sharingSuccess.sendEvent();
|
sharingSuccess.sendEvent();
|
||||||
Clipboard.saveText(jobView.job.output.url);
|
Clipboard.saveText(jobView.job.output.url);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import 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
|
||||||
|
|||||||
@@ -142,95 +142,107 @@ Kirigami.Dialog {
|
|||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
visible: root.user.id !== root.connection.localUserId && !!root.user
|
visible: root.user.id !== root.connection.localUserId && !!root.user
|
||||||
text: !!root.user && root.connection.isIgnored(root.user.id) ? i18n("Unignore this user") : i18n("Ignore this user")
|
action: Kirigami.Action {
|
||||||
icon.name: "im-invisible-user"
|
text: !!root.user && root.connection.isIgnored(root.user.id) ? i18n("Unignore this user") : i18n("Ignore this user")
|
||||||
onClicked: {
|
icon.name: "im-invisible-user"
|
||||||
root.close();
|
onTriggered: {
|
||||||
root.connection.isIgnored(root.user.id) ? root.connection.removeFromIgnoredUsers(root.user.id) : root.connection.addToIgnoredUsers(root.user.id);
|
root.close();
|
||||||
|
root.connection.isIgnored(root.user.id) ? root.connection.removeFromIgnoredUsers(root.user.id) : root.connection.addToIgnoredUsers(root.user.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("kick") && room.containsUser(root.user.id) && room.memberEffectivePowerLevel(root.user.id) < room.memberEffectivePowerLevel(root.connection.localUserId)
|
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("kick") && room.containsUser(root.user.id) && room.memberEffectivePowerLevel(root.user.id) < room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||||
|
|
||||||
text: i18nc("@action:button", "Kick this user")
|
action: Kirigami.Action {
|
||||||
icon.name: "im-kick-user"
|
text: i18n("Kick this user")
|
||||||
onClicked: {
|
icon.name: "im-kick-user"
|
||||||
let dialog = (root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
onTriggered: {
|
||||||
title: i18nc("@title:dialog", "Kick User"),
|
let dialog = (root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||||
placeholder: i18nc("@info:placeholder", "Reason for kicking this user"),
|
title: i18nc("@title:dialog", "Kick User"),
|
||||||
actionText: i18nc("@action:button 'Kick' as in 'Kick this user from the room'", "Kick"),
|
placeholder: i18nc("@info:placeholder", "Reason for kicking this user"),
|
||||||
icon: "im-kick-user"
|
actionText: i18nc("@action:button 'Kick' as in 'Kick this user from the room'", "Kick"),
|
||||||
}, {
|
icon: "im-kick-user"
|
||||||
title: i18nc("@title:dialog", "Kick User"),
|
}, {
|
||||||
width: Kirigami.Units.gridUnit * 25
|
title: i18nc("@title:dialog", "Kick User"),
|
||||||
});
|
width: Kirigami.Units.gridUnit * 25
|
||||||
dialog.accepted.connect(reason => {
|
});
|
||||||
root.room.kickMember(root.user.id, reason);
|
dialog.accepted.connect(reason => {
|
||||||
});
|
root.room.kickMember(root.user.id, reason);
|
||||||
root.close();
|
});
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("invite") && !room.containsUser(root.user.id)
|
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("invite") && !room.containsUser(root.user.id)
|
||||||
|
|
||||||
enabled: root.room && !root.room.isUserBanned(root.user.id)
|
action: Kirigami.Action {
|
||||||
text: i18nc("@action:button", "Invite this user")
|
enabled: root.room && !root.room.isUserBanned(root.user.id)
|
||||||
icon.name: "list-add-user"
|
text: i18n("Invite this user")
|
||||||
onClicked: {
|
icon.name: "list-add-user"
|
||||||
root.room.inviteToRoom(root.user.id);
|
onTriggered: {
|
||||||
root.close();
|
root.room.inviteToRoom(root.user.id);
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("ban") && !room.isUserBanned(root.user.id) && room.memberEffectivePowerLevel(root.user.id) < room.memberEffectivePowerLevel(root.connection.localUserId)
|
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("ban") && !room.isUserBanned(root.user.id) && room.memberEffectivePowerLevel(root.user.id) < room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||||
|
|
||||||
text: i18nc("@action:button", "Ban this user")
|
action: Kirigami.Action {
|
||||||
icon.name: "im-ban-user"
|
text: i18n("Ban this user")
|
||||||
icon.color: Kirigami.Theme.negativeTextColor
|
icon.name: "im-ban-user"
|
||||||
onClicked: {
|
icon.color: Kirigami.Theme.negativeTextColor
|
||||||
let dialog = (root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
onTriggered: {
|
||||||
title: i18nc("@title:dialog", "Ban User"),
|
let dialog = (root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||||
placeholder: i18nc("@info:placeholder", "Reason for banning this user"),
|
title: i18nc("@title:dialog", "Ban User"),
|
||||||
actionText: i18nc("@action:button 'Ban' as in 'Ban this user'", "Ban"),
|
placeholder: i18nc("@info:placeholder", "Reason for banning this user"),
|
||||||
icon: "im-ban-user"
|
actionText: i18nc("@action:button 'Ban' as in 'Ban this user'", "Ban"),
|
||||||
}, {
|
icon: "im-ban-user"
|
||||||
title: i18nc("@title:dialog", "Ban User"),
|
}, {
|
||||||
width: Kirigami.Units.gridUnit * 25
|
title: i18nc("@title:dialog", "Ban User"),
|
||||||
});
|
width: Kirigami.Units.gridUnit * 25
|
||||||
dialog.accepted.connect(reason => {
|
});
|
||||||
root.room.ban(root.user.id, reason);
|
dialog.accepted.connect(reason => {
|
||||||
});
|
root.room.ban(root.user.id, reason);
|
||||||
root.close();
|
});
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("ban") && room.isUserBanned(root.user.id)
|
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("ban") && room.isUserBanned(root.user.id)
|
||||||
|
|
||||||
text: i18nc("@action:button", "Unban this user")
|
action: Kirigami.Action {
|
||||||
icon.name: "im-irc"
|
text: i18n("Unban this user")
|
||||||
icon.color: Kirigami.Theme.negativeTextColor
|
icon.name: "im-irc"
|
||||||
onClicked: {
|
icon.color: Kirigami.Theme.negativeTextColor
|
||||||
root.room.unban(root.user.id);
|
onTriggered: {
|
||||||
root.close();
|
root.room.unban(root.user.id);
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
visible: root.room && root.room.canSendState("m.room.power_levels")
|
visible: root.room && root.room.canSendState("m.room.power_levels")
|
||||||
text: i18nc("@action:button", "Set user power level")
|
action: Kirigami.Action {
|
||||||
icon.name: "visibility"
|
text: i18n("Set user power level")
|
||||||
onClicked: {
|
icon.name: "visibility"
|
||||||
let dialog = powerLevelDialog.createObject(this, {
|
onTriggered: {
|
||||||
room: root.room,
|
let dialog = powerLevelDialog.createObject(this, {
|
||||||
userId: root.user.id,
|
room: root.room,
|
||||||
powerLevel: root.room.memberEffectivePowerLevel(root.user.id)
|
userId: root.user.id,
|
||||||
});
|
powerLevel: root.room.memberEffectivePowerLevel(root.user.id)
|
||||||
dialog.open();
|
});
|
||||||
root.close();
|
dialog.open();
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
@@ -244,40 +256,48 @@ Kirigami.Dialog {
|
|||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
visible: root.room && (root.user.id === root.connection.localUserId || room.canSendState("redact"))
|
visible: root.room && (root.user.id === root.connection.localUserId || room.canSendState("redact"))
|
||||||
|
|
||||||
text: i18nc("@action:button", "Remove recent messages by this user")
|
action: Kirigami.Action {
|
||||||
icon.name: "delete"
|
text: i18nc("@action:button", "Remove recent messages by this user")
|
||||||
icon.color: Kirigami.Theme.negativeTextColor
|
icon.name: "delete"
|
||||||
onClicked: {
|
icon.color: Kirigami.Theme.negativeTextColor
|
||||||
let dialog = pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
onTriggered: {
|
||||||
title: i18nc("@title:dialog", "Remove Messages"),
|
let dialog = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||||
placeholder: i18nc("@info:placeholder", "Reason for removing this user's recent messages"),
|
title: i18nc("@title:dialog", "Remove Messages"),
|
||||||
actionText: i18nc("@action:button 'Remove' as in 'Remove these messages'", "Remove"),
|
placeholder: i18nc("@info:placeholder", "Reason for removing this user's recent messages"),
|
||||||
icon: "delete"
|
actionText: i18nc("@action:button 'Remove' as in 'Remove these messages'", "Remove"),
|
||||||
}, {
|
icon: "delete"
|
||||||
title: i18nc("@title", "Remove Messages"),
|
}, {
|
||||||
width: Kirigami.Units.gridUnit * 25
|
title: i18nc("@title", "Remove Messages"),
|
||||||
});
|
width: Kirigami.Units.gridUnit * 25
|
||||||
dialog.accepted.connect(reason => {
|
});
|
||||||
root.room.deleteMessagesByUser(root.user.id, reason);
|
dialog.accepted.connect(reason => {
|
||||||
});
|
root.room.deleteMessagesByUser(root.user.id, reason);
|
||||||
root.close();
|
});
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
visible: root.user.id !== root.connection.localUserId
|
visible: root.user.id !== root.connection.localUserId
|
||||||
text: root.connection.directChatExists(root.user) ? i18nc("%1 is the name of the user.", "Chat with %1", root.room ? root.room.member(root.user.id).htmlSafeDisplayName : QmlUtils.escapeString(root.user.displayName)) : i18n("Invite to private chat")
|
action: Kirigami.Action {
|
||||||
icon.name: "document-send"
|
text: root.connection.directChatExists(root.user) ? i18nc("%1 is the name of the user.", "Chat with %1", root.room ? root.room.member(root.user.id).htmlSafeDisplayName : QmlUtils.escapeString(root.user.displayName)) : i18n("Invite to private chat")
|
||||||
onClicked: {
|
icon.name: "document-send"
|
||||||
root.connection.requestDirectChat(root.user.id);
|
onTriggered: {
|
||||||
root.close();
|
root.connection.requestDirectChat(root.user.id);
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
text: i18n("Copy link")
|
action: Kirigami.Action {
|
||||||
icon.name: "username-copy"
|
text: i18n("Copy link")
|
||||||
onClicked: Clipboard.saveText("https://matrix.to/#/" + root.user.id)
|
icon.name: "username-copy"
|
||||||
|
onTriggered: {
|
||||||
|
Clipboard.saveText("https://matrix.to/#/" + root.user.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,19 +236,11 @@ void RoomManager::resolveResource(Uri uri, const QString &action)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomManager::maximizeMedia(const QString &eventId)
|
void RoomManager::maximizeMedia(int index)
|
||||||
{
|
{
|
||||||
if (eventId.isEmpty()) {
|
if (index < -1 || index > m_mediaMessageFilterModel->rowCount()) {
|
||||||
qWarning() << "Tried to open media for empty event id";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto index = m_mediaMessageFilterModel->getRowForEventId(eventId);
|
|
||||||
if (index == -1) {
|
|
||||||
qWarning() << "Tried to open media for unknown event id" << eventId;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_EMIT showMaximizedMedia(index);
|
Q_EMIT showMaximizedMedia(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,17 +264,8 @@ void RoomManager::viewEventSource(const QString &eventId)
|
|||||||
|
|
||||||
void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText, const QString &hoveredLink)
|
void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText, const QString &hoveredLink)
|
||||||
{
|
{
|
||||||
if (eventId.isEmpty()) {
|
const auto &event = **room->findInTimeline(eventId);
|
||||||
qWarning() << "Tried to open event menu with empty event id";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto it = room->findInTimeline(eventId);
|
|
||||||
if (it == room->historyEdge()) {
|
|
||||||
// This is probably a pending event
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto &event = **it;
|
|
||||||
if (EventHandler::mediaInfo(room, &event).contains("mimeType"_L1)) {
|
if (EventHandler::mediaInfo(room, &event).contains("mimeType"_L1)) {
|
||||||
Q_EMIT showFileMenu(eventId,
|
Q_EMIT showFileMenu(eventId,
|
||||||
sender,
|
sender,
|
||||||
@@ -375,6 +358,19 @@ void RoomManager::visitRoom(Room *r, const QString &eventId)
|
|||||||
if (m_currentRoom && !m_currentRoom->editCache()->editId().isEmpty()) {
|
if (m_currentRoom && !m_currentRoom->editCache()->editId().isEmpty()) {
|
||||||
m_currentRoom->editCache()->setEditId({});
|
m_currentRoom->editCache()->setEditId({});
|
||||||
}
|
}
|
||||||
|
if (m_currentRoom && !m_currentRoom->isSpace() && m_chatDocumentHandler) {
|
||||||
|
// We're doing these things here because it is critical that they are switched at the same time
|
||||||
|
if (m_chatDocumentHandler->document()) {
|
||||||
|
m_currentRoom->mainCache()->setSavedText(m_chatDocumentHandler->document()->textDocument()->toPlainText());
|
||||||
|
m_chatDocumentHandler->setRoom(room);
|
||||||
|
if (room) {
|
||||||
|
m_chatDocumentHandler->document()->textDocument()->setPlainText(room->mainCache()->savedText());
|
||||||
|
room->mainCache()->setText(room->mainCache()->savedText());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_chatDocumentHandler->setRoom(room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!room) {
|
if (!room) {
|
||||||
setCurrentRoom({});
|
setCurrentRoom({});
|
||||||
@@ -474,6 +470,18 @@ bool RoomManager::visitNonMatrix(const QUrl &url)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatDocumentHandler *RoomManager::chatDocumentHandler() const
|
||||||
|
{
|
||||||
|
return m_chatDocumentHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoomManager::setChatDocumentHandler(ChatDocumentHandler *handler)
|
||||||
|
{
|
||||||
|
m_chatDocumentHandler = handler;
|
||||||
|
m_chatDocumentHandler->setRoom(m_currentRoom);
|
||||||
|
Q_EMIT chatDocumentHandlerChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void RoomManager::setConnection(NeoChatConnection *connection)
|
void RoomManager::setConnection(NeoChatConnection *connection)
|
||||||
{
|
{
|
||||||
if (m_connection == connection) {
|
if (m_connection == connection) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <Quotient/roommember.h>
|
#include <Quotient/roommember.h>
|
||||||
#include <Quotient/uriresolver.h>
|
#include <Quotient/uriresolver.h>
|
||||||
|
|
||||||
|
#include "chatdocumenthandler.h"
|
||||||
#include "enums/messagecomponenttype.h"
|
#include "enums/messagecomponenttype.h"
|
||||||
#include "enums/messagetype.h"
|
#include "enums/messagetype.h"
|
||||||
#include "models/mediamessagefiltermodel.h"
|
#include "models/mediamessagefiltermodel.h"
|
||||||
@@ -136,6 +137,13 @@ class RoomManager : public QObject, public UriResolverBase
|
|||||||
*/
|
*/
|
||||||
Q_PROPERTY(bool hasOpenRoom READ hasOpenRoom NOTIFY currentRoomChanged)
|
Q_PROPERTY(bool hasOpenRoom READ hasOpenRoom NOTIFY currentRoomChanged)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ChatDocumentHandler for the open room.
|
||||||
|
*
|
||||||
|
* @sa ChatDocumentHandler
|
||||||
|
*/
|
||||||
|
Q_PROPERTY(ChatDocumentHandler *chatDocumentHandler READ chatDocumentHandler WRITE setChatDocumentHandler NOTIFY chatDocumentHandlerChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~RoomManager();
|
virtual ~RoomManager();
|
||||||
static RoomManager &instance();
|
static RoomManager &instance();
|
||||||
@@ -204,8 +212,12 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Show a media item maximized.
|
* @brief Show a media item maximized.
|
||||||
|
*
|
||||||
|
* @param index the index to open the maximize delegate model at. This is the
|
||||||
|
* index in the MediaMessageFilterModel owned by this RoomManager. A value
|
||||||
|
* of -1 opens a the default item.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void maximizeMedia(const QString &eventId);
|
Q_INVOKABLE void maximizeMedia(int index);
|
||||||
|
|
||||||
Q_INVOKABLE void maximizeCode(NeochatRoomMember *author, const QDateTime &time, const QString &codeText, const QString &language);
|
Q_INVOKABLE void maximizeCode(NeochatRoomMember *author, const QDateTime &time, const QString &codeText, const QString &language);
|
||||||
|
|
||||||
@@ -225,6 +237,9 @@ public:
|
|||||||
Q_INVOKABLE void
|
Q_INVOKABLE void
|
||||||
viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText = {}, const QString &hoveredLink = {});
|
viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText = {}, const QString &hoveredLink = {});
|
||||||
|
|
||||||
|
ChatDocumentHandler *chatDocumentHandler() const;
|
||||||
|
void setChatDocumentHandler(ChatDocumentHandler *handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set a URL to be loaded as the initial room.
|
* @brief Set a URL to be loaded as the initial room.
|
||||||
*/
|
*/
|
||||||
@@ -327,6 +342,8 @@ Q_SIGNALS:
|
|||||||
*/
|
*/
|
||||||
void showMessage(MessageType::Type messageType, const QString &message);
|
void showMessage(MessageType::Type messageType, const QString &message);
|
||||||
|
|
||||||
|
void chatDocumentHandlerChanged();
|
||||||
|
|
||||||
void connectionChanged();
|
void connectionChanged();
|
||||||
|
|
||||||
void directChatsActiveChanged();
|
void directChatsActiveChanged();
|
||||||
@@ -355,6 +372,7 @@ private:
|
|||||||
KConfigGroup m_lastRoomConfig;
|
KConfigGroup m_lastRoomConfig;
|
||||||
KConfigGroup m_lastSpaceConfig;
|
KConfigGroup m_lastSpaceConfig;
|
||||||
KConfigGroup m_directChatsConfig;
|
KConfigGroup m_directChatsConfig;
|
||||||
|
QPointer<ChatDocumentHandler> m_chatDocumentHandler;
|
||||||
|
|
||||||
RoomListModel *m_roomListModel;
|
RoomListModel *m_roomListModel;
|
||||||
SortFilterRoomListModel *m_sortFilterRoomListModel;
|
SortFilterRoomListModel *m_sortFilterRoomListModel;
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
#include <QDBusMetaType>
|
#include <QDBusMetaType>
|
||||||
|
|
||||||
#include <KWindowSystem>
|
|
||||||
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "models/roomlistmodel.h"
|
#include "models/roomlistmodel.h"
|
||||||
#include "models/sortfilterroomlistmodel.h"
|
#include "models/sortfilterroomlistmodel.h"
|
||||||
@@ -88,9 +86,4 @@ void Runner::Run(const QString &id, const QString &actionId)
|
|||||||
WindowController::instance().showAndRaiseWindow(QString());
|
WindowController::instance().showAndRaiseWindow(QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runner::SetActivationToken(const QString &token)
|
|
||||||
{
|
|
||||||
KWindowSystem::setCurrentXdgActivationToken(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_runner.cpp"
|
#include "moc_runner.cpp"
|
||||||
|
|||||||
@@ -190,8 +190,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_SCRIPTABLE void Run(const QString &id, const QString &actionId);
|
Q_SCRIPTABLE void Run(const QString &id, const QString &actionId);
|
||||||
|
|
||||||
Q_SCRIPTABLE void SetActivationToken(const QString &token);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void roomListModelChanged();
|
void roomListModelChanged();
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ QQC2.Popup {
|
|||||||
|
|
||||||
icon.name: 'mail-attachment'
|
icon.name: 'mail-attachment'
|
||||||
|
|
||||||
text: i18nc("@action:button", "Choose local file")
|
text: i18n("Choose local file")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.close();
|
root.close();
|
||||||
var fileDialog = openFileDialog.createObject(QQC2.Overlay.overlay) as OpenFileDialog;
|
var fileDialog = openFileDialog.createObject(QQC2.Overlay.overlay);
|
||||||
fileDialog.chosen.connect(path => root.chosen(path));
|
fileDialog.chosen.connect(path => root.chosen(path));
|
||||||
fileDialog.open();
|
fileDialog.open();
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ QQC2.Popup {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
icon.name: 'insert-image'
|
icon.name: 'insert-image'
|
||||||
text: i18nc("@action:button", "Clipboard image")
|
text: i18n("Clipboard image")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const path = StandardPaths.standardLocations(StandardPaths.CacheLocation)[0] + "/screenshots/" + (new Date()).getTime() + ".png";
|
const path = StandardPaths.standardLocations(StandardPaths.CacheLocation)[0] + "/screenshots/" + (new Date()).getTime() + ".png";
|
||||||
if (!Clipboard.saveImage(path)) {
|
if (!Clipboard.saveImage(path)) {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.currentRoom.mainCache
|
target: currentRoom.mainCache
|
||||||
|
|
||||||
function onMentionAdded(mention: string): void {
|
function onMentionAdded(mention: string): void {
|
||||||
// add mention text
|
// add mention text
|
||||||
@@ -74,34 +74,34 @@ QQC2.Control {
|
|||||||
* Each of these will be visualised in the ChatBar so new actions can be added
|
* Each of these will be visualised in the ChatBar so new actions can be added
|
||||||
* by appending to this list.
|
* by appending to this list.
|
||||||
*/
|
*/
|
||||||
property list<BusyAction> actions: [
|
property list<Kirigami.Action> actions: [
|
||||||
BusyAction {
|
Kirigami.Action {
|
||||||
id: attachmentAction
|
id: attachmentAction
|
||||||
|
|
||||||
isBusy: root.currentRoom && root.currentRoom.hasFileUploading
|
property bool isBusy: root.currentRoom && root.currentRoom.hasFileUploading
|
||||||
|
|
||||||
// Matrix does not allow sending attachments in replies
|
// Matrix does not allow sending attachments in replies
|
||||||
visible: _private.chatBarCache.replyId.length === 0 && _private.chatBarCache.attachmentPath.length === 0
|
visible: _private.chatBarCache.replyId.length === 0 && _private.chatBarCache.attachmentPath.length === 0
|
||||||
icon.name: "mail-attachment"
|
icon.name: "mail-attachment"
|
||||||
text: i18nc("@action:button", "Attach an image or file")
|
text: i18n("Attach an image or file")
|
||||||
displayHint: Kirigami.DisplayHint.IconOnly
|
displayHint: Kirigami.DisplayHint.IconOnly
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
let dialog = (Clipboard.hasImage ? attachDialog : openFileDialog).createObject(root.QQC2.Overlay.overlay);
|
let dialog = (Clipboard.hasImage ? attachDialog : openFileDialog).createObject(applicationWindow().overlay);
|
||||||
dialog.chosen.connect(path => _private.chatBarCache.attachmentPath = path);
|
dialog.chosen.connect(path => _private.chatBarCache.attachmentPath = path);
|
||||||
dialog.open();
|
dialog.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
tooltip: text
|
tooltip: text
|
||||||
},
|
},
|
||||||
BusyAction {
|
Kirigami.Action {
|
||||||
id: emojiAction
|
id: emojiAction
|
||||||
|
|
||||||
isBusy: false
|
property bool isBusy: false
|
||||||
|
|
||||||
visible: !Kirigami.Settings.isMobile
|
visible: !Kirigami.Settings.isMobile
|
||||||
icon.name: "smiley"
|
icon.name: "smiley"
|
||||||
text: i18nc("@action:button", "Emojis & Stickers")
|
text: i18n("Emojis & Stickers")
|
||||||
displayHint: Kirigami.DisplayHint.IconOnly
|
displayHint: Kirigami.DisplayHint.IconOnly
|
||||||
checkable: true
|
checkable: true
|
||||||
|
|
||||||
@@ -114,11 +114,11 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
tooltip: text
|
tooltip: text
|
||||||
},
|
},
|
||||||
BusyAction {
|
Kirigami.Action {
|
||||||
id: mapButton
|
id: mapButton
|
||||||
icon.name: "mark-location-symbolic"
|
icon.name: "mark-location-symbolic"
|
||||||
isBusy: false
|
property bool isBusy: false
|
||||||
text: i18nc("@action:button", "Send a Location")
|
text: i18n("Send a Location")
|
||||||
displayHint: QQC2.AbstractButton.IconOnly
|
displayHint: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
@@ -128,10 +128,10 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
tooltip: text
|
tooltip: text
|
||||||
},
|
},
|
||||||
BusyAction {
|
Kirigami.Action {
|
||||||
id: pollButton
|
id: pollButton
|
||||||
icon.name: "amarok_playcount"
|
icon.name: "amarok_playcount"
|
||||||
isBusy: false
|
property bool isBusy: false
|
||||||
text: i18nc("@action:button", "Create a Poll")
|
text: i18nc("@action:button", "Create a Poll")
|
||||||
displayHint: QQC2.AbstractButton.IconOnly
|
displayHint: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
@@ -142,13 +142,13 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
tooltip: text
|
tooltip: text
|
||||||
},
|
},
|
||||||
BusyAction {
|
Kirigami.Action {
|
||||||
id: sendAction
|
id: sendAction
|
||||||
|
|
||||||
isBusy: false
|
property bool isBusy: false
|
||||||
|
|
||||||
icon.name: "document-send"
|
icon.name: "document-send"
|
||||||
text: i18nc("@action:button", "Send message")
|
text: i18n("Send message")
|
||||||
displayHint: Kirigami.DisplayHint.IconOnly
|
displayHint: Kirigami.DisplayHint.IconOnly
|
||||||
checkable: true
|
checkable: true
|
||||||
|
|
||||||
@@ -191,34 +191,18 @@ QQC2.Control {
|
|||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: Kirigami.Units.largeSpacing
|
Layout.margins: Kirigami.Units.largeSpacing
|
||||||
Layout.preferredHeight: active ? (item as Item).implicitHeight : 0
|
Layout.preferredHeight: active ? item.implicitHeight : 0
|
||||||
|
|
||||||
active: visible
|
active: visible
|
||||||
visible: root.currentRoom.mainCache.replyId.length > 0
|
visible: root.currentRoom.mainCache.replyId.length > 0
|
||||||
sourceComponent: replyPane
|
sourceComponent: replyPane
|
||||||
}
|
}
|
||||||
RowLayout {
|
|
||||||
visible: replyLoader.visible && !root.currentRoom.mainCache.relationAuthorIsPresent
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Kirigami.Icon {
|
|
||||||
source: "help-hint-symbolic"
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
|
|
||||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
|
||||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
|
||||||
}
|
|
||||||
QQC2.Label {
|
|
||||||
text: i18nc("@info", "The user you're replying to has left the room, and can't be notified.")
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loader {
|
Loader {
|
||||||
id: attachLoader
|
id: attachLoader
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: Kirigami.Units.largeSpacing
|
Layout.margins: Kirigami.Units.largeSpacing
|
||||||
Layout.preferredHeight: active ? (item as Item).implicitHeight : 0
|
Layout.preferredHeight: active ? item.implicitHeight : 0
|
||||||
|
|
||||||
active: visible
|
active: visible
|
||||||
visible: root.currentRoom.mainCache.attachmentPath.length > 0
|
visible: root.currentRoom.mainCache.attachmentPath.length > 0
|
||||||
@@ -250,10 +234,9 @@ QQC2.Control {
|
|||||||
QQC2.TextArea {
|
QQC2.TextArea {
|
||||||
id: textField
|
id: textField
|
||||||
|
|
||||||
placeholderText: root.currentRoom.usesEncryption ? i18nc("@placeholder", "Send an encrypted message…") : root.currentRoom.mainCache.attachmentPath.length > 0 ? i18nc("@placeholder", "Set an attachment caption…") : i18nc("@placeholder", "Send a message…")
|
placeholderText: root.currentRoom.usesEncryption ? i18n("Send an encrypted message…") : root.currentRoom.mainCache.attachmentPath.length > 0 ? i18n("Set an attachment caption…") : i18n("Send a message…")
|
||||||
verticalAlignment: TextEdit.AlignVCenter
|
verticalAlignment: TextEdit.AlignVCenter
|
||||||
wrapMode: TextEdit.Wrap
|
wrapMode: TextEdit.Wrap
|
||||||
textFormat: TextEdit.MarkdownText
|
|
||||||
|
|
||||||
Accessible.description: placeholderText
|
Accessible.description: placeholderText
|
||||||
|
|
||||||
@@ -270,6 +253,7 @@ QQC2.Control {
|
|||||||
root.currentRoom.sendTypingNotification(textExists);
|
root.currentRoom.sendTypingNotification(textExists);
|
||||||
textExists ? repeatTimer.start() : repeatTimer.stop();
|
textExists ? repeatTimer.start() : repeatTimer.stop();
|
||||||
}
|
}
|
||||||
|
_private.chatBarCache.text = text;
|
||||||
}
|
}
|
||||||
onSelectedTextChanged: {
|
onSelectedTextChanged: {
|
||||||
if (selectedText.length > 0) {
|
if (selectedText.length > 0) {
|
||||||
@@ -285,7 +269,7 @@ QQC2.Control {
|
|||||||
x: textField.cursorRectangle.x
|
x: textField.cursorRectangle.x
|
||||||
y: textField.cursorRectangle.y - height
|
y: textField.cursorRectangle.y - height
|
||||||
|
|
||||||
onFormattingSelected: (format, selectionStart, selectionEnd) => _private.formatText(format, selectionStart, selectionEnd)
|
onFormattingSelected: _private.formatText(format, selectionStart, selectionEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEnterPressed: event => {
|
Keys.onEnterPressed: event => {
|
||||||
@@ -363,8 +347,6 @@ QQC2.Control {
|
|||||||
Repeater {
|
Repeater {
|
||||||
model: root.actions
|
model: root.actions
|
||||||
delegate: QQC2.ToolButton {
|
delegate: QQC2.ToolButton {
|
||||||
id: actionDelegate
|
|
||||||
required property BusyAction modelData
|
|
||||||
icon.name: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
|
icon.name: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
|
||||||
onClicked: modelData.trigger()
|
onClicked: modelData.trigger()
|
||||||
|
|
||||||
@@ -375,7 +357,7 @@ QQC2.Control {
|
|||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
|
||||||
contentItem: PieProgressBar {
|
contentItem: PieProgressBar {
|
||||||
visible: actionDelegate.modelData.isBusy
|
visible: modelData.isBusy
|
||||||
progress: root.currentRoom.fileUploadingProgress
|
progress: root.currentRoom.fileUploadingProgress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -400,6 +382,8 @@ QQC2.Control {
|
|||||||
implicitHeight: replyComponent.implicitHeight
|
implicitHeight: replyComponent.implicitHeight
|
||||||
ReplyComponent {
|
ReplyComponent {
|
||||||
id: replyComponent
|
id: replyComponent
|
||||||
|
replyEventId: _private.chatBarCache.replyId
|
||||||
|
replyAuthor: _private.chatBarCache.relationAuthor
|
||||||
replyContentModel: ContentProvider.contentModelForEvent(root.currentRoom, _private.chatBarCache.replyId, true)
|
replyContentModel: ContentProvider.contentModelForEvent(root.currentRoom, _private.chatBarCache.replyId, true)
|
||||||
Message.maxContentWidth: replyLoader.item.width
|
Message.maxContentWidth: replyLoader.item.width
|
||||||
|
|
||||||
@@ -440,6 +424,7 @@ QQC2.Control {
|
|||||||
QtObject {
|
QtObject {
|
||||||
id: _private
|
id: _private
|
||||||
property ChatBarCache chatBarCache
|
property ChatBarCache chatBarCache
|
||||||
|
onChatBarCacheChanged: documentHandler.chatBarCache = chatBarCache
|
||||||
|
|
||||||
function postMessage() {
|
function postMessage() {
|
||||||
_private.chatBarCache.postMessage();
|
_private.chatBarCache.postMessage();
|
||||||
@@ -501,9 +486,15 @@ QQC2.Control {
|
|||||||
|
|
||||||
ChatDocumentHandler {
|
ChatDocumentHandler {
|
||||||
id: documentHandler
|
id: documentHandler
|
||||||
type: ChatBarType.Room
|
document: textField.textDocument
|
||||||
textItem: textField
|
cursorPosition: textField.cursorPosition
|
||||||
room: root.currentRoom
|
selectionStart: textField.selectionStart
|
||||||
|
selectionEnd: textField.selectionEnd
|
||||||
|
mentionColor: Kirigami.Theme.linkColor
|
||||||
|
errorColor: Kirigami.Theme.negativeTextColor
|
||||||
|
Component.onCompleted: {
|
||||||
|
RoomManager.chatDocumentHandler = documentHandler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
@@ -562,7 +553,7 @@ QQC2.Control {
|
|||||||
|
|
||||||
currentRoom: root.currentRoom
|
currentRoom: root.currentRoom
|
||||||
|
|
||||||
onChosen: emoji => root.insertText(emoji)
|
onChosen: emoji => insertText(emoji)
|
||||||
onClosed: if (emojiAction.checked) {
|
onClosed: if (emojiAction.checked) {
|
||||||
emojiAction.checked = false;
|
emojiAction.checked = false;
|
||||||
}
|
}
|
||||||
@@ -573,8 +564,4 @@ QQC2.Control {
|
|||||||
textField.text = textField.text.substr(0, initialCursorPosition) + text + textField.text.substr(initialCursorPosition);
|
textField.text = textField.text.substr(0, initialCursorPosition) + text + textField.text.substr(initialCursorPosition);
|
||||||
textField.cursorPosition = initialCursorPosition + text.length;
|
textField.cursorPosition = initialCursorPosition + text.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
component BusyAction : Kirigami.Action {
|
|
||||||
required property bool isBusy
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ QQC2.Popup {
|
|||||||
padding: 2
|
padding: 2
|
||||||
|
|
||||||
implicitHeight: Kirigami.Units.gridUnit * 20 + 2 * padding
|
implicitHeight: Kirigami.Units.gridUnit * 20 + 2 * padding
|
||||||
width: Math.min(contentItem.categoryIconSize * 11 + 2 * padding, QQC2.ApplicationWindow.window.width)
|
width: Math.min(contentItem.categoryIconSize * 11 + 2 * padding, applicationWindow().width)
|
||||||
contentItem: EmojiPicker {
|
contentItem: EmojiPicker {
|
||||||
id: emojiPicker
|
id: emojiPicker
|
||||||
height: 400
|
height: 400
|
||||||
|
|||||||
@@ -20,13 +20,6 @@ FormCard.FormCard {
|
|||||||
|
|
||||||
onToggled: NeoChatConfig.showAllEvents = checked
|
onToggled: NeoChatConfig.showAllEvents = checked
|
||||||
}
|
}
|
||||||
FormCard.FormCheckDelegate {
|
|
||||||
text: i18nc("@option:check", "Allow sending relations to any event in the timeline")
|
|
||||||
description: i18nc("@info", "This includes state events")
|
|
||||||
checked: NeoChatConfig.relateAnyEvent
|
|
||||||
|
|
||||||
onToggled: NeoChatConfig.relateAnyEvent = checked
|
|
||||||
}
|
|
||||||
FormCard.FormCheckDelegate {
|
FormCard.FormCheckDelegate {
|
||||||
id: roomAccountDataVisibleCheck
|
id: roomAccountDataVisibleCheck
|
||||||
text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification")
|
text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification")
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import QtQuick.Window
|
|||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
|
import org.kde.kitemmodels
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import QtQuick.Layouts
|
|||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
|
import org.kde.kitemmodels
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import QtQuick.Window
|
|||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
|
import org.kde.kitemmodels
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ target_sources(LibNeoChat PRIVATE
|
|||||||
texthandler.cpp
|
texthandler.cpp
|
||||||
urlhelper.cpp
|
urlhelper.cpp
|
||||||
utils.cpp
|
utils.cpp
|
||||||
enums/chatbartype.h
|
|
||||||
enums/messagecomponenttype.h
|
enums/messagecomponenttype.h
|
||||||
enums/messagetype.h
|
enums/messagetype.h
|
||||||
enums/powerlevel.cpp
|
enums/powerlevel.cpp
|
||||||
@@ -47,10 +46,6 @@ target_sources(LibNeoChat PRIVATE
|
|||||||
models/userlistmodel.cpp
|
models/userlistmodel.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (TARGET KF6::KIOWidgets)
|
|
||||||
target_compile_definitions(LibNeoChat PUBLIC -DHAVE_KIO)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ecm_add_qml_module(LibNeoChat GENERATE_PLUGIN_SOURCE
|
ecm_add_qml_module(LibNeoChat GENERATE_PLUGIN_SOURCE
|
||||||
URI org.kde.neochat.libneochat
|
URI org.kde.neochat.libneochat
|
||||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/libneochat
|
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/libneochat
|
||||||
@@ -62,8 +57,6 @@ ecm_add_qml_module(LibNeoChat GENERATE_PLUGIN_SOURCE
|
|||||||
qml/SearchPage.qml
|
qml/SearchPage.qml
|
||||||
qml/CreateRoomDialog.qml
|
qml/CreateRoomDialog.qml
|
||||||
qml/CreateSpaceDialog.qml
|
qml/CreateSpaceDialog.qml
|
||||||
DEPENDENCIES
|
|
||||||
com.github.quotient_im.libquotient
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_qt_declare_logging_category(LibNeoChat
|
ecm_qt_declare_logging_category(LibNeoChat
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user