Compare commits
1 Commits
work/test-
...
work/redst
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e0f0182cb |
@@ -2,5 +2,7 @@
|
|||||||
; 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.9",
|
"runtime-version": "6.8",
|
||||||
"sdk": "org.kde.Sdk",
|
"sdk": "org.kde.Sdk",
|
||||||
"command": "neochat",
|
"command": "neochat",
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -149,6 +149,27 @@
|
|||||||
],
|
],
|
||||||
"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,20 +3,19 @@
|
|||||||
|
|
||||||
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 "11")
|
set(RELEASE_SERVICE_VERSION_MINOR "07")
|
||||||
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,7 +61,6 @@ 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();
|
||||||
@@ -451,32 +450,6 @@ 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.
|
||||||
*
|
*
|
||||||
@@ -485,13 +458,46 @@ void TextHandlerTest::receiveRichPlainUrl_data()
|
|||||||
*/
|
*/
|
||||||
void TextHandlerTest::receiveRichPlainUrl()
|
void TextHandlerTest::receiveRichPlainUrl()
|
||||||
{
|
{
|
||||||
QFETCH(QString, input);
|
// This is an actual link that caused trouble which is why it's so long. Keeping
|
||||||
QFETCH(QString, output);
|
// so we can confirm consistent behaviour for complex urls.
|
||||||
|
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(input);
|
testTextHandler.setData(testInputStringLink1);
|
||||||
|
|
||||||
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), output);
|
QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringLink1);
|
||||||
|
|
||||||
|
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(NeoChatRoom *, NeoChatRoom *)));
|
QSignalSpy spy(model, SIGNAL(roomChanged()));
|
||||||
|
|
||||||
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(NeoChatRoom *, NeoChatRoom *)));
|
QSignalSpy spy(model, SIGNAL(roomChanged()));
|
||||||
|
|
||||||
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->indexforEventId(u"$153456789:example.org"_s).row(), 0);
|
QCOMPARE(model->eventIdToRow(u"$153456789:example.org"_s), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineMessageModelTest::cleanup()
|
void TimelineMessageModelTest::cleanup()
|
||||||
|
|||||||
@@ -477,8 +477,6 @@
|
|||||||
<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
1115
po/ast/neochat.po
1115
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
1153
po/eo/neochat.po
1153
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
1155
po/hi/neochat.po
1155
po/hi/neochat.po
File diff suppressed because it is too large
Load Diff
1663
po/hu/neochat.po
1663
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1161
po/ia/neochat.po
1161
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
1107
po/ja/neochat.po
1107
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
1398
po/ko/neochat.po
1398
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1125
po/lt/neochat.po
1125
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
1175
po/pl/neochat.po
1175
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
1180
po/ru/neochat.po
1180
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1151
po/sa/neochat.po
1151
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
1163
po/ta/neochat.po
1163
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,7 +9,6 @@ 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,6 +20,8 @@ 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
|
||||||
@@ -59,7 +61,9 @@ 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
|
||||||
@@ -104,11 +108,12 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
|||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
QtCore
|
QtCore
|
||||||
QtQuick
|
QtQuick
|
||||||
|
org.kde.prison
|
||||||
|
org.kde.prison.scanner
|
||||||
IMPORTS
|
IMPORTS
|
||||||
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
|
||||||
@@ -177,7 +182,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 MessageContentplugin Timelineplugin Spacesplugin Chatbarplugin Settingsplugin Devtoolsplugin)
|
target_link_libraries(neochat PRIVATE Loginplugin Roomsplugin RoomInfoplugin Timelineplugin Spacesplugin Chatbarplugin Settingsplugin Devtoolsplugin)
|
||||||
target_link_libraries(neochat PUBLIC
|
target_link_libraries(neochat PUBLIC
|
||||||
LibNeoChat
|
LibNeoChat
|
||||||
Timeline
|
Timeline
|
||||||
@@ -202,7 +207,6 @@ target_link_libraries(neochat PUBLIC
|
|||||||
QuotientQt6
|
QuotientQt6
|
||||||
Login
|
Login
|
||||||
Rooms
|
Rooms
|
||||||
MessageContent
|
|
||||||
Spaces
|
Spaces
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -357,10 +361,3 @@ 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,9 +407,4 @@ 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,7 +99,6 @@ 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);
|
||||||
|
|||||||
223
src/app/logger.cpp
Normal file
223
src/app/logger.cpp
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
// 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"
|
||||||
9
src/app/logger.h
Normal file
9
src/app/logger.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// 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,6 +49,7 @@
|
|||||||
#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"
|
||||||
@@ -137,11 +138,6 @@ 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);
|
||||||
@@ -181,6 +177,8 @@ 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);
|
||||||
|
|
||||||
@@ -197,9 +195,6 @@ 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);
|
||||||
@@ -236,7 +231,7 @@ int main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_KDBUSADDONS
|
#ifdef HAVE_KDBUSADDONS
|
||||||
KDBusService service(KDBusService::Unique | (parser.isSet(replaceOption) ? KDBusService::Replace : KDBusService::StartupOption(0)));
|
KDBusService service(KDBusService::Unique);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const auto accountManager = std::make_unique<AccountManager>(parser.isSet("test"_L1));
|
const auto accountManager = std::make_unique<AccountManager>(parser.isSet("test"_L1));
|
||||||
@@ -244,6 +239,13 @@ 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,12 +78,6 @@
|
|||||||
<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>
|
||||||
@@ -211,10 +205,6 @@
|
|||||||
<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,18 +36,14 @@ 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: NeoChatSettingsView.openWithInitialProperties("accounts", {initialAccount: root.connection});
|
onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.settings', 'AccountEditorPage'), {
|
||||||
|
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.qmlSafeMember(currentRoom.invitingUserId)
|
readonly property var invitingMember: currentRoom.member(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: NeoChatConfig.hideImages ? undefined : root.invitingMember.avatarUrl
|
source: root.invitingMember.avatarUrl
|
||||||
color: root.invitingMember.color
|
color: root.invitingMember.color
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ 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: NeoChatConfig.lastSaveDirectory.length > 0 ? NeoChatConfig.lastSaveDirectory : Core.StandardPaths.writableLocation(Core.StandardPaths.DownloadLocation)
|
currentFolder: root.saveFolder
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
NeoChatConfig.lastSaveDirectory = currentFolder;
|
NeoChatConfig.lastSaveDirectory = currentFolder;
|
||||||
NeoChatConfig.save();
|
NeoChatConfig.save();
|
||||||
|
|||||||
@@ -28,14 +28,6 @@ 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
|
||||||
@@ -58,7 +50,6 @@ 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,14 +11,15 @@ 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.
|
||||||
* @brief The NeoChatRoom the delegate is being displayed in.
|
property NeoChatRoom currentRoom: RoomManager.currentRoom
|
||||||
*/
|
|
||||||
readonly property NeoChatRoom currentRoom: RoomManager.currentRoom
|
required property NeoChatConnection connection
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The TimelineModel to use.
|
* @brief The TimelineModel to use.
|
||||||
@@ -58,6 +59,11 @@ 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
|
||||||
@@ -80,9 +86,9 @@ Kirigami.Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.currentRoom.connection
|
target: root.connection
|
||||||
function onIsOnlineChanged() {
|
function onIsOnlineChanged() {
|
||||||
if (!root.currentRoom.connection.isOnline) {
|
if (!root.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;
|
||||||
@@ -103,15 +109,18 @@ Kirigami.Page {
|
|||||||
Loader {
|
Loader {
|
||||||
id: timelineViewLoader
|
id: timelineViewLoader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
active: root.currentRoom && !root.currentRoom.isInvite && !root.currentRoom.isSpace
|
active: root.currentRoom && !root.currentRoom.isInvite && !root.loading && !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
|
||||||
compactLayout: NeoChatConfig.compactLayout
|
onFocusChatBar: {
|
||||||
fileDropEnabled: !Controller.isFlatpak
|
if (chatBarLoader.item) {
|
||||||
markReadCondition: NeoChatConfig.markReadCondition
|
chatBarLoader.item.forceActiveFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +152,14 @@ 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
|
||||||
@@ -157,7 +174,12 @@ Kirigami.Page {
|
|||||||
id: chatBar
|
id: chatBar
|
||||||
width: parent.width
|
width: parent.width
|
||||||
currentRoom: root.currentRoom
|
currentRoom: root.currentRoom
|
||||||
connection: root.currentRoom.connection
|
connection: root.connection
|
||||||
|
onMessageSent: {
|
||||||
|
if (!timelineViewLoader.item.atYEnd) {
|
||||||
|
timelineViewLoader.item.goToLastMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,8 +196,21 @@ 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.currentRoom.connection
|
target: root.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);
|
||||||
@@ -261,7 +296,7 @@ Kirigami.Page {
|
|||||||
id: messageDelegateContextMenu
|
id: messageDelegateContextMenu
|
||||||
MessageDelegateContextMenu {
|
MessageDelegateContextMenu {
|
||||||
room: root.currentRoom
|
room: root.currentRoom
|
||||||
connection: root.currentRoom.connection
|
connection: root.connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +304,7 @@ Kirigami.Page {
|
|||||||
id: fileDelegateContextMenu
|
id: fileDelegateContextMenu
|
||||||
FileDelegateContextMenu {
|
FileDelegateContextMenu {
|
||||||
room: root.currentRoom
|
room: root.currentRoom
|
||||||
connection: root.currentRoom.connection
|
connection: root.connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ 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,7 +96,6 @@ 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,5 +15,4 @@ ecm_add_qml_module(Chatbar GENERATE_PLUGIN_SOURCE
|
|||||||
EmojiPicker.qml
|
EmojiPicker.qml
|
||||||
EmojiDialog.qml
|
EmojiDialog.qml
|
||||||
EmojiTonesPicker.qml
|
EmojiTonesPicker.qml
|
||||||
ImageEditorPage.qml
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -160,6 +160,11 @@ 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
|
||||||
@@ -431,6 +436,7 @@ 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.url
|
source: model.avatarUrl
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
sourceSize.width: width
|
sourceSize.width: width
|
||||||
sourceSize.height: height
|
sourceSize.height: height
|
||||||
|
|||||||
@@ -36,13 +36,4 @@ 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,7 +28,6 @@ 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
|
||||||
@@ -49,6 +48,11 @@ target_sources(LibNeoChat PRIVATE
|
|||||||
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
|
||||||
|
DEPENDENCIES
|
||||||
|
QtCore
|
||||||
|
QtQuick
|
||||||
|
org.kde.prison
|
||||||
|
org.kde.prison.scanner
|
||||||
QML_FILES
|
QML_FILES
|
||||||
qml/GroupChatDrawerHeader.qml
|
qml/GroupChatDrawerHeader.qml
|
||||||
qml/LocationMapItem.qml
|
qml/LocationMapItem.qml
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
// 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,13 +435,6 @@ 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());
|
||||||
},
|
},
|
||||||
@@ -641,14 +634,7 @@ 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 &e) {
|
[senderString](const StateEvent &) {
|
||||||
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;
|
||||||
|
|
||||||
bool operator==(const MessageComponent &right) const
|
int 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,38 +1214,34 @@ 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()) {
|
if (evtIt != messageEvents().rend() && is<RoomMessageEvent>(**evtIt)) {
|
||||||
return;
|
const auto event = evtIt->viewAs<RoomMessageEvent>();
|
||||||
}
|
if (event->has<EventContent::FileContent>()) {
|
||||||
|
const auto transferInfo = cachedFileTransferInfo(event);
|
||||||
// TODO: Also allow stickers here, once that's fixed in libQuotient
|
if (transferInfo.completed()) {
|
||||||
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.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE NeochatRoomMember *qmlSafeMember(const QString &memberId);
|
NeochatRoomMember *qmlSafeMember(const QString &memberId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pin a message in the room.
|
* @brief Pin a message in the room.
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
# 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()
|
|
||||||
@@ -14,10 +14,4 @@ ecm_add_qml_module(RoomInfo GENERATE_PLUGIN_SOURCE
|
|||||||
LocationsPage.qml
|
LocationsPage.qml
|
||||||
RoomPinnedMessagesPage.qml
|
RoomPinnedMessagesPage.qml
|
||||||
RoomSearchPage.qml
|
RoomSearchPage.qml
|
||||||
SOURCES
|
|
||||||
locationhelper.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(RoomInfo PRIVATE
|
|
||||||
Qt::Core
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,22 +17,13 @@ import org.kde.neochat
|
|||||||
Kirigami.Page {
|
Kirigami.Page {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
Kirigami.ColumnView.interactiveResizeEnabled: true
|
/**
|
||||||
Kirigami.ColumnView.minimumWidth: _private.collapsedSize + spaceDrawer.width + 1
|
* @brief The current width of the room list.
|
||||||
Kirigami.ColumnView.maximumWidth: _private.defaultWidth + spaceDrawer.width + 1
|
*
|
||||||
Kirigami.ColumnView.onInteractiveResizingChanged: {
|
* @note Other objects can access the value but the private function makes sure
|
||||||
if (!Kirigami.ColumnView.interactiveResizing && collapsed) {
|
* that only the internal members can modify it.
|
||||||
Kirigami.ColumnView.preferredWidth = root.Kirigami.ColumnView.minimumWidth;
|
*/
|
||||||
}
|
readonly property int currentWidth: _private.currentWidth + spaceDrawer.width + 1
|
||||||
}
|
|
||||||
Kirigami.ColumnView.preferredWidth: _private.currentWidth + spaceDrawer.width + 1
|
|
||||||
Kirigami.ColumnView.onPreferredWidthChanged: {
|
|
||||||
if (width > _private.collapseWidth) {
|
|
||||||
NeoChatConfig.collapsed = false;
|
|
||||||
} else if (Kirigami.ColumnView.interactiveResizing) {
|
|
||||||
NeoChatConfig.collapsed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
required property NeoChatConnection connection
|
required property NeoChatConnection connection
|
||||||
|
|
||||||
@@ -40,6 +31,10 @@ Kirigami.Page {
|
|||||||
|
|
||||||
signal search
|
signal search
|
||||||
|
|
||||||
|
onCurrentWidthChanged: pageStack.defaultColumnWidth = root.currentWidth
|
||||||
|
Component.onCompleted: pageStack.defaultColumnWidth = root.currentWidth
|
||||||
|
|
||||||
|
|
||||||
onCollapsedChanged: {
|
onCollapsedChanged: {
|
||||||
if (collapsed) {
|
if (collapsed) {
|
||||||
RoomManager.sortFilterRoomTreeModel.filterText = "";
|
RoomManager.sortFilterRoomTreeModel.filterText = "";
|
||||||
@@ -249,6 +244,49 @@ Kirigami.Page {
|
|||||||
sourceComponent: Kirigami.Settings.isMobile ? exploreComponentMobile : userInfoDesktop
|
sourceComponent: Kirigami.Settings.isMobile ? exploreComponentMobile : userInfoDesktop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
parent: applicationWindow().overlay.parent
|
||||||
|
|
||||||
|
x: root.currentWidth - width / 2
|
||||||
|
width: Kirigami.Units.smallSpacing * 2
|
||||||
|
z: root.z + 1
|
||||||
|
enabled: RoomManager.hasOpenRoom && applicationWindow().width >= Kirigami.Units.gridUnit * 35
|
||||||
|
visible: enabled
|
||||||
|
cursorShape: Qt.SplitHCursor
|
||||||
|
|
||||||
|
property int _lastX
|
||||||
|
|
||||||
|
onPressed: mouse => {
|
||||||
|
_lastX = mouse.x;
|
||||||
|
}
|
||||||
|
onPositionChanged: mouse => {
|
||||||
|
if (_lastX == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mouse.x > _lastX) {
|
||||||
|
// we moved to the right
|
||||||
|
if (_private.currentWidth < _private.collapseWidth && _private.currentWidth + (mouse.x - _lastX) >= _private.collapseWidth) {
|
||||||
|
// Here we get back directly to a more wide mode.
|
||||||
|
_private.currentWidth = _private.defaultWidth;
|
||||||
|
NeoChatConfig.collapsed = false;
|
||||||
|
} else if (_private.currentWidth >= _private.collapseWidth) {
|
||||||
|
// Increase page width
|
||||||
|
_private.currentWidth = Math.min(_private.defaultWidth, _private.currentWidth + (mouse.x - _lastX));
|
||||||
|
}
|
||||||
|
} else if (mouse.x < _lastX) {
|
||||||
|
const tmpWidth = _private.currentWidth - (_lastX - mouse.x);
|
||||||
|
if (tmpWidth < _private.collapseWidth) {
|
||||||
|
_private.currentWidth = Qt.binding(() => _private.collapsedSize);
|
||||||
|
NeoChatConfig.collapsed = true;
|
||||||
|
} else {
|
||||||
|
_private.currentWidth = tmpWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: userInfo
|
id: userInfo
|
||||||
UserInfo {
|
UserInfo {
|
||||||
|
|||||||
@@ -38,14 +38,26 @@ QQC2.ItemDelegate {
|
|||||||
Keys.onSpacePressed: root.treeView.toggleExpanded(row)
|
Keys.onSpacePressed: root.treeView.toggleExpanded(row)
|
||||||
|
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
spacing: 0
|
spacing: Kirigami.Units.largeSpacing
|
||||||
Kirigami.ListSectionHeader {
|
|
||||||
|
Kirigami.Heading {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
visible: !root.collapsed
|
||||||
|
|
||||||
|
opacity: 0.7
|
||||||
|
level: 5
|
||||||
|
type: Kirigami.Heading.Primary
|
||||||
|
text: root.collapsed ? "" : model.displayName
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
// we override the Primary type's font weight (DemiBold) for Bold for contrast with small text
|
||||||
|
font.weight: Font.Bold
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Separator {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
visible: !root.collapsed
|
visible: !root.collapsed
|
||||||
horizontalPadding: 0
|
Layout.alignment: Qt.AlignVCenter
|
||||||
topPadding: 0
|
|
||||||
bottomPadding: 0
|
|
||||||
text: root.collapsed ? "" : root.displayName
|
|
||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
id: collapseButton
|
id: collapseButton
|
||||||
|
|||||||
@@ -95,19 +95,31 @@ RowLayout {
|
|||||||
window: QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow
|
window: QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QQC2.ToolButton {
|
|
||||||
display: QQC2.Button.IconOnly
|
|
||||||
action: Kirigami.Action {
|
|
||||||
text: i18n("Open Settings")
|
|
||||||
icon.name: "settings-configure-symbolic"
|
|
||||||
onTriggered: {
|
|
||||||
NeoChatSettingsView.open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.ToolTip.text: text
|
Kirigami.ActionToolBar {
|
||||||
QQC2.ToolTip.visible: hovered
|
alignment: Qt.AlignRight
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
display: QQC2.Button.IconOnly
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: maximumContentWidth
|
||||||
|
|
||||||
|
actions: [
|
||||||
|
Kirigami.Action {
|
||||||
|
text: i18n("Switch User")
|
||||||
|
icon.name: "system-switch-user"
|
||||||
|
shortcut: "Ctrl+U"
|
||||||
|
onTriggered: accountSwitchDialog.createObject(QQC2.Overlay.overlay, {
|
||||||
|
connection: root.connection
|
||||||
|
}).open();
|
||||||
|
},
|
||||||
|
Kirigami.Action {
|
||||||
|
text: i18n("Open Settings")
|
||||||
|
icon.name: "settings-configure-symbolic"
|
||||||
|
onTriggered: {
|
||||||
|
NeoChatSettingsView.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ FormCard.FormCardPage {
|
|||||||
icon.name: "document-save-symbolic"
|
icon.name: "document-save-symbolic"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!root.connection.setAvatar(avatar.source)) {
|
if (!root.connection.setAvatar(avatar.source)) {
|
||||||
(root.Window.window as Kirigami.ApplicationWindow).showPassiveNotification("The Avatar could not be set");
|
showPassiveNotification("The Avatar could not be set");
|
||||||
}
|
}
|
||||||
if (root.connection.localUser.displayName !== name.text) {
|
if (root.connection.localUser.displayName !== name.text) {
|
||||||
root.connection.localUser.rename(name.text);
|
root.connection.localUser.rename(name.text);
|
||||||
|
|||||||
@@ -134,45 +134,9 @@ FormCard.FormCardPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FormCard.FormHeader {
|
FormCard.FormHeader {
|
||||||
title: i18nc("@title", "Timeline")
|
title: i18n("Timeline Events")
|
||||||
}
|
}
|
||||||
FormCard.FormCard {
|
FormCard.FormCard {
|
||||||
FormCard.FormComboBoxDelegate {
|
|
||||||
id: markAsReadCombo
|
|
||||||
text: i18n("Mark messages as read when:")
|
|
||||||
textRole: "name"
|
|
||||||
valueRole: "value"
|
|
||||||
model: [
|
|
||||||
{
|
|
||||||
name: i18n("Never"),
|
|
||||||
value: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: i18nc("@item:inlistbox As in mark messages in the room as read when entering the room", "Entering the room"),
|
|
||||||
value: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: i18nc("@item:inlistbox As in mark messages in the room as read when entering the room and all messages are visible on screen", "Entering the room and all unread messages are visible"),
|
|
||||||
value: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: i18nc("@item:inlistbox As in mark messages in the room as read when exiting the room", "Exiting the room"),
|
|
||||||
value: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: i18nc("@item:inlistbox As in mark messages in the room as read when exiting the room and all messages are visible on screen", "Exiting the room and all unread messages are visible"),
|
|
||||||
value: 4
|
|
||||||
}
|
|
||||||
]
|
|
||||||
Component.onCompleted: currentIndex = NeoChatConfig.markReadCondition
|
|
||||||
onCurrentValueChanged: NeoChatConfig.markReadCondition = currentValue
|
|
||||||
}
|
|
||||||
|
|
||||||
FormCard.FormDelegateSeparator {
|
|
||||||
above: markAsReadCombo
|
|
||||||
below: showDeletedMessages
|
|
||||||
}
|
|
||||||
|
|
||||||
FormCard.FormCheckDelegate {
|
FormCard.FormCheckDelegate {
|
||||||
id: showDeletedMessages
|
id: showDeletedMessages
|
||||||
text: i18n("Show deleted messages")
|
text: i18n("Show deleted messages")
|
||||||
@@ -345,16 +309,8 @@ FormCard.FormCardPage {
|
|||||||
FormCard.FormCard {
|
FormCard.FormCard {
|
||||||
FormCard.FormButtonDelegate {
|
FormCard.FormButtonDelegate {
|
||||||
icon.name: "kt-restore-defaults-symbolic"
|
icon.name: "kt-restore-defaults-symbolic"
|
||||||
text: i18nc("@action:button", "Reset all configuration values to their default")
|
text: i18nc("@action:button", "Reset All Configuration Values to Their Default")
|
||||||
onClicked: resetDialog.open()
|
onClicked: Controller.revertToDefaultConfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kirigami.PromptDialog {
|
|
||||||
id: resetDialog
|
|
||||||
title: i18nc("@title:dialog", "Reset Configuration")
|
|
||||||
subtitle: i18nc("@info", "Do you really want to reset all options to their default values?")
|
|
||||||
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
|
|
||||||
onAccepted: Controller.revertToDefaultConfig()
|
|
||||||
anchors.centerIn: QQC2.Overlay.overlay
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ KirigamiSettings.ConfigurationView {
|
|||||||
visible: root.connection !== null
|
visible: root.connection !== null
|
||||||
},
|
},
|
||||||
KirigamiSettings.ConfigurationModule {
|
KirigamiSettings.ConfigurationModule {
|
||||||
id: accountsModule
|
|
||||||
moduleId: "accounts"
|
moduleId: "accounts"
|
||||||
text: i18n("Accounts")
|
text: i18n("Accounts")
|
||||||
icon.name: "preferences-system-users-symbolic"
|
icon.name: "preferences-system-users-symbolic"
|
||||||
@@ -112,14 +111,4 @@ KirigamiSettings.ConfigurationView {
|
|||||||
category: i18nc("@title:group", "About")
|
category: i18nc("@title:group", "About")
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
function openWithInitialProperties(defaultModule = '', initialProperties): void {
|
|
||||||
let module = modules.find(module => module.moduleId == defaultModule) ?? null;
|
|
||||||
if (module) {
|
|
||||||
module.initialProperties = () => {
|
|
||||||
return initialProperties;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
root.open(defaultModule);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,15 @@ using namespace Quotient;
|
|||||||
DevicesModel::DevicesModel(QObject *parent)
|
DevicesModel::DevicesModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
|
connect(m_connection, &Connection::sessionVerified, this, [this](const QString &, const QString &deviceId) {
|
||||||
|
const auto it = std::find_if(m_devices.begin(), m_devices.end(), [deviceId](const Quotient::Device &device) {
|
||||||
|
return device.deviceId == deviceId;
|
||||||
|
});
|
||||||
|
if (it != m_devices.end()) {
|
||||||
|
const auto index = this->index(it - m_devices.begin());
|
||||||
|
Q_EMIT dataChanged(index, index, {Type});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicesModel::fetchDevices()
|
void DevicesModel::fetchDevices()
|
||||||
@@ -153,15 +162,6 @@ void DevicesModel::setConnection(NeoChatConnection *connection)
|
|||||||
disconnect(m_connection, nullptr, this, nullptr);
|
disconnect(m_connection, nullptr, this, nullptr);
|
||||||
}
|
}
|
||||||
m_connection = connection;
|
m_connection = connection;
|
||||||
connect(m_connection, &Connection::sessionVerified, this, [this](const QString &, const QString &deviceId) {
|
|
||||||
const auto it = std::find_if(m_devices.begin(), m_devices.end(), [deviceId](const Quotient::Device &device) {
|
|
||||||
return device.deviceId == deviceId;
|
|
||||||
});
|
|
||||||
if (it != m_devices.end()) {
|
|
||||||
const auto index = this->index(it - m_devices.begin());
|
|
||||||
Q_EMIT dataChanged(index, index, {Type});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Q_EMIT connectionChanged();
|
Q_EMIT connectionChanged();
|
||||||
fetchDevices();
|
fetchDevices();
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ 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 Components
|
import org.kde.kirigamiaddons.labs.components as Components
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
import org.kde.neochat.libneochat
|
import org.kde.neochat.libneochat
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|||||||
@@ -13,42 +13,127 @@ ecm_add_qml_module(Timeline GENERATE_PLUGIN_SOURCE
|
|||||||
LoadingDelegate.qml
|
LoadingDelegate.qml
|
||||||
PredecessorDelegate.qml
|
PredecessorDelegate.qml
|
||||||
ReadMarkerDelegate.qml
|
ReadMarkerDelegate.qml
|
||||||
SpacerDelegate.qml
|
|
||||||
StateDelegate.qml
|
StateDelegate.qml
|
||||||
SuccessorDelegate.qml
|
SuccessorDelegate.qml
|
||||||
TimelineEndDelegate.qml
|
TimelineEndDelegate.qml
|
||||||
Bubble.qml
|
Bubble.qml
|
||||||
AvatarFlow.qml
|
AvatarFlow.qml
|
||||||
|
SectionDelegate.qml
|
||||||
QuickActions.qml
|
QuickActions.qml
|
||||||
TypingPane.qml
|
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
|
||||||
DelegateContextMenu.qml
|
DelegateContextMenu.qml
|
||||||
FileDelegateContextMenu.qml
|
FileDelegateContextMenu.qml
|
||||||
MessageDelegateContextMenu.qml
|
MessageDelegateContextMenu.qml
|
||||||
SOURCES
|
SOURCES
|
||||||
|
contentprovider.cpp
|
||||||
|
locationhelper.cpp
|
||||||
|
mediasizehelper.cpp
|
||||||
messageattached.cpp
|
messageattached.cpp
|
||||||
messagedelegate.cpp
|
messagedelegate.cpp
|
||||||
|
pollhandler.cpp
|
||||||
timelinedelegate.cpp
|
timelinedelegate.cpp
|
||||||
enums/delegatetype.h
|
enums/delegatetype.h
|
||||||
|
models/itinerarymodel.cpp
|
||||||
|
models/linemodel.cpp
|
||||||
models/mediamessagefiltermodel.cpp
|
models/mediamessagefiltermodel.cpp
|
||||||
|
models/messagecontentmodel.cpp
|
||||||
models/messagecontentfiltermodel.cpp
|
models/messagecontentfiltermodel.cpp
|
||||||
models/messagefiltermodel.cpp
|
models/messagefiltermodel.cpp
|
||||||
models/messagemodel.cpp
|
models/messagemodel.cpp
|
||||||
models/pinnedmessagemodel.cpp
|
models/pinnedmessagemodel.cpp
|
||||||
|
models/pollanswermodel.cpp
|
||||||
|
models/reactionmodel.cpp
|
||||||
models/readmarkermodel.cpp
|
models/readmarkermodel.cpp
|
||||||
models/searchmodel.cpp
|
models/searchmodel.cpp
|
||||||
models/timelinemessagemodel.cpp
|
models/timelinemessagemodel.cpp
|
||||||
models/timelinemodel.cpp
|
models/timelinemodel.cpp
|
||||||
|
models/threadmodel.cpp
|
||||||
models/webshortcutmodel.cpp
|
models/webshortcutmodel.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
|
DEPENDENCIES
|
||||||
QtQuick
|
QtQuick
|
||||||
)
|
)
|
||||||
|
|
||||||
|
configure_file(config-neochat.h.in ${CMAKE_CURRENT_BINARY_DIR}/config-neochat.h)
|
||||||
|
|
||||||
|
ecm_qt_declare_logging_category(Timeline
|
||||||
|
HEADER "messagemodel_logging.h"
|
||||||
|
IDENTIFIER "Message"
|
||||||
|
CATEGORY_NAME "org.kde.neochat.messagemodel"
|
||||||
|
DESCRIPTION "Neochat: messagemodel"
|
||||||
|
DEFAULT_SEVERITY Info
|
||||||
|
EXPORT NEOCHAT
|
||||||
|
)
|
||||||
|
|
||||||
target_include_directories(Timeline PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/enums ${CMAKE_CURRENT_SOURCE_DIR}/models)
|
target_include_directories(Timeline PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/enums ${CMAKE_CURRENT_SOURCE_DIR}/models)
|
||||||
target_link_libraries(Timeline PRIVATE
|
target_link_libraries(Timeline PRIVATE
|
||||||
|
LibNeoChat
|
||||||
Qt::Core
|
Qt::Core
|
||||||
Qt::Quick
|
Qt::Quick
|
||||||
Qt::QuickControls2
|
Qt::QuickControls2
|
||||||
KF6::Kirigami
|
KF6::Kirigami
|
||||||
LibNeoChat
|
|
||||||
MessageContent
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(NOT ANDROID)
|
||||||
|
target_link_libraries(Timeline PUBLIC KF6::SyntaxHighlighting)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -62,11 +62,6 @@ DelegateChooser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DelegateChoice {
|
|
||||||
roleValue: DelegateType.Spacer
|
|
||||||
delegate: SpacerDelegate {}
|
|
||||||
}
|
|
||||||
|
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: DelegateType.Other
|
roleValue: DelegateType.Other
|
||||||
delegate: NeoChatConfig.showAllEvents ? hiddenDelegate : emptyDelegate
|
delegate: NeoChatConfig.showAllEvents ? hiddenDelegate : emptyDelegate
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user