Compare commits
81 Commits
work/redst
...
work/test-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf754711e3 | ||
|
|
32d0f846ee | ||
|
|
b125c284bd | ||
|
|
87213903b1 | ||
|
|
3d9d211d25 | ||
|
|
d5d291396d | ||
|
|
d7cd38b5e5 | ||
|
|
1a25cfc0e3 | ||
|
|
8d9669e033 | ||
|
|
690d2e2b12 | ||
|
|
2208b1b2b3 | ||
|
|
67da272ccd | ||
|
|
171930fb1d | ||
|
|
2bd59fa16f | ||
|
|
d0d0384bdb | ||
|
|
680573de61 | ||
|
|
ba7f866cf5 | ||
|
|
57a95ae972 | ||
|
|
de97275a38 | ||
|
|
d08181f56d | ||
|
|
f6e8491bf1 | ||
|
|
a1447ebd6f | ||
|
|
3b67e4deaf | ||
|
|
e55afd0402 | ||
|
|
7c0710d445 | ||
|
|
61f9cd41f7 | ||
|
|
6c7a7a7be5 | ||
|
|
63125d97c3 | ||
|
|
cb4e7d4943 | ||
|
|
b9d5ed699e | ||
|
|
75fe5c8970 | ||
|
|
91da2d01b7 | ||
|
|
4bade72ce4 | ||
|
|
9c05e2feed | ||
|
|
ba94098411 | ||
|
|
43c691160e | ||
|
|
e2daa091e8 | ||
|
|
f026414b1a | ||
|
|
fd640a4bd0 | ||
|
|
dd433d7f99 | ||
|
|
3183e00acc | ||
|
|
1860de12ea | ||
|
|
277f1ab252 | ||
|
|
324b332fa6 | ||
|
|
33d29f6b02 | ||
|
|
419aed6375 | ||
|
|
7bb26ac3be | ||
|
|
7654333ec1 | ||
|
|
d3a2da391d | ||
|
|
f19f59c37f | ||
|
|
94e53e14a3 | ||
|
|
d2b3788872 | ||
|
|
8095062db2 | ||
|
|
89beaa9316 | ||
|
|
dfaffd043e | ||
|
|
a8c200222f | ||
|
|
598a1c28ac | ||
|
|
b972703f34 | ||
|
|
d30fdc67c6 | ||
|
|
6a5a2e6144 | ||
|
|
235143528c | ||
|
|
33ca2b8d09 | ||
|
|
50176cfafb | ||
|
|
a67fb36a84 | ||
|
|
aea9984187 | ||
|
|
7a6c234b40 | ||
|
|
4cdaa513d3 | ||
|
|
aaf655ea5b | ||
|
|
207c824ec7 | ||
|
|
29abe0bacb | ||
|
|
d14eda2ca0 | ||
|
|
0425cf41d0 | ||
|
|
4ff014f288 | ||
|
|
2e24500866 | ||
|
|
f13a256150 | ||
|
|
c958e8cba9 | ||
|
|
7668da68d3 | ||
|
|
c478a0c0fc | ||
|
|
fe60a08817 | ||
|
|
dec5369a8f | ||
|
|
5ec0b9393e |
@@ -2,7 +2,5 @@
|
|||||||
; SPDX-License-Identifier: CC0-1.0
|
; SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
[BlueprintSettings]
|
[BlueprintSettings]
|
||||||
kde/frameworks/extra-cmake-modules.version=master
|
|
||||||
kde/unreleased/kirigami-addons.version=master
|
|
||||||
kde/applications/neochat.packageAppx=True
|
kde/applications/neochat.packageAppx=True
|
||||||
libs/qt.qtMajorVersion=6
|
libs/qt.qtMajorVersion=6
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"id": "org.kde.neochat",
|
"id": "org.kde.neochat",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"runtime": "org.kde.Platform",
|
"runtime": "org.kde.Platform",
|
||||||
"runtime-version": "6.8",
|
"runtime-version": "6.9",
|
||||||
"sdk": "org.kde.Sdk",
|
"sdk": "org.kde.Sdk",
|
||||||
"command": "neochat",
|
"command": "neochat",
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -149,27 +149,6 @@
|
|||||||
],
|
],
|
||||||
"builddir": true
|
"builddir": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "qcoro",
|
|
||||||
"buildsystem": "cmake-ninja",
|
|
||||||
"config-opts": [
|
|
||||||
"-DQCORO_BUILD_EXAMPLES=OFF",
|
|
||||||
"-DBUILD_TESTING=OFF"
|
|
||||||
],
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "archive",
|
|
||||||
"url": "https://github.com/danvratil/qcoro/archive/refs/tags/v0.11.0.tar.gz",
|
|
||||||
"sha256": "9942c5b4c533192f6c5954dc6d10178b3829075e6a621b67df73f0a4b74d8297",
|
|
||||||
"x-checker-data": {
|
|
||||||
"type": "anitya",
|
|
||||||
"project-id": 236236,
|
|
||||||
"stable-only": true,
|
|
||||||
"url-template": "https://github.com/danvratil/qcoro/archive/refs/tags/v$version.tar.gz"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "kunifiedpush",
|
"name": "kunifiedpush",
|
||||||
"buildsystem": "cmake-ninja",
|
"buildsystem": "cmake-ninja",
|
||||||
|
|||||||
@@ -3,19 +3,20 @@
|
|||||||
|
|
||||||
include:
|
include:
|
||||||
- project: sysadmin/ci-utilities
|
- project: sysadmin/ci-utilities
|
||||||
|
ref: work/switch-vm-ci
|
||||||
file:
|
file:
|
||||||
- /gitlab-templates/reuse-lint.yml
|
#- /gitlab-templates/reuse-lint.yml
|
||||||
- /gitlab-templates/json-validation.yml
|
#- /gitlab-templates/json-validation.yml
|
||||||
- /gitlab-templates/xml-lint.yml
|
#- /gitlab-templates/xml-lint.yml
|
||||||
- /gitlab-templates/yaml-lint.yml
|
#- /gitlab-templates/yaml-lint.yml
|
||||||
- /gitlab-templates/android-qt6.yml
|
#- /gitlab-templates/android-qt6.yml
|
||||||
- /gitlab-templates/linux-qt6.yml
|
- /gitlab-templates/linux-qt6.yml
|
||||||
- /gitlab-templates/linux-qt6-next.yml
|
- /gitlab-templates/linux-qt6-next.yml
|
||||||
- /gitlab-templates/windows-qt6.yml
|
#- /gitlab-templates/windows-qt6.yml
|
||||||
- /gitlab-templates/freebsd-qt6.yml
|
#- /gitlab-templates/freebsd-qt6.yml
|
||||||
- /gitlab-templates/flatpak.yml
|
- /gitlab-templates/flatpak.yml
|
||||||
- /gitlab-templates/snap-snapcraft-lxd.yml
|
- /gitlab-templates/snap-snapcraft-lxd.yml
|
||||||
- /gitlab-templates/craft-android-qt6-apks.yml
|
#- /gitlab-templates/craft-android-qt6-apks.yml
|
||||||
- /gitlab-templates/craft-appimage-qt6.yml
|
#- /gitlab-templates/craft-appimage-qt6.yml
|
||||||
- /gitlab-templates/craft-windows-x86-64-qt6.yml
|
- /gitlab-templates/craft-windows-x86-64-qt6.yml
|
||||||
- /gitlab-templates/craft-windows-appx-qt6.yml
|
- /gitlab-templates/craft-windows-appx-qt6.yml
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.16)
|
|||||||
|
|
||||||
# KDE Applications version, managed by release script.
|
# KDE Applications version, managed by release script.
|
||||||
set(RELEASE_SERVICE_VERSION_MAJOR "25")
|
set(RELEASE_SERVICE_VERSION_MAJOR "25")
|
||||||
set(RELEASE_SERVICE_VERSION_MINOR "07")
|
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
||||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ private Q_SLOTS:
|
|||||||
void receiveRichStrikethrough();
|
void receiveRichStrikethrough();
|
||||||
void receiveRichtextIn();
|
void receiveRichtextIn();
|
||||||
void receiveRichMxcUrl();
|
void receiveRichMxcUrl();
|
||||||
|
void receiveRichPlainUrl_data();
|
||||||
void receiveRichPlainUrl();
|
void receiveRichPlainUrl();
|
||||||
void receiveRichEdited_data();
|
void receiveRichEdited_data();
|
||||||
void receiveRichEdited();
|
void receiveRichEdited();
|
||||||
@@ -450,6 +451,32 @@ void TextHandlerTest::receiveRichMxcUrl()
|
|||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(0).get()), testOutputString);
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(0).get()), testOutputString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextHandlerTest::receiveRichPlainUrl_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("input");
|
||||||
|
QTest::addColumn<QString>("output");
|
||||||
|
|
||||||
|
// This is an actual link that caused trouble which is why it's so long. Keeping
|
||||||
|
// so we can confirm consistent behaviour for complex urls.
|
||||||
|
QTest::addRow("link 1")
|
||||||
|
<< u"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"_s
|
||||||
|
<< u"<a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im</a> <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"_s;
|
||||||
|
|
||||||
|
// Another real case. The linkification wasn't handling it when a single link
|
||||||
|
// contains what looks like and email. It was broken into 3 but needs to
|
||||||
|
// be just single link.
|
||||||
|
QTest::addRow("link 2")
|
||||||
|
<< u"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/"_s
|
||||||
|
<< u"<a href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\">https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>"_s;
|
||||||
|
|
||||||
|
QTest::addRow("email") << uR"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)"_s
|
||||||
|
<< uR"(<a href="mailto:email@example.com">email@example.com</a> <a href="mailto:email@example.com">Link already rich</a>)"_s;
|
||||||
|
QTest::addRow("mxid")
|
||||||
|
<< u"@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>"_s
|
||||||
|
<< u"<b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a></b>"_s;
|
||||||
|
QTest::addRow("mxid with prefix") << u"a @user:kde.org b"_s << u"a <b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> b"_s;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For when your rich input string has a plain text url left in.
|
* For when your rich input string has a plain text url left in.
|
||||||
*
|
*
|
||||||
@@ -458,46 +485,13 @@ void TextHandlerTest::receiveRichMxcUrl()
|
|||||||
*/
|
*/
|
||||||
void TextHandlerTest::receiveRichPlainUrl()
|
void TextHandlerTest::receiveRichPlainUrl()
|
||||||
{
|
{
|
||||||
// This is an actual link that caused trouble which is why it's so long. Keeping
|
QFETCH(QString, input);
|
||||||
// so we can confirm consistent behaviour for complex urls.
|
QFETCH(QString, output);
|
||||||
const QString testInputStringLink1 =
|
|
||||||
u"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"_s;
|
|
||||||
const QString testOutputStringLink1 =
|
|
||||||
u"<a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im</a> <a href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"_s;
|
|
||||||
|
|
||||||
// Another real case. The linkification wasn't handling it when a single link
|
|
||||||
// contains what looks like and email. It was been broken into 3 but needs to
|
|
||||||
// be just single link.
|
|
||||||
const QString testInputStringLink2 = u"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/"_s;
|
|
||||||
const QString testOutputStringLink2 =
|
|
||||||
u"<a href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\">https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>"_s;
|
|
||||||
|
|
||||||
QString testInputStringEmail = uR"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)"_s;
|
|
||||||
QString testOutputStringEmail = uR"(<a href="mailto:email@example.com">email@example.com</a> <a href="mailto:email@example.com">Link already rich</a>)"_s;
|
|
||||||
|
|
||||||
QString testInputStringMxId = u"@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>"_s;
|
|
||||||
QString testOutputStringMxId =
|
|
||||||
u"<b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a></b>"_s;
|
|
||||||
|
|
||||||
QString testInputStringMxIdWithPrefix = u"a @user:kde.org b"_s;
|
|
||||||
QString testOutputStringMxIdWithPrefix = u"a <b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> b"_s;
|
|
||||||
|
|
||||||
TextHandler testTextHandler;
|
TextHandler testTextHandler;
|
||||||
testTextHandler.setData(testInputStringLink1);
|
testTextHandler.setData(input);
|
||||||
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringLink1);
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), output);
|
||||||
|
|
||||||
testTextHandler.setData(testInputStringLink2);
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringLink2);
|
|
||||||
|
|
||||||
testTextHandler.setData(testInputStringEmail);
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringEmail);
|
|
||||||
|
|
||||||
testTextHandler.setData(testInputStringMxId);
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxId);
|
|
||||||
|
|
||||||
testTextHandler.setData(testInputStringMxIdWithPrefix);
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxIdWithPrefix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextHandlerTest::receiveRichEdited_data()
|
void TextHandlerTest::receiveRichEdited_data()
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ void TimelineMessageModelTest::switchEmptyRoom()
|
|||||||
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s);
|
||||||
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s);
|
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s);
|
||||||
|
|
||||||
QSignalSpy spy(model, SIGNAL(roomChanged()));
|
QSignalSpy spy(model, SIGNAL(roomChanged(NeoChatRoom *, NeoChatRoom *)));
|
||||||
|
|
||||||
QCOMPARE(model->room(), nullptr);
|
QCOMPARE(model->room(), nullptr);
|
||||||
model->setRoom(firstRoom);
|
model->setRoom(firstRoom);
|
||||||
@@ -77,7 +77,7 @@ void TimelineMessageModelTest::switchSyncedRoom()
|
|||||||
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
auto firstRoom = new TestUtils::TestRoom(connection, u"#firstRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
||||||
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
auto secondRoom = new TestUtils::TestRoom(connection, u"#secondRoom:kde.org"_s, u"test-messageventmodel-sync.json"_s);
|
||||||
|
|
||||||
QSignalSpy spy(model, SIGNAL(roomChanged()));
|
QSignalSpy spy(model, SIGNAL(roomChanged(NeoChatRoom *, NeoChatRoom *)));
|
||||||
|
|
||||||
QCOMPARE(model->room(), nullptr);
|
QCOMPARE(model->room(), nullptr);
|
||||||
model->setRoom(firstRoom);
|
model->setRoom(firstRoom);
|
||||||
@@ -208,7 +208,7 @@ void TimelineMessageModelTest::idToRow()
|
|||||||
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-min-sync.json"_s);
|
auto room = new TestUtils::TestRoom(connection, u"#myroom:kde.org"_s, u"test-min-sync.json"_s);
|
||||||
model->setRoom(room);
|
model->setRoom(room);
|
||||||
|
|
||||||
QCOMPARE(model->eventIdToRow(u"$153456789:example.org"_s), 0);
|
QCOMPARE(model->indexforEventId(u"$153456789:example.org"_s).row(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineMessageModelTest::cleanup()
|
void TimelineMessageModelTest::cleanup()
|
||||||
|
|||||||
@@ -477,6 +477,8 @@
|
|||||||
<content_attribute id="social-chat">intense</content_attribute>
|
<content_attribute id="social-chat">intense</content_attribute>
|
||||||
</content_rating>
|
</content_rating>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="25.04.3" date="2025-07-03"/>
|
||||||
|
<release version="25.04.2" date="2025-06-05"/>
|
||||||
<release version="25.04.1" date="2025-05-08"/>
|
<release version="25.04.1" date="2025-05-08"/>
|
||||||
<release version="25.04.0" date="2025-04-17"/>
|
<release version="25.04.0" date="2025-04-17"/>
|
||||||
<release version="24.12.3" date="2025-03-06"/>
|
<release version="24.12.3" date="2025-03-06"/>
|
||||||
|
|||||||
1174
po/ar/neochat.po
1174
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
1129
po/ast/neochat.po
1129
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
1174
po/az/neochat.po
1174
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1147
po/ca/neochat.po
1147
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1139
po/cs/neochat.po
1139
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1155
po/da/neochat.po
1155
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1158
po/de/neochat.po
1158
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1166
po/el/neochat.po
1166
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1165
po/en_GB/neochat.po
1165
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1151
po/eo/neochat.po
1151
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
1144
po/es/neochat.po
1144
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1405
po/eu/neochat.po
1405
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1437
po/fi/neochat.po
1437
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1282
po/fr/neochat.po
1282
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1491
po/gl/neochat.po
1491
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
1151
po/he/neochat.po
1151
po/he/neochat.po
File diff suppressed because it is too large
Load Diff
1153
po/hi/neochat.po
1153
po/hi/neochat.po
File diff suppressed because it is too large
Load Diff
1649
po/hu/neochat.po
1649
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1159
po/ia/neochat.po
1159
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1174
po/id/neochat.po
1174
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1151
po/ie/neochat.po
1151
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1150
po/it/neochat.po
1150
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1121
po/ja/neochat.po
1121
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1147
po/ka/neochat.po
1147
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1396
po/ko/neochat.po
1396
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1139
po/lt/neochat.po
1139
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
1522
po/lv/neochat.po
1522
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
1148
po/nl/neochat.po
1148
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
1144
po/nn/neochat.po
1144
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1172
po/pa/neochat.po
1172
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
1173
po/pl/neochat.po
1173
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1170
po/pt/neochat.po
1170
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
1166
po/pt_BR/neochat.po
1166
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
1178
po/ru/neochat.po
1178
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1149
po/sa/neochat.po
1149
po/sa/neochat.po
File diff suppressed because it is too large
Load Diff
1171
po/sk/neochat.po
1171
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
1154
po/sl/neochat.po
1154
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
1148
po/sv/neochat.po
1148
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1161
po/ta/neochat.po
1161
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1164
po/tok/neochat.po
1164
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
1140
po/tr/neochat.po
1140
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
1162
po/uk/neochat.po
1162
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
1112
po/zh_CN/neochat.po
1112
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
1122
po/zh_TW/neochat.po
1122
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ add_subdirectory(libneochat)
|
|||||||
add_subdirectory(login)
|
add_subdirectory(login)
|
||||||
add_subdirectory(rooms)
|
add_subdirectory(rooms)
|
||||||
add_subdirectory(roominfo)
|
add_subdirectory(roominfo)
|
||||||
|
add_subdirectory(messagecontent)
|
||||||
add_subdirectory(timeline)
|
add_subdirectory(timeline)
|
||||||
add_subdirectory(spaces)
|
add_subdirectory(spaces)
|
||||||
add_subdirectory(chatbar)
|
add_subdirectory(chatbar)
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ add_library(neochat STATIC
|
|||||||
windowcontroller.h
|
windowcontroller.h
|
||||||
models/serverlistmodel.cpp
|
models/serverlistmodel.cpp
|
||||||
models/serverlistmodel.h
|
models/serverlistmodel.h
|
||||||
logger.cpp
|
|
||||||
logger.h
|
|
||||||
models/notificationsmodel.cpp
|
models/notificationsmodel.cpp
|
||||||
models/notificationsmodel.h
|
models/notificationsmodel.h
|
||||||
proxycontroller.cpp
|
proxycontroller.cpp
|
||||||
@@ -61,9 +59,7 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
|||||||
qml/RoomPage.qml
|
qml/RoomPage.qml
|
||||||
qml/ManualRoomDialog.qml
|
qml/ManualRoomDialog.qml
|
||||||
qml/ExplorerDelegate.qml
|
qml/ExplorerDelegate.qml
|
||||||
qml/ImageEditorPage.qml
|
|
||||||
qml/NeochatMaximizeComponent.qml
|
qml/NeochatMaximizeComponent.qml
|
||||||
qml/TypingPane.qml
|
|
||||||
qml/QuickSwitcher.qml
|
qml/QuickSwitcher.qml
|
||||||
qml/AttachmentPane.qml
|
qml/AttachmentPane.qml
|
||||||
qml/QuickFormatBar.qml
|
qml/QuickFormatBar.qml
|
||||||
@@ -112,6 +108,7 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
|||||||
org.kde.neochat.libneochat
|
org.kde.neochat.libneochat
|
||||||
org.kde.neochat.rooms
|
org.kde.neochat.rooms
|
||||||
org.kde.neochat.roominfo
|
org.kde.neochat.roominfo
|
||||||
|
org.kde.neochat.messagecontent
|
||||||
org.kde.neochat.timeline
|
org.kde.neochat.timeline
|
||||||
org.kde.neochat.spaces
|
org.kde.neochat.spaces
|
||||||
org.kde.neochat.settings
|
org.kde.neochat.settings
|
||||||
@@ -180,7 +177,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models)
|
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models)
|
||||||
target_link_libraries(neochat PRIVATE Loginplugin Roomsplugin RoomInfoplugin Timelineplugin Spacesplugin Chatbarplugin Settingsplugin Devtoolsplugin)
|
target_link_libraries(neochat PRIVATE Loginplugin Roomsplugin RoomInfoplugin MessageContentplugin Timelineplugin Spacesplugin Chatbarplugin Settingsplugin Devtoolsplugin)
|
||||||
target_link_libraries(neochat PUBLIC
|
target_link_libraries(neochat PUBLIC
|
||||||
LibNeoChat
|
LibNeoChat
|
||||||
Timeline
|
Timeline
|
||||||
@@ -205,6 +202,7 @@ target_link_libraries(neochat PUBLIC
|
|||||||
QuotientQt6
|
QuotientQt6
|
||||||
Login
|
Login
|
||||||
Rooms
|
Rooms
|
||||||
|
MessageContent
|
||||||
Spaces
|
Spaces
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -359,3 +357,10 @@ install(TARGETS neochat-app ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
|||||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||||
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins)
|
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
set_target_properties(neochat-app PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.neochat")
|
||||||
|
set_target_properties(neochat-app PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "NeoChat")
|
||||||
|
set_target_properties(neochat-app PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING ${RELEASE_SERVICE_VERSION})
|
||||||
|
set_target_properties(neochat-app PROPERTIES MACOSX_BUNDLE_BUNDLE_VERSION ${RELEASE_SERVICE_VERSION})
|
||||||
|
endif ()
|
||||||
|
|||||||
@@ -407,4 +407,9 @@ void Controller::markImageShown(const QString &eventId)
|
|||||||
m_shownImages.append(eventId);
|
m_shownImages.append(eventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Controller::markImageHidden(const QString &eventId)
|
||||||
|
{
|
||||||
|
m_shownImages.removeAll(eventId);
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_controller.cpp"
|
#include "moc_controller.cpp"
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE bool isImageShown(const QString &eventId);
|
Q_INVOKABLE bool isImageShown(const QString &eventId);
|
||||||
Q_INVOKABLE void markImageShown(const QString &eventId);
|
Q_INVOKABLE void markImageShown(const QString &eventId);
|
||||||
|
Q_INVOKABLE void markImageHidden(const QString &eventId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Controller(QObject *parent = nullptr);
|
explicit Controller(QObject *parent = nullptr);
|
||||||
|
|||||||
@@ -1,223 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 1997 Matthias Kalle Dalheimer <kalle@kde.org>
|
|
||||||
// SPDX-FileCopyrightText: 2002 Holger Freyther <freyther@kde.org>
|
|
||||||
// SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org>
|
|
||||||
// SPDX-FileCopyrightText: 2023 Tobias Fella <fella@posteo.de>
|
|
||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QStandardPaths>
|
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
|
||||||
|
|
||||||
static QLoggingCategory::CategoryFilter oldCategoryFilter = nullptr;
|
|
||||||
static QtMessageHandler oldHandler = nullptr;
|
|
||||||
static bool e2eeDebugEnabled = false;
|
|
||||||
|
|
||||||
class FileDebugStream : public QIODevice
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
FileDebugStream()
|
|
||||||
: mType(QtCriticalMsg)
|
|
||||||
{
|
|
||||||
open(WriteOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSequential() const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
qint64 readData(char *, qint64) override
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
qint64 readLineData(char *, qint64) override
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 writeData(const char *data, qint64 len) override
|
|
||||||
{
|
|
||||||
if (!mFileName.isEmpty()) {
|
|
||||||
QFile outputFile(mFileName);
|
|
||||||
outputFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered);
|
|
||||||
outputFile.write(data, len);
|
|
||||||
outputFile.putChar('\n');
|
|
||||||
outputFile.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFileName(const QString &fileName)
|
|
||||||
{
|
|
||||||
mFileName = fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setType(QtMsgType type)
|
|
||||||
{
|
|
||||||
mType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString mFileName;
|
|
||||||
QtMsgType mType;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DebugPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DebugPrivate()
|
|
||||||
: origHandler(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~DebugPrivate()
|
|
||||||
{
|
|
||||||
qInstallMessageHandler(origHandler);
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void log(QtMsgType type, const QMessageLogContext &context, const QString &message)
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&mutex);
|
|
||||||
QByteArray buf;
|
|
||||||
QTextStream str(&buf);
|
|
||||||
str << QDateTime::currentDateTime().toString(Qt::ISODate) << u" ["_s;
|
|
||||||
switch (type) {
|
|
||||||
case QtDebugMsg:
|
|
||||||
str << u"DEBUG"_s;
|
|
||||||
break;
|
|
||||||
case QtInfoMsg:
|
|
||||||
str << u"INFO "_s;
|
|
||||||
break;
|
|
||||||
case QtWarningMsg:
|
|
||||||
str << u"WARN "_s;
|
|
||||||
break;
|
|
||||||
case QtFatalMsg:
|
|
||||||
str << u"FATAL"_s;
|
|
||||||
break;
|
|
||||||
case QtCriticalMsg:
|
|
||||||
str << u"CRITICAL"_s;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str << u"] "_s << context.category << u": "_s;
|
|
||||||
if (context.file && *context.file && context.line) {
|
|
||||||
str << context.file << u":"_s << context.line << u": "_s;
|
|
||||||
}
|
|
||||||
if (context.function && *context.function) {
|
|
||||||
str << context.function << u": "_s;
|
|
||||||
}
|
|
||||||
str << message << u"\n"_s;
|
|
||||||
str.flush();
|
|
||||||
file.write(buf.constData(), buf.size());
|
|
||||||
file.flush();
|
|
||||||
|
|
||||||
if (oldHandler && (!context.category || (strcmp(context.category, "quotient.e2ee") != 0 || e2eeDebugEnabled))) {
|
|
||||||
oldHandler(type, context, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setName(const QString &appName)
|
|
||||||
{
|
|
||||||
name = appName;
|
|
||||||
|
|
||||||
if (file.isOpen()) {
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
const auto &filePath = u"%1%2%3"_s.arg(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), QDir::separator(), appName);
|
|
||||||
|
|
||||||
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QDir::separator());
|
|
||||||
auto entryList = dir.entryList({appName + u".*"_s});
|
|
||||||
std::sort(entryList.begin(), entryList.end(), [](const auto &left, const auto &right) {
|
|
||||||
auto leftIndex = left.split(u"."_s).last().toInt();
|
|
||||||
auto rightIndex = right.split(u"."_s).last().toInt();
|
|
||||||
return leftIndex > rightIndex;
|
|
||||||
});
|
|
||||||
for (const auto &entry : entryList) {
|
|
||||||
bool ok = false;
|
|
||||||
const auto index = entry.split(u"."_s).last().toInt(&ok);
|
|
||||||
if (!ok) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
QFileInfo info(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QDir::separator() + entry);
|
|
||||||
if (info.exists()) {
|
|
||||||
QFile file(info.absoluteFilePath());
|
|
||||||
if (index > 50) {
|
|
||||||
file.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto &newName = u"%1.%2"_s.arg(filePath, QString::number(index + 1));
|
|
||||||
const auto success = file.copy(newName);
|
|
||||||
if (success) {
|
|
||||||
file.remove();
|
|
||||||
} else {
|
|
||||||
qFatal("Cannot rename log file '%s' to '%s': %s",
|
|
||||||
qUtf8Printable(file.fileName()),
|
|
||||||
qUtf8Printable(newName),
|
|
||||||
qUtf8Printable(file.errorString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileInfo finfo(filePath);
|
|
||||||
if (!finfo.absoluteDir().exists()) {
|
|
||||||
QDir().mkpath(finfo.absolutePath());
|
|
||||||
}
|
|
||||||
file.setFileName(filePath + u".0"_s);
|
|
||||||
file.open(QIODevice::WriteOnly | QIODevice::Unbuffered);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOrigHandler(QtMessageHandler origHandler_)
|
|
||||||
{
|
|
||||||
origHandler = origHandler_;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMutex mutex;
|
|
||||||
QFile file;
|
|
||||||
QString name;
|
|
||||||
QtMessageHandler origHandler;
|
|
||||||
QByteArray loggingCategory;
|
|
||||||
};
|
|
||||||
|
|
||||||
Q_GLOBAL_STATIC(DebugPrivate, sInstance)
|
|
||||||
|
|
||||||
void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case QtDebugMsg:
|
|
||||||
case QtInfoMsg:
|
|
||||||
case QtWarningMsg:
|
|
||||||
case QtCriticalMsg:
|
|
||||||
sInstance()->log(type, context, message);
|
|
||||||
break;
|
|
||||||
case QtFatalMsg:
|
|
||||||
sInstance()->log(QtInfoMsg, context, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter(QLoggingCategory *category)
|
|
||||||
{
|
|
||||||
if (qstrcmp(category->categoryName(), "quotient.e2ee") == 0) {
|
|
||||||
category->setEnabled(QtDebugMsg, true);
|
|
||||||
} else if (oldCategoryFilter) {
|
|
||||||
oldCategoryFilter(category);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void initLogging()
|
|
||||||
{
|
|
||||||
e2eeDebugEnabled = QLoggingCategory("quotient.e2ee", QtInfoMsg).isEnabled(QtDebugMsg);
|
|
||||||
oldCategoryFilter = QLoggingCategory::installFilter(filter);
|
|
||||||
oldHandler = qInstallMessageHandler(messageHandler);
|
|
||||||
sInstance->setOrigHandler(oldHandler);
|
|
||||||
sInstance->setName(u"neochat.log"_s);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "logger.moc"
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initlalize logging to file and enables some additional categories, which will only be logged to the file
|
|
||||||
*/
|
|
||||||
void initLogging();
|
|
||||||
@@ -49,7 +49,6 @@
|
|||||||
#include "blurhashimageprovider.h"
|
#include "blurhashimageprovider.h"
|
||||||
#include "colorschemer.h"
|
#include "colorschemer.h"
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "logger.h"
|
|
||||||
#include "login.h"
|
#include "login.h"
|
||||||
#include "registration.h"
|
#include "registration.h"
|
||||||
#include "roommanager.h"
|
#include "roommanager.h"
|
||||||
@@ -138,6 +137,11 @@ int main(int argc, char *argv[])
|
|||||||
font.setHintingPreference(QFont::PreferNoHinting);
|
font.setHintingPreference(QFont::PreferNoHinting);
|
||||||
app.setFont(font);
|
app.setFont(font);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
QApplication::setStyle(u"breeze"_s);
|
||||||
|
#endif
|
||||||
|
|
||||||
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat"));
|
||||||
|
|
||||||
QGuiApplication::setOrganizationName("KDE"_L1);
|
QGuiApplication::setOrganizationName("KDE"_L1);
|
||||||
@@ -177,8 +181,6 @@ int main(int argc, char *argv[])
|
|||||||
KCrash::initialize();
|
KCrash::initialize();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
initLogging();
|
|
||||||
|
|
||||||
Connection::setEncryptionDefault(true);
|
Connection::setEncryptionDefault(true);
|
||||||
Connection::setDirectChatEncryptionDefault(true);
|
Connection::setDirectChatEncryptionDefault(true);
|
||||||
|
|
||||||
@@ -195,6 +197,9 @@ int main(int argc, char *argv[])
|
|||||||
parser.addPositionalArgument(u"urls"_s, i18n("Supports matrix: url scheme"));
|
parser.addPositionalArgument(u"urls"_s, i18n("Supports matrix: url scheme"));
|
||||||
parser.addOption(QCommandLineOption("ignore-ssl-errors"_L1, i18n("Ignore all SSL Errors, e.g., unsigned certificates.")));
|
parser.addOption(QCommandLineOption("ignore-ssl-errors"_L1, i18n("Ignore all SSL Errors, e.g., unsigned certificates.")));
|
||||||
|
|
||||||
|
QCommandLineOption replaceOption({QStringLiteral("replace")}, i18nc("command line description", "Replace an existing instance"));
|
||||||
|
parser.addOption(replaceOption);
|
||||||
|
|
||||||
QCommandLineOption testOption("test"_L1, i18n("Only used for autotests"));
|
QCommandLineOption testOption("test"_L1, i18n("Only used for autotests"));
|
||||||
testOption.setFlags(QCommandLineOption::HiddenFromHelp);
|
testOption.setFlags(QCommandLineOption::HiddenFromHelp);
|
||||||
parser.addOption(testOption);
|
parser.addOption(testOption);
|
||||||
@@ -231,7 +236,7 @@ int main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_KDBUSADDONS
|
#ifdef HAVE_KDBUSADDONS
|
||||||
KDBusService service(KDBusService::Unique);
|
KDBusService service(KDBusService::Unique | (parser.isSet(replaceOption) ? KDBusService::Replace : KDBusService::StartupOption(0)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const auto accountManager = std::make_unique<AccountManager>(parser.isSet("test"_L1));
|
const auto accountManager = std::make_unique<AccountManager>(parser.isSet("test"_L1));
|
||||||
@@ -239,13 +244,6 @@ int main(int argc, char *argv[])
|
|||||||
LoginHelper::instance().setAccountManager(accountManager.get());
|
LoginHelper::instance().setAccountManager(accountManager.get());
|
||||||
Registration::instance().setAccountManager(accountManager.get());
|
Registration::instance().setAccountManager(accountManager.get());
|
||||||
|
|
||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_settingsPlugin)
|
|
||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_roomsPlugin)
|
|
||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_timelinePlugin)
|
|
||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_devtoolsPlugin)
|
|
||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_loginPlugin)
|
|
||||||
Q_IMPORT_QML_PLUGIN(org_kde_neochat_chatbarPlugin)
|
|
||||||
|
|
||||||
qml_register_types_org_kde_neochat();
|
qml_register_types_org_kde_neochat();
|
||||||
qmlRegisterUncreatableMetaObject(Quotient::staticMetaObject, "Quotient", 1, 0, "JoinRule", u"Access to JoinRule enum only"_s);
|
qmlRegisterUncreatableMetaObject(Quotient::staticMetaObject, "Quotient", 1, 0, "JoinRule", u"Access to JoinRule enum only"_s);
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,12 @@
|
|||||||
<label>Use a compact room list layout</label>
|
<label>Use a compact room list layout</label>
|
||||||
<default>false</default>
|
<default>false</default>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="MarkReadCondition" type="Enum">
|
||||||
|
<label>The sort order for the rooms in the list.</label>
|
||||||
|
<choices name="::TimelineMarkReadCondition::Condition">
|
||||||
|
</choices>
|
||||||
|
<default>2</default>
|
||||||
|
</entry>
|
||||||
<entry name="ShowStateEvent" type="bool">
|
<entry name="ShowStateEvent" type="bool">
|
||||||
<label>Show state events in the timeline</label>
|
<label>Show state events in the timeline</label>
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
@@ -205,6 +211,10 @@
|
|||||||
<label>Enable add phone numbers as 3PIDs</label>
|
<label>Enable add phone numbers as 3PIDs</label>
|
||||||
<default>false</default>
|
<default>false</default>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="Calls" type="bool">
|
||||||
|
<label>Enable audio and video calling</label>
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
</group>
|
</group>
|
||||||
<group name="Security">
|
<group name="Security">
|
||||||
<entry name="RejectUnknownInvites" type="bool">
|
<entry name="RejectUnknownInvites" type="bool">
|
||||||
|
|||||||
@@ -36,14 +36,18 @@ KirigamiComponents.ConvergentContextMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kirigami.Action {
|
||||||
|
text: i18nc("@action:inmenu", "Switch Account")
|
||||||
|
icon.name: "system-switch-user"
|
||||||
|
shortcut: "Ctrl+U"
|
||||||
|
onTriggered: accountSwitchDialog.createObject(QQC2.Overlay.overlay, {
|
||||||
|
connection: root.connection
|
||||||
|
}).open();
|
||||||
|
}
|
||||||
QQC2.Action {
|
QQC2.Action {
|
||||||
text: i18n("Edit This Account")
|
text: i18n("Edit This Account")
|
||||||
icon.name: "document-edit"
|
icon.name: "document-edit"
|
||||||
onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.settings', 'AccountEditorPage'), {
|
onTriggered: NeoChatSettingsView.openWithInitialProperties("accounts", {initialAccount: root.connection});
|
||||||
connection: root.connection
|
|
||||||
}, {
|
|
||||||
title: i18n("Account editor")
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QQC2.Action {
|
QQC2.Action {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ ColumnLayout {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property NeoChatRoom currentRoom
|
required property NeoChatRoom currentRoom
|
||||||
readonly property var invitingMember: currentRoom.member(currentRoom.invitingUserId)
|
readonly property var invitingMember: currentRoom.qmlSafeMember(currentRoom.invitingUserId)
|
||||||
readonly property string inviteTimestamp: root.currentRoom.inviteTimestamp.toLocaleString(Qt.locale(), Locale.ShortFormat)
|
readonly property string inviteTimestamp: root.currentRoom.inviteTimestamp.toLocaleString(Qt.locale(), Locale.ShortFormat)
|
||||||
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
@@ -33,7 +33,7 @@ ColumnLayout {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
name: root.invitingMember.displayName
|
name: root.invitingMember.displayName
|
||||||
source: root.invitingMember.avatarUrl
|
source: NeoChatConfig.hideImages ? undefined : root.invitingMember.avatarUrl
|
||||||
color: root.invitingMember.color
|
color: root.invitingMember.color
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ Kirigami.ApplicationWindow {
|
|||||||
showExisting: true
|
showExisting: true
|
||||||
onConnectionChosen: root.load()
|
onConnectionChosen: root.load()
|
||||||
}
|
}
|
||||||
|
columnView.columnResizeMode: pageStack.wideMode ? Kirigami.ColumnView.DynamicColumns : Kirigami.ColumnView.SingleColumn
|
||||||
globalToolBar.canContainHandles: true
|
globalToolBar.canContainHandles: true
|
||||||
globalToolBar {
|
globalToolBar {
|
||||||
style: Kirigami.ApplicationHeaderStyle.ToolBar
|
style: Kirigami.ApplicationHeaderStyle.ToolBar
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ Components.AlbumMaximizeComponent {
|
|||||||
id: saveAsDialog
|
id: saveAsDialog
|
||||||
Dialogs.FileDialog {
|
Dialogs.FileDialog {
|
||||||
fileMode: Dialogs.FileDialog.SaveFile
|
fileMode: Dialogs.FileDialog.SaveFile
|
||||||
currentFolder: root.saveFolder
|
currentFolder: NeoChatConfig.lastSaveDirectory.length > 0 ? NeoChatConfig.lastSaveDirectory : Core.StandardPaths.writableLocation(Core.StandardPaths.DownloadLocation)
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
NeoChatConfig.lastSaveDirectory = currentFolder;
|
NeoChatConfig.lastSaveDirectory = currentFolder;
|
||||||
NeoChatConfig.save();
|
NeoChatConfig.save();
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ Kirigami.Page {
|
|||||||
placeholderText: root.placeholder
|
placeholderText: root.placeholder
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
wrapMode: TextEdit.Wrap
|
wrapMode: TextEdit.Wrap
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
Keys.onReturnPressed: event => {
|
||||||
|
if (event.modifiers & Qt.ControlModifier) {
|
||||||
|
root.accepted(reason.text);
|
||||||
|
root.closeDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: Kirigami.Theme.backgroundColor
|
color: Kirigami.Theme.backgroundColor
|
||||||
@@ -50,6 +58,7 @@ Kirigami.Page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
QQC2.Button {
|
QQC2.Button {
|
||||||
|
icon.name: "dialog-cancel-symbolic"
|
||||||
text: i18nc("@action", "Cancel")
|
text: i18nc("@action", "Cancel")
|
||||||
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
|
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
|
||||||
onClicked: root.closeDialog()
|
onClicked: root.closeDialog()
|
||||||
|
|||||||
@@ -11,15 +11,14 @@ import org.kde.kirigami as Kirigami
|
|||||||
import org.kde.kitemmodels
|
import org.kde.kitemmodels
|
||||||
|
|
||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
import org.kde.neochat.chatbar
|
|
||||||
|
|
||||||
Kirigami.Page {
|
Kirigami.Page {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
/// Not readonly because of the separate window view.
|
/**
|
||||||
property NeoChatRoom currentRoom: RoomManager.currentRoom
|
* @brief The NeoChatRoom the delegate is being displayed in.
|
||||||
|
*/
|
||||||
required property NeoChatConnection connection
|
readonly property NeoChatRoom currentRoom: RoomManager.currentRoom
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The TimelineModel to use.
|
* @brief The TimelineModel to use.
|
||||||
@@ -59,11 +58,6 @@ Kirigami.Page {
|
|||||||
*/
|
*/
|
||||||
property MediaMessageFilterModel mediaMessageFilterModel: RoomManager.mediaMessageFilterModel
|
property MediaMessageFilterModel mediaMessageFilterModel: RoomManager.mediaMessageFilterModel
|
||||||
|
|
||||||
property bool loading: !root.currentRoom || (root.currentRoom.timelineSize === 0 && !root.currentRoom.allHistoryLoaded)
|
|
||||||
|
|
||||||
/// Disable cancel shortcut. Used by the separate window since it provides its own cancel implementation.
|
|
||||||
property bool disableCancelShortcut: false
|
|
||||||
|
|
||||||
title: root.currentRoom ? root.currentRoom.displayName : ""
|
title: root.currentRoom ? root.currentRoom.displayName : ""
|
||||||
focus: true
|
focus: true
|
||||||
padding: 0
|
padding: 0
|
||||||
@@ -86,9 +80,9 @@ Kirigami.Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.connection
|
target: root.currentRoom.connection
|
||||||
function onIsOnlineChanged() {
|
function onIsOnlineChanged() {
|
||||||
if (!root.connection.isOnline) {
|
if (!root.currentRoom.connection.isOnline) {
|
||||||
banner.text = i18n("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;
|
||||||
@@ -109,18 +103,15 @@ Kirigami.Page {
|
|||||||
Loader {
|
Loader {
|
||||||
id: timelineViewLoader
|
id: timelineViewLoader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
active: root.currentRoom && !root.currentRoom.isInvite && !root.loading && !root.currentRoom.isSpace
|
active: root.currentRoom && !root.currentRoom.isInvite && !root.currentRoom.isSpace
|
||||||
|
// We need the loader to be active but invisible while the room is loading messages so signals in TimelineView work.
|
||||||
|
visible: !root.loading
|
||||||
sourceComponent: TimelineView {
|
sourceComponent: TimelineView {
|
||||||
id: timelineView
|
id: timelineView
|
||||||
currentRoom: root.currentRoom
|
|
||||||
page: root
|
|
||||||
timelineModel: root.timelineModel
|
|
||||||
messageFilterModel: root.messageFilterModel
|
messageFilterModel: root.messageFilterModel
|
||||||
onFocusChatBar: {
|
compactLayout: NeoChatConfig.compactLayout
|
||||||
if (chatBarLoader.item) {
|
fileDropEnabled: !Controller.isFlatpak
|
||||||
chatBarLoader.item.forceActiveFocus();
|
markReadCondition: NeoChatConfig.markReadCondition
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,14 +143,6 @@ Kirigami.Page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
|
||||||
active: root.loading && !invitationLoader.active && RoomManager.currentRoom && !spaceLoader.active
|
|
||||||
anchors.centerIn: parent
|
|
||||||
sourceComponent: Kirigami.LoadingPlaceholder {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||||
Kirigami.Theme.inherit: false
|
Kirigami.Theme.inherit: false
|
||||||
@@ -174,12 +157,7 @@ Kirigami.Page {
|
|||||||
id: chatBar
|
id: chatBar
|
||||||
width: parent.width
|
width: parent.width
|
||||||
currentRoom: root.currentRoom
|
currentRoom: root.currentRoom
|
||||||
connection: root.connection
|
connection: root.currentRoom.connection
|
||||||
onMessageSent: {
|
|
||||||
if (!timelineViewLoader.item.atYEnd) {
|
|
||||||
timelineViewLoader.item.goToLastMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,21 +174,8 @@ Kirigami.Page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
|
||||||
sequence: StandardKey.Cancel
|
|
||||||
onActivated: {
|
|
||||||
if (!timelineViewLoader.item.atYEnd || !root.currentRoom.partiallyReadStats.empty()) {
|
|
||||||
timelineViewLoader.item.goToLastMessage();
|
|
||||||
root.currentRoom.markAllMessagesAsRead();
|
|
||||||
} else {
|
|
||||||
applicationWindow().pageStack.get(0).forceActiveFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enabled: !root.disableCancelShortcut
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.connection
|
target: root.currentRoom.connection
|
||||||
function onJoinedRoom(room, invited) {
|
function onJoinedRoom(room, invited) {
|
||||||
if (root.currentRoom.id === invited.id) {
|
if (root.currentRoom.id === invited.id) {
|
||||||
RoomManager.resolveResource(room.id);
|
RoomManager.resolveResource(room.id);
|
||||||
@@ -296,7 +261,7 @@ Kirigami.Page {
|
|||||||
id: messageDelegateContextMenu
|
id: messageDelegateContextMenu
|
||||||
MessageDelegateContextMenu {
|
MessageDelegateContextMenu {
|
||||||
room: root.currentRoom
|
room: root.currentRoom
|
||||||
connection: root.connection
|
connection: root.currentRoom.connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +269,7 @@ Kirigami.Page {
|
|||||||
id: fileDelegateContextMenu
|
id: fileDelegateContextMenu
|
||||||
FileDelegateContextMenu {
|
FileDelegateContextMenu {
|
||||||
room: root.currentRoom
|
room: root.currentRoom
|
||||||
connection: root.connection
|
connection: root.currentRoom.connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ Kirigami.Dialog {
|
|||||||
text: root.user.id
|
text: root.user.id
|
||||||
elide: Qt.ElideRight
|
elide: Qt.ElideRight
|
||||||
elideWidth: root.availableWidth - avatar.width - qrButton.width - detailRow.spacing * 2 - detailRow.Layout.leftMargin - detailRow.Layout.rightMargin
|
elideWidth: root.availableWidth - avatar.width - qrButton.width - detailRow.spacing * 2 - detailRow.Layout.leftMargin - detailRow.Layout.rightMargin
|
||||||
onElideWidthChanged: console.warn(root.availableWidth, avatar.width, qrButton.width, elideWidth, elidedText)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ RoomManager::RoomManager(QObject *parent)
|
|||||||
m_directChatsConfig = m_config->group(u"DirectChatsActive"_s);
|
m_directChatsConfig = m_config->group(u"DirectChatsActive"_s);
|
||||||
|
|
||||||
connect(this, &RoomManager::currentRoomChanged, this, [this]() {
|
connect(this, &RoomManager::currentRoomChanged, this, [this]() {
|
||||||
|
m_userListModel->setRoom(m_currentRoom);
|
||||||
m_timelineModel->setRoom(m_currentRoom);
|
m_timelineModel->setRoom(m_currentRoom);
|
||||||
m_sortFilterRoomTreeModel->setCurrentRoom(m_currentRoom);
|
m_sortFilterRoomTreeModel->setCurrentRoom(m_currentRoom);
|
||||||
m_userListModel->setRoom(m_currentRoom);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, [this](NeoChatConnection *connection) {
|
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, [this](NeoChatConnection *connection) {
|
||||||
@@ -96,6 +96,7 @@ RoomManager::RoomManager(QObject *parent)
|
|||||||
m_messageFilterModel->invalidate();
|
m_messageFilterModel->invalidate();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
connect(m_timelineModel->timelineMessageModel(), &MessageModel::modelResetComplete, this, &RoomManager::activateUserModel);
|
||||||
MessageFilterModel::setShowAllEvents(NeoChatConfig::self()->showAllEvents());
|
MessageFilterModel::setShowAllEvents(NeoChatConfig::self()->showAllEvents());
|
||||||
connect(NeoChatConfig::self(), &NeoChatConfig::ShowAllEventsChanged, this, [this] {
|
connect(NeoChatConfig::self(), &NeoChatConfig::ShowAllEventsChanged, this, [this] {
|
||||||
MessageFilterModel::setShowAllEvents(NeoChatConfig::self()->showAllEvents());
|
MessageFilterModel::setShowAllEvents(NeoChatConfig::self()->showAllEvents());
|
||||||
|
|||||||
@@ -15,4 +15,5 @@ ecm_add_qml_module(Chatbar GENERATE_PLUGIN_SOURCE
|
|||||||
EmojiPicker.qml
|
EmojiPicker.qml
|
||||||
EmojiDialog.qml
|
EmojiDialog.qml
|
||||||
EmojiTonesPicker.qml
|
EmojiTonesPicker.qml
|
||||||
|
ImageEditorPage.qml
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -160,11 +160,6 @@ QQC2.Control {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A message has been sent from the chat bar.
|
|
||||||
*/
|
|
||||||
signal messageSent
|
|
||||||
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||||
@@ -436,7 +431,6 @@ QQC2.Control {
|
|||||||
repeatTimer.stop();
|
repeatTimer.stop();
|
||||||
root.currentRoom.markAllMessagesAsRead();
|
root.currentRoom.markAllMessagesAsRead();
|
||||||
textField.clear();
|
textField.clear();
|
||||||
messageSent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatText(format, selectionStart, selectionEnd) {
|
function formatText(format, selectionStart, selectionEnd) {
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ ColumnLayout {
|
|||||||
padding: Kirigami.Units.largeSpacing
|
padding: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
contentItem: Image {
|
contentItem: Image {
|
||||||
source: model.avatarUrl
|
source: model.url
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
sourceSize.width: width
|
sourceSize.width: width
|
||||||
sourceSize.height: height
|
sourceSize.height: height
|
||||||
|
|||||||
@@ -36,4 +36,13 @@ FormCard.FormCard {
|
|||||||
NeoChatConfig.save();
|
NeoChatConfig.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FormCard.FormCheckDelegate {
|
||||||
|
text: i18nc("@option:check Enable the matrix feature for audio and video calling", "Calls")
|
||||||
|
checked: NeoChatConfig.calls
|
||||||
|
|
||||||
|
onToggled: {
|
||||||
|
NeoChatConfig.calls = checked;
|
||||||
|
NeoChatConfig.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ target_sources(LibNeoChat PRIVATE
|
|||||||
enums/pushrule.h
|
enums/pushrule.h
|
||||||
enums/roomsortparameter.cpp
|
enums/roomsortparameter.cpp
|
||||||
enums/roomsortorder.h
|
enums/roomsortorder.h
|
||||||
|
enums/timelinemarkreadcondition.h
|
||||||
events/imagepackevent.cpp
|
events/imagepackevent.cpp
|
||||||
events/pollevent.cpp
|
events/pollevent.cpp
|
||||||
jobs/neochatgetcommonroomsjob.cpp
|
jobs/neochatgetcommonroomsjob.cpp
|
||||||
|
|||||||
32
src/libneochat/enums/timelinemarkreadcondition.h
Normal file
32
src/libneochat/enums/timelinemarkreadcondition.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class TimelineMarkReadCondition
|
||||||
|
*
|
||||||
|
* This class is designed to define the TimelineMarkReadCondition enumeration.
|
||||||
|
*/
|
||||||
|
class TimelineMarkReadCondition : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_UNCREATABLE("")
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief The condition for marking messages as read.
|
||||||
|
*/
|
||||||
|
enum Condition {
|
||||||
|
Never = 0, /**< Messages should never be marked automatically. */
|
||||||
|
Entry, /**< Messages should be marked automatically on entry to the room. */
|
||||||
|
EntryVisible, /**< Messages should be marked automatically on entry to the room if all messages are visible. */
|
||||||
|
Exit, /**< Messages should be marked automatically on exiting the room. */
|
||||||
|
ExitVisible, /**< Messages should be marked automatically on exiting the room if all messages are visible. */
|
||||||
|
};
|
||||||
|
Q_ENUM(Condition);
|
||||||
|
};
|
||||||
@@ -435,6 +435,13 @@ QString EventHandler::getBody(const NeoChatRoom *room, const Quotient::RoomEvent
|
|||||||
return i18nc("[User] configured <name> widget", "configured %1 widget", e.contentJson()["name"_L1].toString());
|
return i18nc("[User] configured <name> widget", "configured %1 widget", e.contentJson()["name"_L1].toString());
|
||||||
},
|
},
|
||||||
[prettyPrint](const StateEvent &e) {
|
[prettyPrint](const StateEvent &e) {
|
||||||
|
if (e.matrixType() == "org.matrix.msc3401.call.member"_L1) {
|
||||||
|
if (e.contentJson().isEmpty()) {
|
||||||
|
return i18nc("[User] left a [voice/video] call", "left a call");
|
||||||
|
} else {
|
||||||
|
return i18nc("[User] joined a [voice/video] call", "joined a call");
|
||||||
|
}
|
||||||
|
}
|
||||||
return e.stateKey().isEmpty() ? i18n("updated %1 state", e.matrixType())
|
return e.stateKey().isEmpty() ? i18n("updated %1 state", e.matrixType())
|
||||||
: i18n("updated %1 state for %2", e.matrixType(), prettyPrint ? e.stateKey().toHtmlEscaped() : e.stateKey());
|
: i18n("updated %1 state for %2", e.matrixType(), prettyPrint ? e.stateKey().toHtmlEscaped() : e.stateKey());
|
||||||
},
|
},
|
||||||
@@ -634,7 +641,14 @@ QString EventHandler::genericBody(const NeoChatRoom *room, const Quotient::RoomE
|
|||||||
}
|
}
|
||||||
return i18n("%1 configured a widget", senderString);
|
return i18n("%1 configured a widget", senderString);
|
||||||
},
|
},
|
||||||
[senderString](const StateEvent &) {
|
[senderString](const StateEvent &e) {
|
||||||
|
if (e.matrixType() == "org.matrix.msc3401.call.member"_L1) {
|
||||||
|
if (e.contentJson().isEmpty()) {
|
||||||
|
return i18nc("[User] left a [voice/video] call", "%1 left a call", senderString);
|
||||||
|
} else {
|
||||||
|
return i18nc("[User] joined a [voice/video] call", "%1 joined a call", senderString);
|
||||||
|
}
|
||||||
|
}
|
||||||
return i18n("%1 updated the state", senderString);
|
return i18n("%1 updated the state", senderString);
|
||||||
},
|
},
|
||||||
[senderString](const PollStartEvent &) {
|
[senderString](const PollStartEvent &) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ struct MessageComponent {
|
|||||||
QString content;
|
QString content;
|
||||||
QVariantMap attributes;
|
QVariantMap attributes;
|
||||||
|
|
||||||
int operator==(const MessageComponent &right) const
|
bool operator==(const MessageComponent &right) const
|
||||||
{
|
{
|
||||||
return type == right.type && content == right.content && attributes == right.attributes;
|
return type == right.type && content == right.content && attributes == right.attributes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1214,34 +1214,38 @@ QByteArray NeoChatRoom::getEventJsonSource(const QString &eventId)
|
|||||||
void NeoChatRoom::openEventMediaExternally(const QString &eventId)
|
void NeoChatRoom::openEventMediaExternally(const QString &eventId)
|
||||||
{
|
{
|
||||||
const auto evtIt = findInTimeline(eventId);
|
const auto evtIt = findInTimeline(eventId);
|
||||||
if (evtIt != messageEvents().rend() && is<RoomMessageEvent>(**evtIt)) {
|
if (evtIt == messageEvents().rend()) {
|
||||||
const auto event = evtIt->viewAs<RoomMessageEvent>();
|
return;
|
||||||
if (event->has<EventContent::FileContent>()) {
|
}
|
||||||
const auto transferInfo = cachedFileTransferInfo(event);
|
|
||||||
if (transferInfo.completed()) {
|
// TODO: Also allow stickers here, once that's fixed in libQuotient
|
||||||
|
if (!is<RoomMessageEvent>(**evtIt) || !evtIt->viewAs<RoomMessageEvent>()->has<EventContent::FileContentBase>()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto transferInfo = cachedFileTransferInfo(evtIt->viewAs<RoomEvent>());
|
||||||
|
if (transferInfo.completed()) {
|
||||||
|
UrlHelper helper;
|
||||||
|
helper.openUrl(transferInfo.localPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downloadFile(eventId,
|
||||||
|
QUrl(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + u'/'
|
||||||
|
+ evtIt->event()->id().replace(u':', u'_').replace(u'/', u'_').replace(u'+', u'_') + fileNameToDownload(eventId)));
|
||||||
|
connect(
|
||||||
|
this,
|
||||||
|
&Room::fileTransferCompleted,
|
||||||
|
this,
|
||||||
|
[this, eventId](QString id, QUrl localFile, FileSourceInfo fileMetadata) {
|
||||||
|
Q_UNUSED(localFile);
|
||||||
|
Q_UNUSED(fileMetadata);
|
||||||
|
if (id == eventId) {
|
||||||
|
auto transferInfo = fileTransferInfo(eventId);
|
||||||
UrlHelper helper;
|
UrlHelper helper;
|
||||||
helper.openUrl(transferInfo.localPath);
|
helper.openUrl(transferInfo.localPath);
|
||||||
} else {
|
|
||||||
downloadFile(eventId,
|
|
||||||
QUrl(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + u'/'
|
|
||||||
+ event->id().replace(u':', u'_').replace(u'/', u'_').replace(u'+', u'_') + fileNameToDownload(eventId)));
|
|
||||||
connect(
|
|
||||||
this,
|
|
||||||
&Room::fileTransferCompleted,
|
|
||||||
this,
|
|
||||||
[this, eventId](QString id, QUrl localFile, FileSourceInfo fileMetadata) {
|
|
||||||
Q_UNUSED(localFile);
|
|
||||||
Q_UNUSED(fileMetadata);
|
|
||||||
if (id == eventId) {
|
|
||||||
auto transferInfo = fileTransferInfo(eventId);
|
|
||||||
UrlHelper helper;
|
|
||||||
helper.openUrl(transferInfo.localPath);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NeoChatRoom::copyEventMedia(const QString &eventId)
|
void NeoChatRoom::copyEventMedia(const QString &eventId)
|
||||||
|
|||||||
@@ -557,7 +557,7 @@ public:
|
|||||||
* responsibility of the caller to ensure that they only ask for objects
|
* responsibility of the caller to ensure that they only ask for objects
|
||||||
* for real senders.
|
* for real senders.
|
||||||
*/
|
*/
|
||||||
NeochatRoomMember *qmlSafeMember(const QString &memberId);
|
Q_INVOKABLE NeochatRoomMember *qmlSafeMember(const QString &memberId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pin a message in the room.
|
* @brief Pin a message in the room.
|
||||||
|
|||||||
107
src/messagecontent/CMakeLists.txt
Normal file
107
src/messagecontent/CMakeLists.txt
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
qt_add_library(MessageContent STATIC)
|
||||||
|
ecm_add_qml_module(MessageContent GENERATE_PLUGIN_SOURCE
|
||||||
|
URI org.kde.neochat.messagecontent
|
||||||
|
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/messagecontent
|
||||||
|
QML_FILES
|
||||||
|
BaseMessageComponentChooser.qml
|
||||||
|
MessageComponentChooser.qml
|
||||||
|
ReplyMessageComponentChooser.qml
|
||||||
|
AuthorComponent.qml
|
||||||
|
AudioComponent.qml
|
||||||
|
ChatBarComponent.qml
|
||||||
|
CodeComponent.qml
|
||||||
|
EncryptedComponent.qml
|
||||||
|
FetchButtonComponent.qml
|
||||||
|
FileComponent.qml
|
||||||
|
ImageComponent.qml
|
||||||
|
ItineraryComponent.qml
|
||||||
|
ItineraryReservationComponent.qml
|
||||||
|
JourneySectionStopDelegateLineSegment.qml
|
||||||
|
TransportIcon.qml
|
||||||
|
FoodReservationComponent.qml
|
||||||
|
TrainReservationComponent.qml
|
||||||
|
FlightReservationComponent.qml
|
||||||
|
HotelReservationComponent.qml
|
||||||
|
LinkPreviewComponent.qml
|
||||||
|
LinkPreviewLoadComponent.qml
|
||||||
|
LiveLocationComponent.qml
|
||||||
|
LoadComponent.qml
|
||||||
|
LocationComponent.qml
|
||||||
|
MimeComponent.qml
|
||||||
|
PdfPreviewComponent.qml
|
||||||
|
PollComponent.qml
|
||||||
|
QuoteComponent.qml
|
||||||
|
ReactionComponent.qml
|
||||||
|
ReplyAuthorComponent.qml
|
||||||
|
ReplyButtonComponent.qml
|
||||||
|
ReplyComponent.qml
|
||||||
|
StateComponent.qml
|
||||||
|
TextComponent.qml
|
||||||
|
ThreadBodyComponent.qml
|
||||||
|
VideoComponent.qml
|
||||||
|
SOURCES
|
||||||
|
contentprovider.cpp
|
||||||
|
mediasizehelper.cpp
|
||||||
|
pollhandler.cpp
|
||||||
|
models/itinerarymodel.cpp
|
||||||
|
models/linemodel.cpp
|
||||||
|
models/messagecontentmodel.cpp
|
||||||
|
models/pollanswermodel.cpp
|
||||||
|
models/reactionmodel.cpp
|
||||||
|
models/threadmodel.cpp
|
||||||
|
RESOURCES
|
||||||
|
images/bike.svg
|
||||||
|
images/bus.svg
|
||||||
|
images/cablecar.svg
|
||||||
|
images/car.svg
|
||||||
|
images/coach.svg
|
||||||
|
images/couchettecar.svg
|
||||||
|
images/elevator.svg
|
||||||
|
images/escalator.svg
|
||||||
|
images/ferry.svg
|
||||||
|
images/flight.svg
|
||||||
|
images/foodestablishment.svg
|
||||||
|
images/funicular.svg
|
||||||
|
images/longdistancetrain.svg
|
||||||
|
images/rapidtransit.svg
|
||||||
|
images/seat.svg
|
||||||
|
images/shuttle.svg
|
||||||
|
images/sleepingcar.svg
|
||||||
|
images/stairs.svg
|
||||||
|
images/subway.svg
|
||||||
|
images/taxi.svg
|
||||||
|
images/train.svg
|
||||||
|
images/tramway.svg
|
||||||
|
images/transfer.svg
|
||||||
|
images/wait.svg
|
||||||
|
images/walk.svg
|
||||||
|
DEPENDENCIES
|
||||||
|
QtQuick
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_file(config-neochat.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-neochat.h)
|
||||||
|
|
||||||
|
ecm_qt_declare_logging_category(MessageContent
|
||||||
|
HEADER "messagemodel_logging.h"
|
||||||
|
IDENTIFIER "Message"
|
||||||
|
CATEGORY_NAME "org.kde.neochat.messagemodel"
|
||||||
|
DESCRIPTION "Neochat: messagemodel"
|
||||||
|
DEFAULT_SEVERITY Info
|
||||||
|
EXPORT NEOCHAT
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(MessageContent PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models)
|
||||||
|
target_link_libraries(MessageContent PRIVATE
|
||||||
|
Qt::Core
|
||||||
|
Qt::Quick
|
||||||
|
Qt::QuickControls2
|
||||||
|
KF6::Kirigami
|
||||||
|
LibNeoChat
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT ANDROID)
|
||||||
|
target_link_libraries(MessageContent PUBLIC KF6::SyntaxHighlighting)
|
||||||
|
endif()
|
||||||
@@ -46,9 +46,32 @@ Item {
|
|||||||
*/
|
*/
|
||||||
required property var fileTransferInfo
|
required property var fileTransferInfo
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum height of the image. Can be left undefined most of the times. Passed to MediaSizeHelper::contentMaxHeight.
|
||||||
|
*/
|
||||||
|
property var contentMaxHeight: undefined
|
||||||
|
|
||||||
implicitWidth: mediaSizeHelper.currentSize.width
|
implicitWidth: mediaSizeHelper.currentSize.width
|
||||||
implicitHeight: mediaSizeHelper.currentSize.height
|
implicitHeight: mediaSizeHelper.currentSize.height
|
||||||
|
|
||||||
|
QQC2.Button {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
visible: !_private.hideImage
|
||||||
|
icon.name: "view-hidden"
|
||||||
|
text: i18nc("@action:button", "Hide Image")
|
||||||
|
display: QQC2.Button.IconOnly
|
||||||
|
z: 10
|
||||||
|
onClicked: {
|
||||||
|
_private.hideImage = true;
|
||||||
|
Controller.markImageHidden(root.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.ToolTip.text: text
|
||||||
|
QQC2.ToolTip.visible: hovered
|
||||||
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: imageLoader
|
id: imageLoader
|
||||||
|
|
||||||
@@ -98,7 +121,7 @@ Item {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
visible: _private.imageItem.status !== Image.Ready
|
visible: _private.imageItem.status !== Image.Ready || _private.hideImage
|
||||||
|
|
||||||
color: "#BB000000"
|
color: "#BB000000"
|
||||||
|
|
||||||
@@ -164,6 +187,7 @@ Item {
|
|||||||
MediaSizeHelper {
|
MediaSizeHelper {
|
||||||
id: mediaSizeHelper
|
id: mediaSizeHelper
|
||||||
contentMaxWidth: root.Message.maxContentWidth
|
contentMaxWidth: root.Message.maxContentWidth
|
||||||
|
contentMaxHeight: root.contentMaxHeight ?? -1
|
||||||
mediaWidth: root?.mediaInfo.isSticker ? 256 : (root?.mediaInfo.width ?? 0)
|
mediaWidth: root?.mediaInfo.isSticker ? 256 : (root?.mediaInfo.width ?? 0)
|
||||||
mediaHeight: root?.mediaInfo.isSticker ? 256 : (root?.mediaInfo.height ?? 0)
|
mediaHeight: root?.mediaInfo.isSticker ? 256 : (root?.mediaInfo.height ?? 0)
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user