Compare commits

...

53 Commits

Author SHA1 Message Date
l10n daemon script
5b3e650854 GIT_SILENT Sync po/docbooks with svn 2024-08-16 03:04:39 +00:00
Heiko Becker
86d85c6ce7 GIT_SILENT Update Appstream for new release 2024-08-16 00:35:00 +02:00
Heiko Becker
863e20394a GIT_SILENT Upgrade release service version to 24.08.0. 2024-08-15 23:34:44 +02:00
l10n daemon script
908dcea75e GIT_SILENT made messages (after extraction) 2024-08-11 02:34:30 +00:00
l10n daemon script
c59d5bc75d SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-08-10 03:12:41 +00:00
l10n daemon script
ff4ba4df9c GIT_SILENT made messages (after extraction) 2024-08-10 02:39:29 +00:00
l10n daemon script
0c1494e74a SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-08-09 03:01:15 +00:00
Albert Astals Cid
18d4da8b42 GIT_SILENT Upgrade release service version to 24.07.90. 2024-08-08 10:00:41 +02:00
l10n daemon script
9680cbbb38 GIT_SILENT Sync po/docbooks with svn 2024-08-06 03:07:30 +00:00
l10n daemon script
3b5ba470b6 GIT_SILENT Sync po/docbooks with svn 2024-08-04 03:12:15 +00:00
l10n daemon script
e1066aede2 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-08-04 03:08:29 +00:00
l10n daemon script
2bf4ed26f0 GIT_SILENT Sync po/docbooks with svn 2024-08-03 03:09:58 +00:00
l10n daemon script
b460b588a8 GIT_SILENT Sync po/docbooks with svn 2024-08-02 03:10:44 +00:00
l10n daemon script
05270c38bf GIT_SILENT Sync po/docbooks with svn 2024-07-31 03:05:10 +00:00
l10n daemon script
18afad83db GIT_SILENT Sync po/docbooks with svn 2024-07-30 03:09:21 +00:00
Tobias Fella
d390433b2b Show time without seconds in timeline
(cherry picked from commit 2df2e39d43)
2024-07-29 18:00:10 +02:00
Tobias Fella
0017be1c0f Show time without timezone in tooltip
Constructing the timezone string is relatively heavy and is done for each delegate, even when the tooltip is never shown

(cherry picked from commit 42cec7d5ba)
2024-07-29 18:00:08 +02:00
l10n daemon script
63eda3796d GIT_SILENT Sync po/docbooks with svn 2024-07-29 03:09:38 +00:00
l10n daemon script
3246076a0b GIT_SILENT Sync po/docbooks with svn 2024-07-28 03:10:41 +00:00
James Graham
e905cdd151 Cherrypick: Create NeochatRoomMember as a shim for RoomMember
The intention is that NeochatRoomMember can be created passed to QML and then be fully managed by it. It effectively just grabs the current RoomMember, calls the correct function then discards it so that we don't end up trying to access an already deleted state event.


(cherry picked from commit 11fd4f88ec)

a2a8ad09 Create NeochatRoomMember as a shim for RoomMember so it can be safely passed to QML
0867eef5 Fix showAuthor
0f72ccd0 Mamange the creation of NeochatRoomMembers and only create one per member rather than event.
dba88fe2 REmove getAuthor as no longer needed
4e3a61d1 Update include
32d4d9f7 Pass NeochatRoomMembers rather than RoomMembers to menus
8e4b2034 Don't leak memory
c2f2bb26 Fix code component regression.
5aee89be Make sure the sender Id is intialised properly for pending events
c10c2677 Tweak intialisation
b3146034 Make sure event objects are created for new pending events
e4fab6d9 Pass an empty NeochatRoomMember when not in the map

Co-authored-by: James Graham <james.h.graham@protonmail.com>
2024-07-27 09:33:14 +00:00
l10n daemon script
0372074beb GIT_SILENT Sync po/docbooks with svn 2024-07-27 03:10:43 +00:00
Joshua Goins
09e97f2bdb Make the "Unignore this user" button work on the Ignored Users page
This function now takes a QString. This should be fine to use since it's
in the 0.8.2 release which we require.

(cherry picked from commit 9a4504ce61)
2024-07-26 19:09:57 +00:00
Joshua Goins
8e324c16f3 Fix the emoji page not doing anything
This is yet more stuff broken due to referencing a implicit pageStack
that no longer exists.


(cherry picked from commit cb8ed02e82)

Co-authored-by: Joshua Goins <josh@redstrate.com>
2024-07-26 19:00:47 +00:00
Joshua Goins
2bb55eece7 Don't flag invite notifications as persistent
These really don't need to be persistent, as they even stick around
when NeoChat is closed. This also spams the user's notification system
usually, if they get lots of invitations at once which don't go away
automatically.

(cherry picked from commit 51197d7c1a)
2024-07-25 16:38:13 -04:00
Joshua Goins
2877e40647 Hint that the user can auto-reject invitations on the invite page
This should help make the new setting more discoverable.

(cherry picked from commit 2a2a2e0c05)
2024-07-25 16:38:13 -04:00
Joshua Goins
768ec242fa Allow blocking invites from people you don't share a room with
Matrix currently has a significant moderation loophole, thanks to
invites. Right now, anyone can invite anyone to a room - and clients
like NeoChat will gladly display these rooms to them and even give you
a notification.

However, this creates a pretty easy attack since room names and avatars
are arbitrary and this is a known vector of harassment in the Matrix
community. There's currently no tools to block this server-side, so
let's try to improve the situation where we can.

This adds a new setting to the Security page, wherein it allows you to
block invites from people you don't share a room with. This prevents the
notification from appearing and NeoChat will attempt to leave the room
immediately.

Since this depends on MSC 2666 - a currently unstable feature - the
server may not support it and NeoChat will disable the setting in this
case.

(cherry picked from commit 07fee30cc0)
2024-07-25 16:38:13 -04:00
Joshua Goins
194751627f Don't display notifications for invite rooms
Sometimes a ghost notification will appear, this is sometimes a stray
m.room.invite notification we didn't handle or some other event. Let's
outright reject all notifications from Invite-type rooms to prevent this
from happening altogether.

(cherry picked from commit 83c6ce0ace)
2024-07-25 16:38:13 -04:00
l10n daemon script
bc701c51d9 GIT_SILENT Sync po/docbooks with svn 2024-07-25 03:13:15 +00:00
l10n daemon script
35939b4af4 GIT_SILENT Sync po/docbooks with svn 2024-07-23 03:14:18 +00:00
l10n daemon script
a178b8b6ca SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-07-23 03:04:52 +00:00
Albert Astals Cid
a6994318de GIT_SILENT Upgrade release service version to 24.07.80. 2024-07-21 12:25:07 +02:00
l10n daemon script
5022ed1a63 GIT_SILENT Sync po/docbooks with svn 2024-07-21 01:27:43 +00:00
James Graham
799ffa18c4 Fix the javascript when using .? 2024-07-20 22:35:41 +00:00
Tobias Fella
6323e27040 Remove customemojimodel_p.h
It's been unused for a long time
2024-07-20 22:49:22 +02:00
Tobias Fella
03acb26109 Fix some clazy warnings 2024-07-20 22:38:45 +02:00
Tobias Fella
34fc1f6a6b Fix text alignment in ReadMarkerDelegate 2024-07-20 21:54:55 +02:00
James Graham
042032ec46 Update user sort
Update the user model so it also sorts by power level and update how we initialize the model to improve performance.

The following is also changed:
- Store a single `UserListModel` in `RoomManager` and use it for everything, this means we don't create extra models (incluiding the long initialisation for each in big rooms)
- By using the single model once it has loaded the users of the new room opening and closing the draw now happens instantly (previously the model would have to be loaded every time the drawer was opened).
- To stop the initial loading and room change of Neochat slowing down (as the `UserListModel` would be loaded before the `TimelineView` is shown) the initialisation of the model is delayed until the `TimelineView` has loaded. This prioritises showing some messages in the timeline over populating the model so in large rooms the user list will initially be blank, but this keeps the initial load snappier.
2024-07-20 18:12:30 +00:00
James Graham
73de99f661 Create a list model for readmarkers
Create a list model for read markers. The primary reason is to stop `RoomMembers` being accessed after their state event is deleted. With this the read marker doesn't pass and `RoomMember` objects to qml.
2024-07-20 18:05:15 +00:00
l10n daemon script
cc068f9ebb GIT_SILENT Sync po/docbooks with svn 2024-07-19 01:26:38 +00:00
l10n daemon script
2bfc2b1944 GIT_SILENT Sync po/docbooks with svn 2024-07-18 01:23:41 +00:00
l10n daemon script
029936112f GIT_SILENT made messages (after extraction) 2024-07-18 00:39:13 +00:00
Andreas Gattringer
d5e400e8a4 stop video on destruction to avoid segfault 2024-07-17 11:08:53 +00:00
Andreas Gattringer
9dbb9c3f3b fix filedownload on maximized view and context menu
- move the logic for remembering local filenames from
  messagecontentmodel to neochatroom
- use it also when maximized and in context menu opening, to stop
  re-downloading
- make onFileTransferCompleted signal connection one-shot (stops memory
  leak)
2024-07-17 08:29:29 +00:00
l10n daemon script
a101e6b0a7 GIT_SILENT Sync po/docbooks with svn 2024-07-17 01:24:34 +00:00
Andreas Gattringer
c525ea55ce fix typo in PollComponent that causes polls to not be checked correctly 2024-07-16 21:41:25 +02:00
Andreas Gattringer
8ca45f298f show thumbail when video is stopped 2024-07-16 12:27:35 +02:00
Andreas Gattringer
cb4c6cb677 Audio filename, caption and seeking
- display caption independent of filename (consistancy to File)
- fix audio seeking not working
- change two comments and a variable name
2024-07-16 12:27:35 +02:00
Andreas Gattringer
d574a97a35 take the correct filename for synthax highlighting in code block 2024-07-16 12:27:35 +02:00
Andreas Gattringer
20f9a86ad9 stop assigning undefined to bool in TimelineView and MessageDelegate 2024-07-16 12:27:35 +02:00
Andreas Gattringer
a4a411cf1f correctly display filename in MimeComponents
(previously it would include the caption text and save with it as
filename)
Don't append filename to the caption.

Relevant spec: https://spec.matrix.org/latest/client-server-api/#mfile
2024-07-16 12:27:35 +02:00
Andreas Gattringer
029bda5734 fix code preview components
- fix them vanishing after "opening" a file (they get downloaded to
  /tmp/ without extension, which caused them to lose preview)
- make all text/plain mimetype files preview
- don't show them in Replies (in consistency with media components)
2024-07-16 12:27:35 +02:00
Andreas Gattringer
0fd578e6aa Refactor MimeComponent
- Fix size and duration not showing in MimeComponents in replies
- Display Itinerary in replies as MimeComponent (in consistency with media
  components)
2024-07-16 12:27:35 +02:00
l10n daemon script
95e1bee5e6 GIT_SILENT Sync po/docbooks with svn 2024-07-16 01:23:40 +00:00
103 changed files with 15590 additions and 8926 deletions

View File

@@ -8,8 +8,8 @@ cmake_minimum_required(VERSION 3.16)
# KDE Applications version, managed by release script. # KDE Applications version, managed by release script.
set(RELEASE_SERVICE_VERSION_MAJOR "24") set(RELEASE_SERVICE_VERSION_MAJOR "24")
set(RELEASE_SERVICE_VERSION_MINOR "07") set(RELEASE_SERVICE_VERSION_MINOR "08")
set(RELEASE_SERVICE_VERSION_MICRO "70") set(RELEASE_SERVICE_VERSION_MICRO "0")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION}) project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})

View File

@@ -36,8 +36,6 @@ private Q_SLOTS:
void eventId(); void eventId();
void nullEventId(); void nullEventId();
void author();
void nullAuthor();
void authorDisplayName(); void authorDisplayName();
void nullAuthorDisplayName(); void nullAuthorDisplayName();
void singleLineSidplayName(); void singleLineSidplayName();
@@ -75,8 +73,6 @@ private Q_SLOTS:
void nullThread(); void nullThread();
void location(); void location();
void nullLocation(); void nullLocation();
void readMarkers();
void nullReadMarkers();
}; };
void EventHandlerTest::initTestCase() void EventHandlerTest::initTestCase()
@@ -98,32 +94,6 @@ void EventHandlerTest::nullEventId()
QCOMPARE(noEventHandler.getId(), QString()); QCOMPARE(noEventHandler.getId(), QString());
} }
void EventHandlerTest::author()
{
auto event = room->messageEvents().at(0).get();
auto author = room->member(event->senderId());
EventHandler eventHandler(room, event);
auto eventHandlerAuthor = eventHandler.getAuthor();
QCOMPARE(eventHandlerAuthor.isLocalMember(), author.id() == room->localMember().id());
QCOMPARE(eventHandlerAuthor.id(), author.id());
QCOMPARE(eventHandlerAuthor.displayName(), author.displayName());
QCOMPARE(eventHandlerAuthor.avatarUrl(), author.avatarUrl());
QCOMPARE(eventHandlerAuthor.avatarMediaId(), author.avatarMediaId());
QCOMPARE(eventHandlerAuthor.color(), author.color());
}
void EventHandlerTest::nullAuthor()
{
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getAuthor(), RoomMember());
EventHandler noEventHandler(room, nullptr);
QTest::ignoreMessage(QtWarningMsg, "getAuthor called with m_event set to nullptr. Returning empty user.");
QCOMPARE(noEventHandler.getAuthor(), RoomMember());
}
void EventHandlerTest::authorDisplayName() void EventHandlerTest::authorDisplayName()
{ {
EventHandler eventHandler(room, room->messageEvents().at(1).get()); EventHandler eventHandler(room, room->messageEvents().at(1).get());
@@ -193,6 +163,7 @@ void EventHandlerTest::timeString()
QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::LongFormat)); QLocale().toString(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().time(), QLocale::LongFormat));
QCOMPARE(eventHandler.getTimeString(true, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)), QCOMPARE(eventHandler.getTimeString(true, QLocale::LongFormat, true, QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC)),
format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat)); format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1690699214545, Qt::UTC).toLocalTime().date(), QLocale::LongFormat));
QCOMPARE(eventHandler.getTimeString(QStringLiteral("hh:mm")), QDateTime::fromMSecsSinceEpoch(1432735824654, Qt::UTC).toString(QStringLiteral("hh:mm")));
} }
void EventHandlerTest::nullTimeString() void EventHandlerTest::nullTimeString()
@@ -521,59 +492,5 @@ void EventHandlerTest::nullLocation()
QCOMPARE(emptyHandler.getLocationAssetType(), QString()); QCOMPARE(emptyHandler.getLocationAssetType(), QString());
} }
void EventHandlerTest::readMarkers()
{
EventHandler eventHandler(room, room->messageEvents().at(0).get());
QCOMPARE(eventHandler.hasReadMarkers(), true);
auto readMarkers = eventHandler.getReadMarkers();
QCOMPARE(readMarkers.size(), 1);
QCOMPARE(readMarkers[0].id(), QStringLiteral("@alice:example.org"));
QCOMPARE(eventHandler.getNumberExcessReadMarkers(), QString());
QCOMPARE(eventHandler.getReadMarkersString(), QStringLiteral("1 user: Alice Margatroid"));
EventHandler eventHandler2(room, room->messageEvents().at(2).get());
QCOMPARE(eventHandler2.hasReadMarkers(), true);
readMarkers = eventHandler2.getReadMarkers();
QCOMPARE(readMarkers.size(), 5);
QCOMPARE(eventHandler2.getNumberExcessReadMarkers(), QStringLiteral("+ 1"));
// There are no guarantees on the order of the users it will be different every time so don't match the whole string.
QCOMPARE(eventHandler2.getReadMarkersString().startsWith(QStringLiteral("6 users:")), true);
}
void EventHandlerTest::nullReadMarkers()
{
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.hasReadMarkers(), false);
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReadMarkers(), QList<Quotient::RoomMember>());
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getNumberExcessReadMarkers(), QString());
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getReadMarkersString(), QString());
EventHandler noEventHandler(room, nullptr);
QTest::ignoreMessage(QtWarningMsg, "hasReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.hasReadMarkers(), false);
QTest::ignoreMessage(QtWarningMsg, "getReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReadMarkers(), QList<Quotient::RoomMember>());
QTest::ignoreMessage(QtWarningMsg, "getNumberExcessReadMarkers called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getNumberExcessReadMarkers(), QString());
QTest::ignoreMessage(QtWarningMsg, "getReadMarkersString called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getReadMarkersString(), QString());
}
QTEST_MAIN(EventHandlerTest) QTEST_MAIN(EventHandlerTest)
#include "eventhandlertest.moc" #include "eventhandlertest.moc"

View File

@@ -25,6 +25,7 @@
<name xml:lang="fi">NeoChat</name> <name xml:lang="fi">NeoChat</name>
<name xml:lang="fr">NeoChat</name> <name xml:lang="fr">NeoChat</name>
<name xml:lang="gl">NeoChat</name> <name xml:lang="gl">NeoChat</name>
<name xml:lang="he">NeoChat</name>
<name xml:lang="hu">NeoChat</name> <name xml:lang="hu">NeoChat</name>
<name xml:lang="ia">Neochat</name> <name xml:lang="ia">Neochat</name>
<name xml:lang="id">NeoChat</name> <name xml:lang="id">NeoChat</name>
@@ -61,6 +62,7 @@
<summary xml:lang="fi">Keskustelu ystäviesi kanssa Matrixissa</summary> <summary xml:lang="fi">Keskustelu ystäviesi kanssa Matrixissa</summary>
<summary xml:lang="fr">Discuter avec vos ami(e)s sur le réseau Matrix</summary> <summary xml:lang="fr">Discuter avec vos ami(e)s sur le réseau Matrix</summary>
<summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary> <summary xml:lang="gl">Charle coas súas amizades en Matrix.</summary>
<summary xml:lang="he">התכתבות עם החברים שלך ב־matrix</summary>
<summary xml:lang="hu">Csevegjen barátaival a matrixon</summary> <summary xml:lang="hu">Csevegjen barátaival a matrixon</summary>
<summary xml:lang="ia">Starta Conversation con tu amicos sur matrix</summary> <summary xml:lang="ia">Starta Conversation con tu amicos sur matrix</summary>
<summary xml:lang="it">Conversa con i tuoi contatti su matrix</summary> <summary xml:lang="it">Conversa con i tuoi contatti su matrix</summary>
@@ -89,12 +91,15 @@
<p xml:lang="eu">NeoChat, Matrix sarearen abantaila guztiei probetsua ateratzeko aukera ematen dizun berriketa aplikaizo bat da. Zure familiari, kideei eta lagunei testu mezuak, bideoak eta audio fitxategiak era seguruan bidaltzeko aukera ematen dizu.</p> <p xml:lang="eu">NeoChat, Matrix sarearen abantaila guztiei probetsua ateratzeko aukera ematen dizun berriketa aplikaizo bat da. Zure familiari, kideei eta lagunei testu mezuak, bideoak eta audio fitxategiak era seguruan bidaltzeko aukera ematen dizu.</p>
<p xml:lang="fi">NeoChat on keskustelusovellus, jolla Matrix-verkosta saa täyden hyödyn. Se tarjoaa salatun kanavan lähettää perheelle, työkavereille ja ystäville tekstiviestejä sekä video- ja äänitiedostoja.</p> <p xml:lang="fi">NeoChat on keskustelusovellus, jolla Matrix-verkosta saa täyden hyödyn. Se tarjoaa salatun kanavan lähettää perheelle, työkavereille ja ystäville tekstiviestejä sekä video- ja äänitiedostoja.</p>
<p xml:lang="fr">NeoChat est une application de discussions vous permettant de profiter pleinement du réseau Matrix. Elle vous offre un moyen sécurisé d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos ami(e)s.</p> <p xml:lang="fr">NeoChat est une application de discussions vous permettant de profiter pleinement du réseau Matrix. Elle vous offre un moyen sécurisé d'envoyer des messages de texte, des vidéos et des fichiers audio à votre famille, vos collègues et vos ami(e)s.</p>
<p xml:lang="gl">NeoChat é unha aplicación de conversa que lle permite usar todas as funcionalidades da rede Matrix. Fornece unha forma segura de enviar mensaxes de texto e ficheiros de vídeo e son a familiares, amizades ou no traballo.</p>
<p xml:lang="he">NeoChat הוא יישום התכתבות שמאפשר לך לנצל את רשת Matrix במלואה. הוא מספק דרך מאובטחת לשליחת הודעות כתובות, סרטונים וקובצי שמע למשפחה, לעמיתים לעבודה ולחברים.</p>
<p xml:lang="hu">A NeoChat egy olyan csevegőalkalmazás, amellyel teljes mértékben kihasználhatja a Matrix hálózatot. Biztonságos módot biztosít szöveges üzenetek, videók és hangfájlok küldéséhez családtagjainak, kollégáinak és barátainak.</p> <p xml:lang="hu">A NeoChat egy olyan csevegőalkalmazás, amellyel teljes mértékben kihasználhatja a Matrix hálózatot. Biztonságos módot biztosít szöveges üzenetek, videók és hangfájlok küldéséhez családtagjainak, kollégáinak és barátainak.</p>
<p xml:lang="ia">NeoChat es un app de conversation que te permitte prender avantage plen del rete Matrix. Il te forni un modo secur de inviar messages de texto, videos e files audio a tui familia, collegas e amicos.</p> <p xml:lang="ia">NeoChat es un app de conversation que te permitte prender avantage plen del rete Matrix. Il te forni un modo secur de inviar messages de texto, videos e files audio a tui familia, collegas e amicos.</p>
<p xml:lang="it">NeoChat è un'applicazione di chat che ti consente di sfruttare appieno la rete Matrix. Ti fornisce un modo sicuro per inviare messaggi di testo, video e file audio a familiari, colleghi e amici.</p> <p xml:lang="it">NeoChat è un'applicazione di chat che ti consente di sfruttare appieno la rete Matrix. Ti fornisce un modo sicuro per inviare messaggi di testo, video e file audio a familiari, colleghi e amici.</p>
<p xml:lang="ka">NeoChat ჩატის აპია, რომელიც საშუალება გაძლევთ, Matrix-ის ქსელის საშუალებები ბოლომდე გამოიყენოთ. ის გაძლევთ უსაფრთხო გზას, გააგზავნოთ ტექსტური შეტყობინებები, ვიდეოებ და აუდიოფაილები თქვენს ოჯახთან, კოლეგებთან და მეგობრებთან.</p> <p xml:lang="ka">NeoChat ჩატის აპია, რომელიც საშუალება გაძლევთ, Matrix-ის ქსელის საშუალებები ბოლომდე გამოიყენოთ. ის გაძლევთ უსაფრთხო გზას, გააგზავნოთ ტექსტური შეტყობინებები, ვიდეოებ და აუდიოფაილები თქვენს ოჯახთან, კოლეგებთან და მეგობრებთან.</p>
<p xml:lang="lv">„NeoChat“ ir tērzēšanas programma, kas ļauj pilnvērtīgi izmantot „Matrix“ tīklu. Tā sniedz drošu veidu teksta ziņu, video un audio sūtīšanai ģimenes locekļiem, kolēģiem un draugiem.</p> <p xml:lang="lv">„NeoChat“ ir tērzēšanas programma, kas ļauj pilnvērtīgi izmantot „Matrix“ tīklu. Tā sniedz drošu veidu teksta ziņu, video un audio sūtīšanai ģimenes locekļiem, kolēģiem un draugiem.</p>
<p xml:lang="nl">NeoChat is een chat-toepassing die u het volledige voordeel van het Matrix-netwerk laat genieten. Het levert u op een veilige manier tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden te verzenden.</p> <p xml:lang="nl">NeoChat is een chat-toepassing die u het volledige voordeel van het Matrix-netwerk laat genieten. Het levert u op een veilige manier tekstberichten, video's en geluidsbestanden naar uw familie, collega's en vrienden te verzenden.</p>
<p xml:lang="nn">NeoChat er ein prateapp som lèt deg bruka all funksjonalitet i Matrix-nettverket. Du kan utveksla tekst, lyd og videoar med vennar, familie og kollegaar på ein trygg måte.</p>
<p xml:lang="pl">NoeChat to aplikacja do rozmów, która umożliwia wykorzystanie wszystkich możliwości Matriksa. Umożliwia wysyłanie wiadomości tekstowych, filmów i dźwięków w bezpieczny sposób do twojej rodziny, kolegów i przyjaciół.</p> <p xml:lang="pl">NoeChat to aplikacja do rozmów, która umożliwia wykorzystanie wszystkich możliwości Matriksa. Umożliwia wysyłanie wiadomości tekstowych, filmów i dźwięków w bezpieczny sposób do twojej rodziny, kolegów i przyjaciół.</p>
<p xml:lang="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p> <p xml:lang="sl">NeoChat je aplikacija za klepet, ki vam omogoča, da v celoti izkoristite omrežje Matrix. Zagotavlja vam varen način za pošiljanje besedilnih sporočil, videoposnetkov in zvočnih datotek vaši družini, sodelavcem in prijateljem.</p>
<p xml:lang="sv">NeoChat är ett chattprogram som låter dig dra full nytta av Matrix-nätverket. Det ger dig ett säkert sätt att skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner.</p> <p xml:lang="sv">NeoChat är ett chattprogram som låter dig dra full nytta av Matrix-nätverket. Det ger dig ett säkert sätt att skicka textmeddelanden, videor och ljudfiler till din familj, kollegor och vänner.</p>
@@ -113,6 +118,7 @@
<p xml:lang="fi">NeoChat pyrkii olemaan Matrix-määritelmän täysominaisuuksinen sovellus, joten se tukee kaikkea nykyisessä vakaassa määritelmässä muutamaa huomattavaa poikkeusta lukuun ottamatta (VoIP, säikeet ja jotkin piirteet päästä päähän -salauksessa). Joitakin pienempiäkin puutteita on Matrix-määritelmän jatkuvan kehityksen vuoksi, mutta lopputavoitteena on tarjota määritelmän täysi tuki.</p> <p xml:lang="fi">NeoChat pyrkii olemaan Matrix-määritelmän täysominaisuuksinen sovellus, joten se tukee kaikkea nykyisessä vakaassa määritelmässä muutamaa huomattavaa poikkeusta lukuun ottamatta (VoIP, säikeet ja jotkin piirteet päästä päähän -salauksessa). Joitakin pienempiäkin puutteita on Matrix-määritelmän jatkuvan kehityksen vuoksi, mutta lopputavoitteena on tarjota määritelmän täysi tuki.</p>
<p xml:lang="fr">L'objectif de NeoChat est d'être une application complète pour le protocole Matrix. En tant que tel, tout dans la spécification stable actuelle avec les exceptions notables de VoIP, les processus et certains aspects du chiffrement de bout en bout sont pris en charge. Il y a quelques autres petites omissions en raison du fait que la spécification du protocole Matrix est en constante évolution. Cependant, l'objectif reste de fournir un soutien éventuel pour l'ensemble de la spécification.</p> <p xml:lang="fr">L'objectif de NeoChat est d'être une application complète pour le protocole Matrix. En tant que tel, tout dans la spécification stable actuelle avec les exceptions notables de VoIP, les processus et certains aspects du chiffrement de bout en bout sont pris en charge. Il y a quelques autres petites omissions en raison du fait que la spécification du protocole Matrix est en constante évolution. Cependant, l'objectif reste de fournir un soutien éventuel pour l'ensemble de la spécification.</p>
<p xml:lang="gl">NeoChat pretende ser unha aplicación completa para a especificación de Matrix. Coas excepcións de VoIP, conversas fiadas e algúns aspectos da cifraxe de extremo a extremo, a versión estábel segue as especificacións. Existen algunhas outras pequenas omisións debido ao feito de que Matrix está en continua evolución pero a intención é implementar a especificación completa.</p> <p xml:lang="gl">NeoChat pretende ser unha aplicación completa para a especificación de Matrix. Coas excepcións de VoIP, conversas fiadas e algúns aspectos da cifraxe de extremo a extremo, a versión estábel segue as especificacións. Existen algunhas outras pequenas omisións debido ao feito de que Matrix está en continua evolución pero a intención é implementar a especificación completa.</p>
<p xml:lang="he">NeoChat מתיימר להיות יישום עתיר יכולות לפי מפרט Matrix. כיוון שזה ייעודו, כל מה שבמפרט היציב עם חריגות משמעותיות כגון VoIP, שרשורים ועוד מגוון היבטים של הצפנה מקצה לקצה נתמכים גם הם. יש מספר השמטות קטן עקב העובדה שהמפרט של Matrix ממשיך להתפתח אך המטרה היא להמשיך לספק תמיכה בסופו של דבר לכל המפרט.</p>
<p xml:lang="hu">A NeoChat célja, hogy a Matrix specifikációnak megfelelő teljes funkcionalitású alkalmazás legyen. Mint ilyen, a jelenlegi stabil specifikáció támogatott a VoIP, a szálak és a végpontok közötti titkosítás egyes elemeinek kivételével. Van még néhány kisebb hiányosság annak köszönhetően, hogy a Matrix specifikáció folyamatosan fejlődik, de végső cél a teljes specifikáció megvalósítása.</p> <p xml:lang="hu">A NeoChat célja, hogy a Matrix specifikációnak megfelelő teljes funkcionalitású alkalmazás legyen. Mint ilyen, a jelenlegi stabil specifikáció támogatott a VoIP, a szálak és a végpontok közötti titkosítás egyes elemeinek kivételével. Van még néhány kisebb hiányosság annak köszönhetően, hogy a Matrix specifikáció folyamatosan fejlődik, de végső cél a teljes specifikáció megvalósítása.</p>
<p xml:lang="ia">NeoChat aspira a esser un application plenmente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p> <p xml:lang="ia">NeoChat aspira a esser un application plenmente eminente per le specification de Matrix. Tal como omne cosas in le specification currentemente stabile con le exceptiones notabile de VOIP, threads e alcun aspectos del cryptation End-to-End es supportate. Il ha ltere pauc omissiones, debite al facto que le specification de Matrix es in evolution constante ma le aspiration remane a fornir supporto eventual per le integre specification.</p>
<p xml:lang="it">NeoChat mira ad essere un'applicazione completa per le specifiche Matrix. Pertanto, sono supportati tutti gli elementi dell'attuale specifica stabile con le notevoli eccezioni di VoIP, conversazioni e alcuni aspetti della cifratura end-to-end. Ci sono alcune altre piccole omissioni dovute al fatto che le specifiche Matrix sono in continua evoluzione, ma l'obiettivo rimane quello di fornire un eventuale supporto per l'intera specifica.</p> <p xml:lang="it">NeoChat mira ad essere un'applicazione completa per le specifiche Matrix. Pertanto, sono supportati tutti gli elementi dell'attuale specifica stabile con le notevoli eccezioni di VoIP, conversazioni e alcuni aspetti della cifratura end-to-end. Ci sono alcune altre piccole omissioni dovute al fatto che le specifiche Matrix sono in continua evoluzione, ma l'obiettivo rimane quello di fornire un eventuale supporto per l'intera specifica.</p>
@@ -141,6 +147,7 @@
<p xml:lang="fi">Matrix-määritelmän kehittyessä NeoChat tukee myös monia epävakaita ominaisuuksia. Tällä hetkellä näitä ovat:</p> <p xml:lang="fi">Matrix-määritelmän kehittyessä NeoChat tukee myös monia epävakaita ominaisuuksia. Tällä hetkellä näitä ovat:</p>
<p xml:lang="fr">En raison de la nature du développement des spécifications du protocole Matrix, NeoChat prend également en charge de nombreuses fonctionnalités instables. Actuellement, ce sont :</p> <p xml:lang="fr">En raison de la nature du développement des spécifications du protocole Matrix, NeoChat prend également en charge de nombreuses fonctionnalités instables. Actuellement, ce sont :</p>
<p xml:lang="gl">Debido á natureza do desenvolvemento da especificación de Matrix, NeoChat tamén inclúe varias funcionalidades non estábeis:</p> <p xml:lang="gl">Debido á natureza do desenvolvemento da especificación de Matrix, NeoChat tamén inclúe varias funcionalidades non estábeis:</p>
<p xml:lang="he">מטבע הדברים, הפיתוח של NeoChat תומך במגוון יכולות מפוקפקות כתלות בהתפתחות המפרט הטכני של Matrix. היכולות האלה הן:</p>
<p xml:lang="hu">A Matrix specifikáció fejlesztésének jellegéből adódóan a NeoChat számos instabil funkciót is támogat. Jelenleg a következőket:</p> <p xml:lang="hu">A Matrix specifikáció fejlesztésének jellegéből adódóan a NeoChat számos instabil funkciót is támogat. Jelenleg a következőket:</p>
<p xml:lang="ia">Debite al natura del disveloppamento de specification de Matrix NeoChat tamben supporta numerose characteristicas instabile. Currentemente istes es:</p> <p xml:lang="ia">Debite al natura del disveloppamento de specification de Matrix NeoChat tamben supporta numerose characteristicas instabile. Currentemente istes es:</p>
<p xml:lang="it">A causa della natura dello sviluppo delle specifiche Matrix, NeoChat supporta anche numerose funzionalità instabili. Attualmente queste sono:</p> <p xml:lang="it">A causa della natura dello sviluppo delle specifiche Matrix, NeoChat supporta anche numerose funzionalità instabili. Attualmente queste sono:</p>
@@ -171,6 +178,7 @@
<li xml:lang="fi">Kyselyt MSC3381</li> <li xml:lang="fi">Kyselyt MSC3381</li>
<li xml:lang="fr">Sondages - MSC3381</li> <li xml:lang="fr">Sondages - MSC3381</li>
<li xml:lang="gl">Enquisas — MSC3381</li> <li xml:lang="gl">Enquisas — MSC3381</li>
<li xml:lang="he">סקרים - MSC3381</li>
<li xml:lang="hu">Szavazások - MSC3381</li> <li xml:lang="hu">Szavazások - MSC3381</li>
<li xml:lang="ia">Inquestas - MSC3381</li> <li xml:lang="ia">Inquestas - MSC3381</li>
<li xml:lang="it">Sondaggi - MSC3381</li> <li xml:lang="it">Sondaggi - MSC3381</li>
@@ -199,6 +207,7 @@
<li xml:lang="fi">Tarrapakkaukset MSC2545</li> <li xml:lang="fi">Tarrapakkaukset MSC2545</li>
<li xml:lang="fr">Paquets d'auto-collants - MSC2545</li> <li xml:lang="fr">Paquets d'auto-collants - MSC2545</li>
<li xml:lang="gl">Paquetes de adhesivos — MSC2545</li> <li xml:lang="gl">Paquetes de adhesivos — MSC2545</li>
<li xml:lang="he">חבילות מדבקות - MSC2545</li>
<li xml:lang="hu">Matricacsomagok - MSC2545</li> <li xml:lang="hu">Matricacsomagok - MSC2545</li>
<li xml:lang="ia">Etiquetta gummate (sticker) -MSC2545</li> <li xml:lang="ia">Etiquetta gummate (sticker) -MSC2545</li>
<li xml:lang="it">Pacchetti di adesivi - MSC2545</li> <li xml:lang="it">Pacchetti di adesivi - MSC2545</li>
@@ -228,6 +237,7 @@
<li xml:lang="fi">Sijaintitapahtumat MSC3488</li> <li xml:lang="fi">Sijaintitapahtumat MSC3488</li>
<li xml:lang="fr">Événements de lieu - MSC3488</li> <li xml:lang="fr">Événements de lieu - MSC3488</li>
<li xml:lang="gl">Localización de eventos — MSC3488</li> <li xml:lang="gl">Localización de eventos — MSC3488</li>
<li xml:lang="he">אירועי מקום - MSC3488</li>
<li xml:lang="hu">Események helyadatai - MSC3488</li> <li xml:lang="hu">Események helyadatai - MSC3488</li>
<li xml:lang="ia">Eventos de Location - MSC3488</li> <li xml:lang="ia">Eventos de Location - MSC3488</li>
<li xml:lang="it">Località eventi - MSC3488</li> <li xml:lang="it">Località eventi - MSC3488</li>
@@ -291,6 +301,7 @@
<caption xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</caption> <caption xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</caption>
<caption xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</caption> <caption xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</caption>
<caption xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</caption> <caption xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</caption>
<caption xml:lang="he">תצוגה ראשית עם רשימת חדרים, צ׳אט ופרטי חדר</caption>
<caption xml:lang="hu">A fő nézet a szobalistával, csevegéssel és szobainformációkkal</caption> <caption xml:lang="hu">A fő nézet a szobalistával, csevegéssel és szobainformációkkal</caption>
<caption xml:lang="ia">Vista principal con lista de sala, chat e information de sala</caption> <caption xml:lang="ia">Vista principal con lista de sala, chat e information de sala</caption>
<caption xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</caption> <caption xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</caption>
@@ -322,12 +333,15 @@
<caption xml:lang="eu">Ezagutu komunitate berriak Matrixeko Tokiak erabiliz</caption> <caption xml:lang="eu">Ezagutu komunitate berriak Matrixeko Tokiak erabiliz</caption>
<caption xml:lang="fi">Löydä uusia yhteisöjä Matrix Spacesillä</caption> <caption xml:lang="fi">Löydä uusia yhteisöjä Matrix Spacesillä</caption>
<caption xml:lang="fr">Découvrez de nouvelles communautés avec les espaces sous Matrix</caption> <caption xml:lang="fr">Découvrez de nouvelles communautés avec les espaces sous Matrix</caption>
<caption xml:lang="gl">Descubra novas comunidades dos espazos de Matrix.</caption>
<caption xml:lang="he">אפשר להיחשף לקהילות חדשות דרך Matrix Spaces</caption>
<caption xml:lang="hu">Fedezzen fel új közösségeket a Matrix Terek segítségével</caption> <caption xml:lang="hu">Fedezzen fel új közösségeket a Matrix Terek segítségével</caption>
<caption xml:lang="ia">Discoperi nove communitate con Matrix Spaces (Spatios de Matrix)</caption> <caption xml:lang="ia">Discoperi nove communitate con Matrix Spaces (Spatios de Matrix)</caption>
<caption xml:lang="it">Scopri nuove comunità con Matrix Spaces</caption> <caption xml:lang="it">Scopri nuove comunità con Matrix Spaces</caption>
<caption xml:lang="ka">აღმოაჩინეთ ახალი საზოგადოებები Matrix Spaces-თან ერთად</caption> <caption xml:lang="ka">აღმოაჩინეთ ახალი საზოგადოებები Matrix Spaces-თან ერთად</caption>
<caption xml:lang="lv">Atklājiet jaunas kopienas ar „Matrix“ telpām</caption> <caption xml:lang="lv">Atklājiet jaunas kopienas ar „Matrix“ telpām</caption>
<caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption> <caption xml:lang="nl">Ontdek nieuwe gemeenschappen met Matrix-ruimten</caption>
<caption xml:lang="nn">Oppdag nye fellesskap med Matrix Spaces</caption>
<caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption> <caption xml:lang="pl">Odkrywaj nowe społeczności w Przestrzeniach Matriksa</caption>
<caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption> <caption xml:lang="sl">Odkrijte nove skupnosti z Matrix Spaces</caption>
<caption xml:lang="sv">Upptäck nya gemenskaper med Matrix Spaces</caption> <caption xml:lang="sv">Upptäck nya gemenskaper med Matrix Spaces</caption>
@@ -356,6 +370,7 @@
<caption xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</caption> <caption xml:lang="fi">Päänäkymä, jossa huoneluettelo, keskustelu ja huoneen tiedot</caption>
<caption xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</caption> <caption xml:lang="fr">Vue principale avec la liste des salons ainsi que des informations sur les salons et forums de discussions</caption>
<caption xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</caption> <caption xml:lang="gl">Vista principal coa lista de salas, a charla, e información da sala.</caption>
<caption xml:lang="he">תצוגה ראשית עם רשימת חדרים, צ׳אט ופרטי חדר</caption>
<caption xml:lang="hu">A fő nézet a szobalistával, csevegéssel és szobainformációkkal</caption> <caption xml:lang="hu">A fő nézet a szobalistával, csevegéssel és szobainformációkkal</caption>
<caption xml:lang="ia">Vista principal con lista de sala, chat e information de sala</caption> <caption xml:lang="ia">Vista principal con lista de sala, chat e information de sala</caption>
<caption xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</caption> <caption xml:lang="it">Vista principale con elenco delle stanze, chat e informazioni sulla stanza</caption>
@@ -389,6 +404,7 @@
<caption xml:lang="fi">Kirjautumisnäkymä</caption> <caption xml:lang="fi">Kirjautumisnäkymä</caption>
<caption xml:lang="fr">Écran de connexion</caption> <caption xml:lang="fr">Écran de connexion</caption>
<caption xml:lang="gl">Pantalla de identificación.</caption> <caption xml:lang="gl">Pantalla de identificación.</caption>
<caption xml:lang="he">מסך כניסה</caption>
<caption xml:lang="hu">Bejelentkező képernyő</caption> <caption xml:lang="hu">Bejelentkező képernyő</caption>
<caption xml:lang="ia">Schermo de accesso</caption> <caption xml:lang="ia">Schermo de accesso</caption>
<caption xml:lang="it">Schermata di accesso</caption> <caption xml:lang="it">Schermata di accesso</caption>
@@ -413,6 +429,7 @@
<content_attribute id="social-chat">intense</content_attribute> <content_attribute id="social-chat">intense</content_attribute>
</content_rating> </content_rating>
<releases> <releases>
<release version="24.08.0" date="2024-08-22"/>
<release version="24.05.2" date="2024-07-04"/> <release version="24.05.2" date="2024-07-04"/>
<release version="24.05.1" date="2024-06-13"/> <release version="24.05.1" date="2024-06-13"/>
<release version="24.05.0" date="2024-05-23"/> <release version="24.05.0" date="2024-05-23"/>

View File

@@ -18,6 +18,7 @@ Name[eu]=NeoChat
Name[fi]=NeoChat Name[fi]=NeoChat
Name[fr]=NeoChat Name[fr]=NeoChat
Name[gl]=NeoChat Name[gl]=NeoChat
Name[he]=NeoChat
Name[hu]=NeoChat Name[hu]=NeoChat
Name[ia]=Neochat Name[ia]=Neochat
Name[id]=NeoChat Name[id]=NeoChat
@@ -59,6 +60,7 @@ GenericName[eu]=Matrix bezeroa
GenericName[fi]=Matrix-asiakas GenericName[fi]=Matrix-asiakas
GenericName[fr]=Client « Matrix » GenericName[fr]=Client « Matrix »
GenericName[gl]=Cliente de Matrix GenericName[gl]=Cliente de Matrix
GenericName[he]=לקוח Matrix
GenericName[hu]=Matrix kliens GenericName[hu]=Matrix kliens
GenericName[ia]=Cliente de Matrice GenericName[ia]=Cliente de Matrice
GenericName[id]=Klien Matrix GenericName[id]=Klien Matrix
@@ -99,6 +101,7 @@ Comment[eu]=Matrix protokolorako bezeroa
Comment[fi]=Asiakas Matrix-yhteyskäytännölle Comment[fi]=Asiakas Matrix-yhteyskäytännölle
Comment[fr]=Client pour le protocole « Matrix » Comment[fr]=Client pour le protocole « Matrix »
Comment[gl]=Cliente para o protocolo Matrix. Comment[gl]=Cliente para o protocolo Matrix.
Comment[he]=לקוח לפרוטוקול Matrix
Comment[hu]=Kliens a Matrix protokollhoz Comment[hu]=Kliens a Matrix protokollhoz
Comment[ia]=Cliente per le protocollo de Matrix Comment[ia]=Cliente per le protocollo de Matrix
Comment[id]=Klien untuk protokol Matrix Comment[id]=Klien untuk protokol Matrix

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: neochat\n" "Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2024-07-15 00:38+0000\n" "POT-Creation-Date: 2024-07-30 02:34+0000\n"
"PO-Revision-Date: 2023-12-12 01:02+0100\n" "PO-Revision-Date: 2023-12-12 01:02+0100\n"
"Last-Translator: Enol P. <enolp@softastur.org>\n" "Last-Translator: Enol P. <enolp@softastur.org>\n"
"Language-Team: Asturian <alministradores@softastur.org>\n" "Language-Team: Asturian <alministradores@softastur.org>\n"
@@ -363,7 +363,7 @@ msgid "Custom"
msgstr "" msgstr ""
#: src/enums/powerlevel.cpp:88 src/models/permissionsmodel.cpp:162 #: src/enums/powerlevel.cpp:88 src/models/permissionsmodel.cpp:162
#: src/models/userlistmodel.cpp:113 #: src/models/userlistmodel.cpp:114
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"%1 is the name of the power level, e.g. admin and %2 is the value that " "%1 is the name of the power level, e.g. admin and %2 is the value that "
@@ -371,368 +371,349 @@ msgctxt ""
msgid "%1 (%2)" msgid "%1 (%2)"
msgstr "" msgstr ""
#: src/eventhandler.cpp:304 src/eventhandler.cpp:509 #: src/eventhandler.cpp:297 src/eventhandler.cpp:505
#: src/models/messagecontentmodel.cpp:223 src/models/messageeventmodel.cpp:459 #: src/models/messagecontentmodel.cpp:230 src/models/messageeventmodel.cpp:438
#, kde-format #, kde-format
msgid "<i>[This message was deleted]</i>" msgid "<i>[This message was deleted]</i>"
msgstr "" msgstr ""
#: src/eventhandler.cpp:304 src/models/messagecontentmodel.cpp:224 #: src/eventhandler.cpp:297 src/models/messagecontentmodel.cpp:231
#: src/models/messageeventmodel.cpp:460 #: src/models/messageeventmodel.cpp:439
#, kde-format #, kde-format
msgid "<i>[This message was deleted: %1]</i>" msgid "<i>[This message was deleted: %1]</i>"
msgstr "" msgstr ""
#: src/eventhandler.cpp:335 #: src/eventhandler.cpp:331
#, kde-format #, kde-format
msgid "reinvited %1 to the room" msgid "reinvited %1 to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:337 #: src/eventhandler.cpp:333
#, kde-format #, kde-format
msgctxt "Optional reason for an invitation" msgctxt "Optional reason for an invitation"
msgid ": %1" msgid ": %1"
msgstr ": %1" msgstr ": %1"
#: src/eventhandler.cpp:346 src/eventhandler.cpp:533 #: src/eventhandler.cpp:342 src/eventhandler.cpp:529
#, kde-format #, kde-format
msgid "joined the room (repeated)" msgid "joined the room (repeated)"
msgstr "" msgstr ""
#: src/eventhandler.cpp:348 #: src/eventhandler.cpp:344
#, kde-format #, kde-format
msgid "invited %1 to the room" msgid "invited %1 to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:348 src/eventhandler.cpp:535 #: src/eventhandler.cpp:344 src/eventhandler.cpp:531
#, kde-format #, kde-format
msgid "joined the room" msgid "joined the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:352 #: src/eventhandler.cpp:348
#, kde-format #, kde-format
msgid ": %1" msgid ": %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:359 src/eventhandler.cpp:543 #: src/eventhandler.cpp:355 src/eventhandler.cpp:539
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "cleared their display name" msgid "cleared their display name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:362 #: src/eventhandler.cpp:358
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "changed their display name to %1" msgid "changed their display name to %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:368 src/eventhandler.cpp:550 #: src/eventhandler.cpp:364 src/eventhandler.cpp:546
#, kde-format #, kde-format
msgid " and " msgid " and "
msgstr "" msgstr ""
#: src/eventhandler.cpp:371 src/eventhandler.cpp:553 #: src/eventhandler.cpp:367 src/eventhandler.cpp:549
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "cleared their avatar" msgid "cleared their avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:373 src/eventhandler.cpp:555 #: src/eventhandler.cpp:369 src/eventhandler.cpp:551
#, kde-format #, kde-format
msgid "set an avatar" msgid "set an avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:375 src/eventhandler.cpp:557 #: src/eventhandler.cpp:371 src/eventhandler.cpp:553
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "updated their avatar" msgid "updated their avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:379 src/eventhandler.cpp:561 #: src/eventhandler.cpp:375 src/eventhandler.cpp:557
#, kde-format #, kde-format
msgctxt "<user> changed nothing" msgctxt "<user> changed nothing"
msgid "changed nothing" msgid "changed nothing"
msgstr "" msgstr ""
#: src/eventhandler.cpp:385 #: src/eventhandler.cpp:381
#, kde-format #, kde-format
msgid "withdrew %1's invitation" msgid "withdrew %1's invitation"
msgstr "" msgstr ""
#: src/eventhandler.cpp:385 src/eventhandler.cpp:567 #: src/eventhandler.cpp:381 src/eventhandler.cpp:563
#, kde-format #, kde-format
msgid "rejected the invitation" msgid "rejected the invitation"
msgstr "" msgstr ""
#: src/eventhandler.cpp:389 #: src/eventhandler.cpp:385
#, kde-format #, kde-format
msgid "unbanned %1" msgid "unbanned %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:389 src/eventhandler.cpp:571 #: src/eventhandler.cpp:385 src/eventhandler.cpp:567
#, kde-format #, kde-format
msgid "self-unbanned" msgid "self-unbanned"
msgstr "" msgstr ""
#: src/eventhandler.cpp:392 #: src/eventhandler.cpp:388
#, kde-format #, kde-format
msgid "has put %1 out of the room: %2" msgid "has put %1 out of the room: %2"
msgstr "" msgstr ""
#: src/eventhandler.cpp:393 src/eventhandler.cpp:573 #: src/eventhandler.cpp:389 src/eventhandler.cpp:569
#, kde-format #, kde-format
msgid "left the room" msgid "left the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:397 #: src/eventhandler.cpp:393
#, kde-format #, kde-format
msgid "banned %1 from the room" msgid "banned %1 from the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:399 #: src/eventhandler.cpp:395
#, kde-format #, kde-format
msgid "banned %1 from the room: %2" msgid "banned %1 from the room: %2"
msgstr "" msgstr ""
#: src/eventhandler.cpp:402 src/eventhandler.cpp:578 #: src/eventhandler.cpp:398 src/eventhandler.cpp:574
#, kde-format #, kde-format
msgid "self-banned from the room" msgid "self-banned from the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:406 src/eventhandler.cpp:581 #: src/eventhandler.cpp:402 src/eventhandler.cpp:577
#, kde-format #, kde-format
msgid "requested an invite" msgid "requested an invite"
msgstr "" msgstr ""
#: src/eventhandler.cpp:406 #: src/eventhandler.cpp:402
#, kde-format #, kde-format
msgid "requested an invite with reason: %1" msgid "requested an invite with reason: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:410 src/eventhandler.cpp:585 #: src/eventhandler.cpp:406 src/eventhandler.cpp:581
#, kde-format #, kde-format
msgid "made something unknown" msgid "made something unknown"
msgstr "" msgstr ""
#: src/eventhandler.cpp:413 src/eventhandler.cpp:588 #: src/eventhandler.cpp:409 src/eventhandler.cpp:584
#, kde-format #, kde-format
msgid "cleared the room main alias" msgid "cleared the room main alias"
msgstr "" msgstr ""
#: src/eventhandler.cpp:413 #: src/eventhandler.cpp:409
#, kde-format #, kde-format
msgid "set the room main alias to: %1" msgid "set the room main alias to: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:416 src/eventhandler.cpp:591 #: src/eventhandler.cpp:412 src/eventhandler.cpp:587
#, kde-format #, kde-format
msgid "cleared the room name" msgid "cleared the room name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:416 #: src/eventhandler.cpp:412
#, kde-format #, kde-format
msgid "set the room name to: %1" msgid "set the room name to: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:419 src/eventhandler.cpp:594 #: src/eventhandler.cpp:415 src/eventhandler.cpp:590
#, kde-format #, kde-format
msgid "cleared the topic" msgid "cleared the topic"
msgstr "" msgstr ""
#: src/eventhandler.cpp:420 #: src/eventhandler.cpp:416
#, kde-format #, kde-format
msgid "set the topic to: %1" msgid "set the topic to: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:426 src/eventhandler.cpp:597 #: src/eventhandler.cpp:422 src/eventhandler.cpp:593
#, kde-format #, kde-format
msgid "changed the room avatar" msgid "changed the room avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:429 src/eventhandler.cpp:600 #: src/eventhandler.cpp:425 src/eventhandler.cpp:596
#, kde-format #, kde-format
msgid "activated End-to-End Encryption" msgid "activated End-to-End Encryption"
msgstr "" msgstr ""
#: src/eventhandler.cpp:433 #: src/eventhandler.cpp:429
#, kde-format #, kde-format
msgid "upgraded the room to version %1" msgid "upgraded the room to version %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:434 #: src/eventhandler.cpp:430
#, kde-format #, kde-format
msgid "created the room, version %1" msgid "created the room, version %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:437 src/eventhandler.cpp:606 #: src/eventhandler.cpp:433 src/eventhandler.cpp:602
#, kde-format #, kde-format
msgctxt "'power level' means permission level" msgctxt "'power level' means permission level"
msgid "changed the power levels for this room" msgid "changed the power levels for this room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:443 src/eventhandler.cpp:612 #: src/eventhandler.cpp:439 src/eventhandler.cpp:608
#, kde-format #, kde-format
msgid "changed the server access control lists for this room" msgid "changed the server access control lists for this room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:447 #: src/eventhandler.cpp:443
#, kde-format #, kde-format
msgctxt "[User] added <name> widget" msgctxt "[User] added <name> widget"
msgid "added %1 widget" msgid "added %1 widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:450 #: src/eventhandler.cpp:446
#, kde-format #, kde-format
msgctxt "[User] removed <name> widget" msgctxt "[User] removed <name> widget"
msgid "removed %1 widget" msgid "removed %1 widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:452 #: src/eventhandler.cpp:448
#, kde-format #, kde-format
msgctxt "[User] configured <name> widget" msgctxt "[User] configured <name> widget"
msgid "configured %1 widget" msgid "configured %1 widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:455 #: src/eventhandler.cpp:451
#, kde-format #, kde-format
msgid "updated %1 state" msgid "updated %1 state"
msgstr "" msgstr ""
#: src/eventhandler.cpp:456 #: src/eventhandler.cpp:452
#, kde-format #, kde-format
msgid "updated %1 state for %2" msgid "updated %1 state for %2"
msgstr "" msgstr ""
#: src/eventhandler.cpp:461 src/eventhandler.cpp:630 #: src/eventhandler.cpp:457 src/eventhandler.cpp:626
#, kde-format #, kde-format
msgid "Unknown event" msgid "Unknown event"
msgstr "" msgstr ""
#: src/eventhandler.cpp:476 #: src/eventhandler.cpp:472
#, kde-format #, kde-format
msgid "a file" msgid "a file"
msgstr "" msgstr ""
#: src/eventhandler.cpp:516 #: src/eventhandler.cpp:512
#, kde-format #, kde-format
msgid "sent a message" msgid "sent a message"
msgstr "" msgstr ""
#: src/eventhandler.cpp:520 #: src/eventhandler.cpp:516
#, kde-format #, kde-format
msgid "sent a sticker" msgid "sent a sticker"
msgstr "" msgstr ""
#: src/eventhandler.cpp:526 #: src/eventhandler.cpp:522
#, kde-format #, kde-format
msgid "reinvited someone to the room" msgid "reinvited someone to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:535 #: src/eventhandler.cpp:531
#, kde-format #, kde-format
msgid "invited someone to the room" msgid "invited someone to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:545 #: src/eventhandler.cpp:541
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "changed their display name" msgid "changed their display name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:567 #: src/eventhandler.cpp:563
#, kde-format #, kde-format
msgid "withdrew a user's invitation" msgid "withdrew a user's invitation"
msgstr "" msgstr ""
#: src/eventhandler.cpp:571 #: src/eventhandler.cpp:567
#, kde-format #, kde-format
msgid "unbanned a user" msgid "unbanned a user"
msgstr "" msgstr ""
#: src/eventhandler.cpp:573 #: src/eventhandler.cpp:569
#, kde-format #, kde-format
msgid "put a user out of the room" msgid "put a user out of the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:576 #: src/eventhandler.cpp:572
#, kde-format #, kde-format
msgid "banned a user from the room" msgid "banned a user from the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:588 #: src/eventhandler.cpp:584
#, kde-format #, kde-format
msgid "set the room main alias" msgid "set the room main alias"
msgstr "" msgstr ""
#: src/eventhandler.cpp:591 #: src/eventhandler.cpp:587
#, kde-format #, kde-format
msgid "set the room name" msgid "set the room name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:594 #: src/eventhandler.cpp:590
#, kde-format #, kde-format
msgid "set the topic" msgid "set the topic"
msgstr "" msgstr ""
#: src/eventhandler.cpp:603 #: src/eventhandler.cpp:599
#, kde-format #, kde-format
msgid "upgraded the room version" msgid "upgraded the room version"
msgstr "" msgstr ""
#: src/eventhandler.cpp:603 #: src/eventhandler.cpp:599
#, kde-format #, kde-format
msgid "created the room" msgid "created the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:609 #: src/eventhandler.cpp:605
#, kde-format #, kde-format
msgid "sent a live location beacon" msgid "sent a live location beacon"
msgstr "" msgstr ""
#: src/eventhandler.cpp:616 #: src/eventhandler.cpp:612
#, kde-format #, kde-format
msgid "added a widget" msgid "added a widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:619 #: src/eventhandler.cpp:615
#, kde-format #, kde-format
msgid "removed a widget" msgid "removed a widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:621 #: src/eventhandler.cpp:617
#, kde-format #, kde-format
msgid "configured a widget" msgid "configured a widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:624 #: src/eventhandler.cpp:620
#, kde-format #, kde-format
msgid "updated the state" msgid "updated the state"
msgstr "" msgstr ""
#: src/eventhandler.cpp:628 #: src/eventhandler.cpp:624
#, kde-format #, kde-format
msgid "started a poll" msgid "started a poll"
msgstr "" msgstr ""
#: src/eventhandler.cpp:1035
#, kde-format
msgid "1 user: "
msgid_plural "%1 users: "
msgstr[0] ""
msgstr[1] ""
#: src/eventhandler.cpp:1040
#, kde-format
msgctxt "A member who is not in the room has been requested."
msgid "unknown member"
msgstr ""
#: src/eventhandler.cpp:1044
#, kde-format
msgctxt "list separator"
msgid ", "
msgstr ""
#: src/filetransferpseudojob.cpp:48 #: src/filetransferpseudojob.cpp:48
#, kde-format #, kde-format
msgctxt "Job heading, like 'Copying'" msgctxt "Job heading, like 'Copying'"
@@ -1398,67 +1379,67 @@ msgstr ""
msgid "Removes the user from the room" msgid "Removes the user from the room"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:153 src/models/emojimodel.cpp:211 #: src/models/emojimodel.cpp:155 src/models/emojimodel.cpp:213
#, kde-format #, kde-format
msgctxt "Previously used emojis" msgctxt "Previously used emojis"
msgid "History" msgid "History"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:158 #: src/models/emojimodel.cpp:160
#, kde-format #, kde-format
msgctxt "'Smileys' is a category of emoji" msgctxt "'Smileys' is a category of emoji"
msgid "Smileys" msgid "Smileys"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:163 #: src/models/emojimodel.cpp:165
#, kde-format #, kde-format
msgctxt "'People' is a category of emoji" msgctxt "'People' is a category of emoji"
msgid "People" msgid "People"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:168 #: src/models/emojimodel.cpp:170
#, kde-format #, kde-format
msgctxt "'Nature' is a category of emoji" msgctxt "'Nature' is a category of emoji"
msgid "Nature" msgid "Nature"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:173 #: src/models/emojimodel.cpp:175
#, kde-format #, kde-format
msgctxt "'Food' is a category of emoji" msgctxt "'Food' is a category of emoji"
msgid "Food" msgid "Food"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:178 #: src/models/emojimodel.cpp:180
#, kde-format #, kde-format
msgctxt "'Activities' is a category of emoji" msgctxt "'Activities' is a category of emoji"
msgid "Activities" msgid "Activities"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:183 #: src/models/emojimodel.cpp:185
#, kde-format #, kde-format
msgctxt "'Travel' is a category of emoji" msgctxt "'Travel' is a category of emoji"
msgid "Travel" msgid "Travel"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:188 #: src/models/emojimodel.cpp:190
#, kde-format #, kde-format
msgctxt "'Objects' is a category of emoji" msgctxt "'Objects' is a category of emoji"
msgid "Objects" msgid "Objects"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:193 #: src/models/emojimodel.cpp:195
#, kde-format #, kde-format
msgctxt "'Symbols' is a category of emoji" msgctxt "'Symbols' is a category of emoji"
msgid "Symbols" msgid "Symbols"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:198 #: src/models/emojimodel.cpp:200
#, kde-format #, kde-format
msgctxt "'Flags' is a category of emoji" msgctxt "'Flags' is a category of emoji"
msgid "Flags" msgid "Flags"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:217 #: src/models/emojimodel.cpp:219
#, kde-format #, kde-format
msgctxt "'Custom' is a category of emoji" msgctxt "'Custom' is a category of emoji"
msgid "Custom" msgid "Custom"
@@ -1476,13 +1457,13 @@ msgctxt "As in 'The user's own emojis"
msgid "Own Emojis" msgid "Own Emojis"
msgstr "" msgstr ""
#: src/models/messagecontentmodel.cpp:216 #: src/models/messagecontentmodel.cpp:223
#: src/timeline/LinkPreviewLoadComponent.qml:66 #: src/timeline/LinkPreviewLoadComponent.qml:66
#, kde-format #, kde-format
msgid "Loading reply" msgid "Loading reply"
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:162 #: src/models/messagefiltermodel.cpp:164
#, kde-format #, kde-format
msgctxt "%1: What's being done; %2: How often it is done." msgctxt "%1: What's being done; %2: How often it is done."
msgid " %1" msgid " %1"
@@ -1490,7 +1471,7 @@ msgid_plural " %1 %2 times"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/models/messagefiltermodel.cpp:166 #: src/models/messagefiltermodel.cpp:168
#, kde-format #, kde-format
msgctxt "n users" msgctxt "n users"
msgid " %1 user " msgid " %1 user "
@@ -1498,25 +1479,25 @@ msgid_plural " %1 users "
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/models/messagefiltermodel.cpp:175 #: src/models/messagefiltermodel.cpp:177
#, kde-format #, kde-format
msgctxt "[action 1], [action 2 and/or action 3]" msgctxt "[action 1], [action 2 and/or action 3]"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:179 #: src/models/messagefiltermodel.cpp:181
#, kde-format #, kde-format
msgctxt "[action 1, action 2] or [action 3]" msgctxt "[action 1, action 2] or [action 3]"
msgid " or " msgid " or "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:179 #: src/models/messagefiltermodel.cpp:181
#, kde-format #, kde-format
msgctxt "[action 1, action 2] and [action 3]" msgctxt "[action 1, action 2] and [action 3]"
msgid " and " msgid " and "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:185 #: src/models/messagefiltermodel.cpp:187
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"userText (%1) is either a Matrix username if a single user sent all the " "userText (%1) is either a Matrix username if a single user sent all the "
@@ -1733,103 +1714,122 @@ msgid_plural "%2 reacted with %3"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/neochatconnection.cpp:85 #: src/models/readmarkermodel.cpp:110
#, kde-format
msgid "1 user: "
msgid_plural "%1 users: "
msgstr[0] ""
msgstr[1] ""
#: src/models/readmarkermodel.cpp:115
#, kde-format
msgctxt "A member who is not in the room has been requested."
msgid "unknown member"
msgstr ""
#: src/models/readmarkermodel.cpp:117
#, kde-format
msgctxt "list separator"
msgid ", "
msgstr ""
#: src/neochatconnection.cpp:86
#, kde-format #, kde-format
msgid "File too large to download." msgid "File too large to download."
msgstr "" msgstr ""
#: src/neochatconnection.cpp:85 #: src/neochatconnection.cpp:86
#, kde-format #, kde-format
msgid "Contact your matrix server administrator for support." msgid "Contact your matrix server administrator for support."
msgstr "" msgstr ""
#: src/neochatconnection.cpp:296 #: src/neochatconnection.cpp:317
#, kde-format #, kde-format
msgctxt "@info" msgctxt "@info"
msgid "No identity server configured" msgid "No identity server configured"
msgstr "" msgstr ""
#: src/neochatconnection.cpp:327 #: src/neochatconnection.cpp:348
#, kde-format #, kde-format
msgid "Room creation failed: %1" msgid "Room creation failed: %1"
msgstr "" msgstr ""
#: src/neochatconnection.cpp:364 #: src/neochatconnection.cpp:385
#, kde-format #, kde-format
msgid "Space creation failed: %1" msgid "Space creation failed: %1"
msgstr "" msgstr ""
#: src/neochatroom.cpp:1352 #: src/neochatroom.cpp:1403
#, kde-format #, kde-format
msgid "Report sent successfully." msgid "Report sent successfully."
msgstr "" msgstr ""
#: src/neochatroom.cpp:1622 src/neochatroom.cpp:1630 #: src/neochatroom.cpp:1724 src/neochatroom.cpp:1732
#, kde-format #, kde-format
msgctxt "'Lat' and 'Lon' as in Latitude and Longitude" msgctxt "'Lat' and 'Lon' as in Latitude and Longitude"
msgid "Lat: %1, Lon: %2" msgid "Lat: %1, Lon: %2"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:120 src/notificationsmanager.cpp:325 #: src/notificationsmanager.cpp:126 src/notificationsmanager.cpp:330
#, kde-format #, kde-format
msgid "Encrypted Message" msgid "Encrypted Message"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:204 src/qml/Main.qml:279 #: src/notificationsmanager.cpp:210 src/qml/Main.qml:279
#, kde-format #, kde-format
msgid "%1: %2" msgid "%1: %2"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:210 #: src/notificationsmanager.cpp:216
#, kde-format #, kde-format
msgid "Open NeoChat in this room" msgid "Open NeoChat in this room"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:223 src/qml/DelegateContextMenu.qml:98 #: src/notificationsmanager.cpp:229 src/qml/DelegateContextMenu.qml:98
#: src/qml/HoverActions.qml:111 #: src/qml/HoverActions.qml:111
#, kde-format #, kde-format
msgid "Reply" msgid "Reply"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:224 #: src/notificationsmanager.cpp:230
#, kde-format #, kde-format
msgid "Reply..." msgid "Reply..."
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:243 #: src/notificationsmanager.cpp:249
#, kde-format #, kde-format
msgid "%1 invited you to a room" msgid "%1 invited you to a room"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:247 #: src/notificationsmanager.cpp:252
#, kde-format #, kde-format
msgid "Open this invitation in NeoChat" msgid "Open this invitation in NeoChat"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:257 #: src/notificationsmanager.cpp:262
#, kde-format #, kde-format
msgctxt "@action:button The thing being accepted is an invitation to chat" msgctxt "@action:button The thing being accepted is an invitation to chat"
msgid "Accept" msgid "Accept"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:258 #: src/notificationsmanager.cpp:263
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject" msgid "Reject"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:259 #: src/notificationsmanager.cpp:264
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject and Ignore User" msgid "Reject and Ignore User"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:318 #: src/notificationsmanager.cpp:323
#, kde-format #, kde-format
msgid "%1 (%2)" msgid "%1 (%2)"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:329 #: src/notificationsmanager.cpp:334
#, kde-format #, kde-format
msgid "Open NeoChat" msgid "Open NeoChat"
msgstr "" msgstr ""
@@ -2747,18 +2747,23 @@ msgstr ""
msgid "Accept this invitation?" msgid "Accept this invitation?"
msgstr "" msgstr ""
#: src/qml/InvitationView.qml:21 #: src/qml/InvitationView.qml:18
#, kde-format
msgid "You can reject invitations from unknown users under Security settings."
msgstr ""
#: src/qml/InvitationView.qml:24
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject and ignore user" msgid "Reject and ignore user"
msgstr "" msgstr ""
#: src/qml/InvitationView.qml:30 #: src/qml/InvitationView.qml:33
#, kde-format #, kde-format
msgid "Reject" msgid "Reject"
msgstr "" msgstr ""
#: src/qml/InvitationView.qml:37 src/qml/KeyVerificationDialog.qml:92 #: src/qml/InvitationView.qml:40 src/qml/KeyVerificationDialog.qml:92
#, kde-format #, kde-format
msgid "Accept" msgid "Accept"
msgstr "" msgstr ""
@@ -3513,27 +3518,27 @@ msgctxt "'Space' is a matrix space"
msgid "Leave Space" msgid "Leave Space"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:195 #: src/qml/TimelineView.qml:196
#, kde-format #, kde-format
msgid "Jump to first unread message" msgid "Jump to first unread message"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:195 #: src/qml/TimelineView.qml:196
#, kde-format #, kde-format
msgid "Jump to oldest loaded message" msgid "Jump to oldest loaded message"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:235 #: src/qml/TimelineView.qml:236
#, kde-format #, kde-format
msgid "Jump to latest message" msgid "Jump to latest message"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:260 #: src/qml/TimelineView.qml:261
#, kde-format #, kde-format
msgid "Drag items here to share them" msgid "Drag items here to share them"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:267 #: src/qml/TimelineView.qml:268
#, kde-format #, kde-format
msgctxt "Message displayed when some users are typing" msgctxt "Message displayed when some users are typing"
msgid "%2 is typing" msgid "%2 is typing"
@@ -3920,27 +3925,27 @@ msgstr ""
msgid "Working" msgid "Working"
msgstr "" msgstr ""
#: src/roommanager.cpp:125 #: src/roommanager.cpp:138
#, kde-format #, kde-format
msgid "Malformed or empty Matrix id" msgid "Malformed or empty Matrix id"
msgstr "" msgstr ""
#: src/roommanager.cpp:125 #: src/roommanager.cpp:138
#, kde-format #, kde-format
msgid "%1 is not a correct Matrix identifier" msgid "%1 is not a correct Matrix identifier"
msgstr "" msgstr ""
#: src/roommanager.cpp:337 #: src/roommanager.cpp:345
#, kde-format #, kde-format
msgid "Failed to join room" msgid "Failed to join room"
msgstr "" msgstr ""
#: src/roommanager.cpp:369 #: src/roommanager.cpp:377
#, kde-format #, kde-format
msgid "You requested to join '%1'" msgid "You requested to join '%1'"
msgstr "" msgstr ""
#: src/roommanager.cpp:373 #: src/roommanager.cpp:381
#, kde-format #, kde-format
msgid "Failed to request joining room" msgid "Failed to request joining room"
msgstr "" msgstr ""
@@ -4339,7 +4344,7 @@ msgid "Keyword…"
msgstr "" msgstr ""
#: src/settings/GlobalNotificationsPage.qml:116 #: src/settings/GlobalNotificationsPage.qml:116
#: src/settings/Permissions.qml:391 src/settings/PushNotification.qml:119 #: src/settings/Permissions.qml:386 src/settings/PushNotification.qml:119
#, kde-format #, kde-format
msgid "Add keyword" msgid "Add keyword"
msgstr "" msgstr ""
@@ -4400,7 +4405,7 @@ msgid "Ignored Users"
msgstr "" msgstr ""
#: src/settings/IgnoredUsersDialog.qml:24 #: src/settings/IgnoredUsersDialog.qml:24
#: src/settings/NeoChatSecurityPage.qml:37 #: src/settings/NeoChatSecurityPage.qml:35
#, kde-format #, kde-format
msgctxt "@title:group" msgctxt "@title:group"
msgid "Ignored Users" msgid "Ignored Users"
@@ -4530,37 +4535,61 @@ msgstr ""
#: src/settings/NeoChatSecurityPage.qml:20 #: src/settings/NeoChatSecurityPage.qml:20
#, kde-format #, kde-format
msgctxt "@title" msgctxt "@title:group"
msgid "Keys" msgid "Invitations"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:24
#, kde-format
msgctxt "@option:check"
msgid "Reject invitations from unknown users"
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:25 #: src/settings/NeoChatSecurityPage.qml:25
#, kde-format #, kde-format
msgid "Device key" msgid ""
"If enabled, NeoChat will reject invitations from from users you don't share "
"a room with."
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:29 #: src/settings/NeoChatSecurityPage.qml:25
#, kde-format #, kde-format
msgid "Encryption key" msgid "Your server does not support this setting."
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:33 #: src/settings/NeoChatSecurityPage.qml:39
#, kde-format
msgid "Device id"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:41
#, kde-format #, kde-format
msgctxt "@action:button" msgctxt "@action:button"
msgid "Manage ignored users" msgid "Manage ignored users"
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:43 #: src/settings/NeoChatSecurityPage.qml:41
#, kde-format #, kde-format
msgctxt "@title:window" msgctxt "@title:window"
msgid "Ignored Users" msgid "Ignored Users"
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:46
#, kde-format
msgctxt "@title"
msgid "Keys"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:51
#, kde-format
msgid "Device key"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:55
#, kde-format
msgid "Encryption key"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:59
#, kde-format
msgid "Device id"
msgstr ""
#: src/settings/NeoChatSettingsView.qml:22 src/settings/RoomGeneralPage.qml:22 #: src/settings/NeoChatSettingsView.qml:22 src/settings/RoomGeneralPage.qml:22
#: src/settings/RoomSettingsView.qml:39 #: src/settings/RoomSettingsView.qml:39
#, kde-format #, kde-format
@@ -4714,27 +4743,27 @@ msgctxt "@label:textbox"
msgid "Password:" msgid "Password:"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:37 #: src/settings/Permissions.qml:32
#, kde-format #, kde-format
msgid "Privileged Users" msgid "Privileged Users"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:238 #: src/settings/Permissions.qml:233
#, kde-format #, kde-format
msgid "Default permissions" msgid "Default permissions"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:278 #: src/settings/Permissions.qml:273
#, kde-format #, kde-format
msgid "Basic permissions" msgid "Basic permissions"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:318 #: src/settings/Permissions.qml:313
#, kde-format #, kde-format
msgid "Event permissions" msgid "Event permissions"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:365 #: src/settings/Permissions.qml:360
#, kde-format #, kde-format
msgid "Event Type…" msgid "Event Type…"
msgstr "" msgstr ""
@@ -5202,14 +5231,14 @@ msgid ""
"device." "device."
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:107 src/timeline/FileComponent.qml:190 #: src/timeline/FileComponent.qml:103 src/timeline/FileComponent.qml:186
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; offers ability to download its file" "tooltip for a button on a message; offers ability to download its file"
msgid "Download" msgid "Download"
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:123 src/timeline/FileComponent.qml:180 #: src/timeline/FileComponent.qml:119 src/timeline/FileComponent.qml:176
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; offers ability to open its downloaded " "tooltip for a button on a message; offers ability to open its downloaded "
@@ -5217,13 +5246,13 @@ msgctxt ""
msgid "Open File" msgid "Open File"
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:138 #: src/timeline/FileComponent.qml:134
#, kde-format #, kde-format
msgctxt "file download progress" msgctxt "file download progress"
msgid "%1 / %2" msgid "%1 / %2"
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:143 #: src/timeline/FileComponent.qml:139
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; stops downloading the message's file" "tooltip for a button on a message; stops downloading the message's file"
@@ -5310,7 +5339,7 @@ msgctxt "as in 'this vote has ended'"
msgid "(Ended)" msgid "(Ended)"
msgstr "" msgstr ""
#: src/timeline/ReadMarkerDelegate.qml:39 #: src/timeline/ReadMarkerDelegate.qml:42
#, kde-format #, kde-format
msgctxt "Relative time since the room was last read" msgctxt "Relative time since the room was last read"
msgid "Last read: %1" msgid "Last read: %1"
@@ -5329,18 +5358,18 @@ msgstr ""
msgid "Pl. %1" msgid "Pl. %1"
msgstr "" msgstr ""
#: src/timeline/VideoComponent.qml:171 #: src/timeline/VideoComponent.qml:197
#, kde-format #, kde-format
msgid "Video" msgid "Video"
msgstr "" msgstr ""
#: src/timeline/VideoComponent.qml:235 #: src/timeline/VideoComponent.qml:261
#, kde-format #, kde-format
msgctxt "@action:button" msgctxt "@action:button"
msgid "Volume" msgid "Volume"
msgstr "" msgstr ""
#: src/timeline/VideoComponent.qml:319 #: src/timeline/VideoComponent.qml:345
#, kde-format #, kde-format
msgid "Maximize" msgid "Maximize"
msgstr "" msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

5479
po/gl/neochat.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: neochat\n" "Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2024-07-15 00:38+0000\n" "POT-Creation-Date: 2024-07-30 02:34+0000\n"
"PO-Revision-Date: 2020-11-05 23:50-0800\n" "PO-Revision-Date: 2020-11-05 23:50-0800\n"
"Last-Translator: Japanese KDE translation team <kde-jp@kde.org>\n" "Last-Translator: Japanese KDE translation team <kde-jp@kde.org>\n"
"Language-Team: Japanese <kde-jp@kde.org>\n" "Language-Team: Japanese <kde-jp@kde.org>\n"
@@ -359,7 +359,7 @@ msgid "Custom"
msgstr "" msgstr ""
#: src/enums/powerlevel.cpp:88 src/models/permissionsmodel.cpp:162 #: src/enums/powerlevel.cpp:88 src/models/permissionsmodel.cpp:162
#: src/models/userlistmodel.cpp:113 #: src/models/userlistmodel.cpp:114
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"%1 is the name of the power level, e.g. admin and %2 is the value that " "%1 is the name of the power level, e.g. admin and %2 is the value that "
@@ -367,367 +367,349 @@ msgctxt ""
msgid "%1 (%2)" msgid "%1 (%2)"
msgstr "" msgstr ""
#: src/eventhandler.cpp:304 src/eventhandler.cpp:509 #: src/eventhandler.cpp:297 src/eventhandler.cpp:505
#: src/models/messagecontentmodel.cpp:223 src/models/messageeventmodel.cpp:459 #: src/models/messagecontentmodel.cpp:230 src/models/messageeventmodel.cpp:438
#, kde-format #, kde-format
msgid "<i>[This message was deleted]</i>" msgid "<i>[This message was deleted]</i>"
msgstr "" msgstr ""
#: src/eventhandler.cpp:304 src/models/messagecontentmodel.cpp:224 #: src/eventhandler.cpp:297 src/models/messagecontentmodel.cpp:231
#: src/models/messageeventmodel.cpp:460 #: src/models/messageeventmodel.cpp:439
#, kde-format #, kde-format
msgid "<i>[This message was deleted: %1]</i>" msgid "<i>[This message was deleted: %1]</i>"
msgstr "" msgstr ""
#: src/eventhandler.cpp:335 #: src/eventhandler.cpp:331
#, kde-format #, kde-format
msgid "reinvited %1 to the room" msgid "reinvited %1 to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:337 #: src/eventhandler.cpp:333
#, kde-format #, kde-format
msgctxt "Optional reason for an invitation" msgctxt "Optional reason for an invitation"
msgid ": %1" msgid ": %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:346 src/eventhandler.cpp:533 #: src/eventhandler.cpp:342 src/eventhandler.cpp:529
#, kde-format #, kde-format
msgid "joined the room (repeated)" msgid "joined the room (repeated)"
msgstr "" msgstr ""
#: src/eventhandler.cpp:348 #: src/eventhandler.cpp:344
#, kde-format #, kde-format
msgid "invited %1 to the room" msgid "invited %1 to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:348 src/eventhandler.cpp:535 #: src/eventhandler.cpp:344 src/eventhandler.cpp:531
#, kde-format #, kde-format
msgid "joined the room" msgid "joined the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:352 #: src/eventhandler.cpp:348
#, kde-format #, kde-format
msgid ": %1" msgid ": %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:359 src/eventhandler.cpp:543 #: src/eventhandler.cpp:355 src/eventhandler.cpp:539
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "cleared their display name" msgid "cleared their display name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:362 #: src/eventhandler.cpp:358
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "changed their display name to %1" msgid "changed their display name to %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:368 src/eventhandler.cpp:550 #: src/eventhandler.cpp:364 src/eventhandler.cpp:546
#, kde-format #, kde-format
msgid " and " msgid " and "
msgstr "" msgstr ""
#: src/eventhandler.cpp:371 src/eventhandler.cpp:553 #: src/eventhandler.cpp:367 src/eventhandler.cpp:549
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "cleared their avatar" msgid "cleared their avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:373 src/eventhandler.cpp:555 #: src/eventhandler.cpp:369 src/eventhandler.cpp:551
#, kde-format #, kde-format
msgid "set an avatar" msgid "set an avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:375 src/eventhandler.cpp:557 #: src/eventhandler.cpp:371 src/eventhandler.cpp:553
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "updated their avatar" msgid "updated their avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:379 src/eventhandler.cpp:561 #: src/eventhandler.cpp:375 src/eventhandler.cpp:557
#, kde-format #, kde-format
msgctxt "<user> changed nothing" msgctxt "<user> changed nothing"
msgid "changed nothing" msgid "changed nothing"
msgstr "" msgstr ""
#: src/eventhandler.cpp:385 #: src/eventhandler.cpp:381
#, kde-format #, kde-format
msgid "withdrew %1's invitation" msgid "withdrew %1's invitation"
msgstr "" msgstr ""
#: src/eventhandler.cpp:385 src/eventhandler.cpp:567 #: src/eventhandler.cpp:381 src/eventhandler.cpp:563
#, kde-format #, kde-format
msgid "rejected the invitation" msgid "rejected the invitation"
msgstr "" msgstr ""
#: src/eventhandler.cpp:389 #: src/eventhandler.cpp:385
#, kde-format #, kde-format
msgid "unbanned %1" msgid "unbanned %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:389 src/eventhandler.cpp:571 #: src/eventhandler.cpp:385 src/eventhandler.cpp:567
#, kde-format #, kde-format
msgid "self-unbanned" msgid "self-unbanned"
msgstr "" msgstr ""
#: src/eventhandler.cpp:392 #: src/eventhandler.cpp:388
#, kde-format #, kde-format
msgid "has put %1 out of the room: %2" msgid "has put %1 out of the room: %2"
msgstr "" msgstr ""
#: src/eventhandler.cpp:393 src/eventhandler.cpp:573 #: src/eventhandler.cpp:389 src/eventhandler.cpp:569
#, kde-format #, kde-format
msgid "left the room" msgid "left the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:397 #: src/eventhandler.cpp:393
#, kde-format #, kde-format
msgid "banned %1 from the room" msgid "banned %1 from the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:399 #: src/eventhandler.cpp:395
#, kde-format #, kde-format
msgid "banned %1 from the room: %2" msgid "banned %1 from the room: %2"
msgstr "" msgstr ""
#: src/eventhandler.cpp:402 src/eventhandler.cpp:578 #: src/eventhandler.cpp:398 src/eventhandler.cpp:574
#, kde-format #, kde-format
msgid "self-banned from the room" msgid "self-banned from the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:406 src/eventhandler.cpp:581 #: src/eventhandler.cpp:402 src/eventhandler.cpp:577
#, kde-format #, kde-format
msgid "requested an invite" msgid "requested an invite"
msgstr "" msgstr ""
#: src/eventhandler.cpp:406 #: src/eventhandler.cpp:402
#, kde-format #, kde-format
msgid "requested an invite with reason: %1" msgid "requested an invite with reason: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:410 src/eventhandler.cpp:585 #: src/eventhandler.cpp:406 src/eventhandler.cpp:581
#, kde-format #, kde-format
msgid "made something unknown" msgid "made something unknown"
msgstr "" msgstr ""
#: src/eventhandler.cpp:413 src/eventhandler.cpp:588 #: src/eventhandler.cpp:409 src/eventhandler.cpp:584
#, kde-format #, kde-format
msgid "cleared the room main alias" msgid "cleared the room main alias"
msgstr "" msgstr ""
#: src/eventhandler.cpp:413 #: src/eventhandler.cpp:409
#, kde-format #, kde-format
msgid "set the room main alias to: %1" msgid "set the room main alias to: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:416 src/eventhandler.cpp:591 #: src/eventhandler.cpp:412 src/eventhandler.cpp:587
#, kde-format #, kde-format
msgid "cleared the room name" msgid "cleared the room name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:416 #: src/eventhandler.cpp:412
#, kde-format #, kde-format
msgid "set the room name to: %1" msgid "set the room name to: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:419 src/eventhandler.cpp:594 #: src/eventhandler.cpp:415 src/eventhandler.cpp:590
#, kde-format #, kde-format
msgid "cleared the topic" msgid "cleared the topic"
msgstr "" msgstr ""
#: src/eventhandler.cpp:420 #: src/eventhandler.cpp:416
#, kde-format #, kde-format
msgid "set the topic to: %1" msgid "set the topic to: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:426 src/eventhandler.cpp:597 #: src/eventhandler.cpp:422 src/eventhandler.cpp:593
#, kde-format #, kde-format
msgid "changed the room avatar" msgid "changed the room avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:429 src/eventhandler.cpp:600 #: src/eventhandler.cpp:425 src/eventhandler.cpp:596
#, kde-format #, kde-format
msgid "activated End-to-End Encryption" msgid "activated End-to-End Encryption"
msgstr "" msgstr ""
#: src/eventhandler.cpp:433 #: src/eventhandler.cpp:429
#, kde-format #, kde-format
msgid "upgraded the room to version %1" msgid "upgraded the room to version %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:434 #: src/eventhandler.cpp:430
#, kde-format #, kde-format
msgid "created the room, version %1" msgid "created the room, version %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:437 src/eventhandler.cpp:606 #: src/eventhandler.cpp:433 src/eventhandler.cpp:602
#, kde-format #, kde-format
msgctxt "'power level' means permission level" msgctxt "'power level' means permission level"
msgid "changed the power levels for this room" msgid "changed the power levels for this room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:443 src/eventhandler.cpp:612 #: src/eventhandler.cpp:439 src/eventhandler.cpp:608
#, kde-format #, kde-format
msgid "changed the server access control lists for this room" msgid "changed the server access control lists for this room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:447 #: src/eventhandler.cpp:443
#, kde-format #, kde-format
msgctxt "[User] added <name> widget" msgctxt "[User] added <name> widget"
msgid "added %1 widget" msgid "added %1 widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:450 #: src/eventhandler.cpp:446
#, kde-format #, kde-format
msgctxt "[User] removed <name> widget" msgctxt "[User] removed <name> widget"
msgid "removed %1 widget" msgid "removed %1 widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:452 #: src/eventhandler.cpp:448
#, kde-format #, kde-format
msgctxt "[User] configured <name> widget" msgctxt "[User] configured <name> widget"
msgid "configured %1 widget" msgid "configured %1 widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:455 #: src/eventhandler.cpp:451
#, kde-format #, kde-format
msgid "updated %1 state" msgid "updated %1 state"
msgstr "" msgstr ""
#: src/eventhandler.cpp:456 #: src/eventhandler.cpp:452
#, kde-format #, kde-format
msgid "updated %1 state for %2" msgid "updated %1 state for %2"
msgstr "" msgstr ""
#: src/eventhandler.cpp:461 src/eventhandler.cpp:630 #: src/eventhandler.cpp:457 src/eventhandler.cpp:626
#, kde-format #, kde-format
msgid "Unknown event" msgid "Unknown event"
msgstr "" msgstr ""
#: src/eventhandler.cpp:476 #: src/eventhandler.cpp:472
#, kde-format #, kde-format
msgid "a file" msgid "a file"
msgstr "" msgstr ""
#: src/eventhandler.cpp:516 #: src/eventhandler.cpp:512
#, kde-format #, kde-format
msgid "sent a message" msgid "sent a message"
msgstr "" msgstr ""
#: src/eventhandler.cpp:520 #: src/eventhandler.cpp:516
#, kde-format #, kde-format
msgid "sent a sticker" msgid "sent a sticker"
msgstr "" msgstr ""
#: src/eventhandler.cpp:526 #: src/eventhandler.cpp:522
#, kde-format #, kde-format
msgid "reinvited someone to the room" msgid "reinvited someone to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:535 #: src/eventhandler.cpp:531
#, kde-format #, kde-format
msgid "invited someone to the room" msgid "invited someone to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:545 #: src/eventhandler.cpp:541
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "changed their display name" msgid "changed their display name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:567 #: src/eventhandler.cpp:563
#, kde-format #, kde-format
msgid "withdrew a user's invitation" msgid "withdrew a user's invitation"
msgstr "" msgstr ""
#: src/eventhandler.cpp:571 #: src/eventhandler.cpp:567
#, kde-format #, kde-format
msgid "unbanned a user" msgid "unbanned a user"
msgstr "" msgstr ""
#: src/eventhandler.cpp:573 #: src/eventhandler.cpp:569
#, kde-format #, kde-format
msgid "put a user out of the room" msgid "put a user out of the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:576 #: src/eventhandler.cpp:572
#, kde-format #, kde-format
msgid "banned a user from the room" msgid "banned a user from the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:588 #: src/eventhandler.cpp:584
#, kde-format #, kde-format
msgid "set the room main alias" msgid "set the room main alias"
msgstr "" msgstr ""
#: src/eventhandler.cpp:591 #: src/eventhandler.cpp:587
#, kde-format #, kde-format
msgid "set the room name" msgid "set the room name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:594 #: src/eventhandler.cpp:590
#, kde-format #, kde-format
msgid "set the topic" msgid "set the topic"
msgstr "" msgstr ""
#: src/eventhandler.cpp:603 #: src/eventhandler.cpp:599
#, kde-format #, kde-format
msgid "upgraded the room version" msgid "upgraded the room version"
msgstr "" msgstr ""
#: src/eventhandler.cpp:603 #: src/eventhandler.cpp:599
#, kde-format #, kde-format
msgid "created the room" msgid "created the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:609 #: src/eventhandler.cpp:605
#, kde-format #, kde-format
msgid "sent a live location beacon" msgid "sent a live location beacon"
msgstr "" msgstr ""
#: src/eventhandler.cpp:616 #: src/eventhandler.cpp:612
#, kde-format #, kde-format
msgid "added a widget" msgid "added a widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:619 #: src/eventhandler.cpp:615
#, kde-format #, kde-format
msgid "removed a widget" msgid "removed a widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:621 #: src/eventhandler.cpp:617
#, kde-format #, kde-format
msgid "configured a widget" msgid "configured a widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:624 #: src/eventhandler.cpp:620
#, kde-format #, kde-format
msgid "updated the state" msgid "updated the state"
msgstr "" msgstr ""
#: src/eventhandler.cpp:628 #: src/eventhandler.cpp:624
#, kde-format #, kde-format
msgid "started a poll" msgid "started a poll"
msgstr "" msgstr ""
#: src/eventhandler.cpp:1035
#, kde-format
msgid "1 user: "
msgid_plural "%1 users: "
msgstr[0] ""
#: src/eventhandler.cpp:1040
#, kde-format
msgctxt "A member who is not in the room has been requested."
msgid "unknown member"
msgstr ""
#: src/eventhandler.cpp:1044
#, kde-format
msgctxt "list separator"
msgid ", "
msgstr ""
#: src/filetransferpseudojob.cpp:48 #: src/filetransferpseudojob.cpp:48
#, kde-format #, kde-format
msgctxt "Job heading, like 'Copying'" msgctxt "Job heading, like 'Copying'"
@@ -1393,67 +1375,67 @@ msgstr ""
msgid "Removes the user from the room" msgid "Removes the user from the room"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:153 src/models/emojimodel.cpp:211 #: src/models/emojimodel.cpp:155 src/models/emojimodel.cpp:213
#, kde-format #, kde-format
msgctxt "Previously used emojis" msgctxt "Previously used emojis"
msgid "History" msgid "History"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:158 #: src/models/emojimodel.cpp:160
#, kde-format #, kde-format
msgctxt "'Smileys' is a category of emoji" msgctxt "'Smileys' is a category of emoji"
msgid "Smileys" msgid "Smileys"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:163 #: src/models/emojimodel.cpp:165
#, kde-format #, kde-format
msgctxt "'People' is a category of emoji" msgctxt "'People' is a category of emoji"
msgid "People" msgid "People"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:168 #: src/models/emojimodel.cpp:170
#, kde-format #, kde-format
msgctxt "'Nature' is a category of emoji" msgctxt "'Nature' is a category of emoji"
msgid "Nature" msgid "Nature"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:173 #: src/models/emojimodel.cpp:175
#, kde-format #, kde-format
msgctxt "'Food' is a category of emoji" msgctxt "'Food' is a category of emoji"
msgid "Food" msgid "Food"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:178 #: src/models/emojimodel.cpp:180
#, kde-format #, kde-format
msgctxt "'Activities' is a category of emoji" msgctxt "'Activities' is a category of emoji"
msgid "Activities" msgid "Activities"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:183 #: src/models/emojimodel.cpp:185
#, kde-format #, kde-format
msgctxt "'Travel' is a category of emoji" msgctxt "'Travel' is a category of emoji"
msgid "Travel" msgid "Travel"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:188 #: src/models/emojimodel.cpp:190
#, kde-format #, kde-format
msgctxt "'Objects' is a category of emoji" msgctxt "'Objects' is a category of emoji"
msgid "Objects" msgid "Objects"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:193 #: src/models/emojimodel.cpp:195
#, kde-format #, kde-format
msgctxt "'Symbols' is a category of emoji" msgctxt "'Symbols' is a category of emoji"
msgid "Symbols" msgid "Symbols"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:198 #: src/models/emojimodel.cpp:200
#, kde-format #, kde-format
msgctxt "'Flags' is a category of emoji" msgctxt "'Flags' is a category of emoji"
msgid "Flags" msgid "Flags"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:217 #: src/models/emojimodel.cpp:219
#, kde-format #, kde-format
msgctxt "'Custom' is a category of emoji" msgctxt "'Custom' is a category of emoji"
msgid "Custom" msgid "Custom"
@@ -1471,45 +1453,45 @@ msgctxt "As in 'The user's own emojis"
msgid "Own Emojis" msgid "Own Emojis"
msgstr "" msgstr ""
#: src/models/messagecontentmodel.cpp:216 #: src/models/messagecontentmodel.cpp:223
#: src/timeline/LinkPreviewLoadComponent.qml:66 #: src/timeline/LinkPreviewLoadComponent.qml:66
#, kde-format #, kde-format
msgid "Loading reply" msgid "Loading reply"
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:162 #: src/models/messagefiltermodel.cpp:164
#, kde-format #, kde-format
msgctxt "%1: What's being done; %2: How often it is done." msgctxt "%1: What's being done; %2: How often it is done."
msgid " %1" msgid " %1"
msgid_plural " %1 %2 times" msgid_plural " %1 %2 times"
msgstr[0] "" msgstr[0] ""
#: src/models/messagefiltermodel.cpp:166 #: src/models/messagefiltermodel.cpp:168
#, kde-format #, kde-format
msgctxt "n users" msgctxt "n users"
msgid " %1 user " msgid " %1 user "
msgid_plural " %1 users " msgid_plural " %1 users "
msgstr[0] "" msgstr[0] ""
#: src/models/messagefiltermodel.cpp:175 #: src/models/messagefiltermodel.cpp:177
#, kde-format #, kde-format
msgctxt "[action 1], [action 2 and/or action 3]" msgctxt "[action 1], [action 2 and/or action 3]"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:179 #: src/models/messagefiltermodel.cpp:181
#, kde-format #, kde-format
msgctxt "[action 1, action 2] or [action 3]" msgctxt "[action 1, action 2] or [action 3]"
msgid " or " msgid " or "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:179 #: src/models/messagefiltermodel.cpp:181
#, kde-format #, kde-format
msgctxt "[action 1, action 2] and [action 3]" msgctxt "[action 1, action 2] and [action 3]"
msgid " and " msgid " and "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:185 #: src/models/messagefiltermodel.cpp:187
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"userText (%1) is either a Matrix username if a single user sent all the " "userText (%1) is either a Matrix username if a single user sent all the "
@@ -1724,103 +1706,121 @@ msgid "%2 reacted with %3"
msgid_plural "%2 reacted with %3" msgid_plural "%2 reacted with %3"
msgstr[0] "" msgstr[0] ""
#: src/neochatconnection.cpp:85 #: src/models/readmarkermodel.cpp:110
#, kde-format
msgid "1 user: "
msgid_plural "%1 users: "
msgstr[0] ""
#: src/models/readmarkermodel.cpp:115
#, kde-format
msgctxt "A member who is not in the room has been requested."
msgid "unknown member"
msgstr ""
#: src/models/readmarkermodel.cpp:117
#, kde-format
msgctxt "list separator"
msgid ", "
msgstr ""
#: src/neochatconnection.cpp:86
#, kde-format #, kde-format
msgid "File too large to download." msgid "File too large to download."
msgstr "" msgstr ""
#: src/neochatconnection.cpp:85 #: src/neochatconnection.cpp:86
#, kde-format #, kde-format
msgid "Contact your matrix server administrator for support." msgid "Contact your matrix server administrator for support."
msgstr "" msgstr ""
#: src/neochatconnection.cpp:296 #: src/neochatconnection.cpp:317
#, kde-format #, kde-format
msgctxt "@info" msgctxt "@info"
msgid "No identity server configured" msgid "No identity server configured"
msgstr "" msgstr ""
#: src/neochatconnection.cpp:327 #: src/neochatconnection.cpp:348
#, kde-format #, kde-format
msgid "Room creation failed: %1" msgid "Room creation failed: %1"
msgstr "" msgstr ""
#: src/neochatconnection.cpp:364 #: src/neochatconnection.cpp:385
#, kde-format #, kde-format
msgid "Space creation failed: %1" msgid "Space creation failed: %1"
msgstr "" msgstr ""
#: src/neochatroom.cpp:1352 #: src/neochatroom.cpp:1403
#, kde-format #, kde-format
msgid "Report sent successfully." msgid "Report sent successfully."
msgstr "" msgstr ""
#: src/neochatroom.cpp:1622 src/neochatroom.cpp:1630 #: src/neochatroom.cpp:1724 src/neochatroom.cpp:1732
#, kde-format #, kde-format
msgctxt "'Lat' and 'Lon' as in Latitude and Longitude" msgctxt "'Lat' and 'Lon' as in Latitude and Longitude"
msgid "Lat: %1, Lon: %2" msgid "Lat: %1, Lon: %2"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:120 src/notificationsmanager.cpp:325 #: src/notificationsmanager.cpp:126 src/notificationsmanager.cpp:330
#, kde-format #, kde-format
msgid "Encrypted Message" msgid "Encrypted Message"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:204 src/qml/Main.qml:279 #: src/notificationsmanager.cpp:210 src/qml/Main.qml:279
#, kde-format #, kde-format
msgid "%1: %2" msgid "%1: %2"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:210 #: src/notificationsmanager.cpp:216
#, kde-format #, kde-format
msgid "Open NeoChat in this room" msgid "Open NeoChat in this room"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:223 src/qml/DelegateContextMenu.qml:98 #: src/notificationsmanager.cpp:229 src/qml/DelegateContextMenu.qml:98
#: src/qml/HoverActions.qml:111 #: src/qml/HoverActions.qml:111
#, kde-format #, kde-format
msgid "Reply" msgid "Reply"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:224 #: src/notificationsmanager.cpp:230
#, kde-format #, kde-format
msgid "Reply..." msgid "Reply..."
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:243 #: src/notificationsmanager.cpp:249
#, kde-format #, kde-format
msgid "%1 invited you to a room" msgid "%1 invited you to a room"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:247 #: src/notificationsmanager.cpp:252
#, kde-format #, kde-format
msgid "Open this invitation in NeoChat" msgid "Open this invitation in NeoChat"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:257 #: src/notificationsmanager.cpp:262
#, kde-format #, kde-format
msgctxt "@action:button The thing being accepted is an invitation to chat" msgctxt "@action:button The thing being accepted is an invitation to chat"
msgid "Accept" msgid "Accept"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:258 #: src/notificationsmanager.cpp:263
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject" msgid "Reject"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:259 #: src/notificationsmanager.cpp:264
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject and Ignore User" msgid "Reject and Ignore User"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:318 #: src/notificationsmanager.cpp:323
#, kde-format #, kde-format
msgid "%1 (%2)" msgid "%1 (%2)"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:329 #: src/notificationsmanager.cpp:334
#, kde-format #, kde-format
msgid "Open NeoChat" msgid "Open NeoChat"
msgstr "" msgstr ""
@@ -2738,18 +2738,23 @@ msgstr ""
msgid "Accept this invitation?" msgid "Accept this invitation?"
msgstr "" msgstr ""
#: src/qml/InvitationView.qml:21 #: src/qml/InvitationView.qml:18
#, kde-format
msgid "You can reject invitations from unknown users under Security settings."
msgstr ""
#: src/qml/InvitationView.qml:24
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject and ignore user" msgid "Reject and ignore user"
msgstr "" msgstr ""
#: src/qml/InvitationView.qml:30 #: src/qml/InvitationView.qml:33
#, kde-format #, kde-format
msgid "Reject" msgid "Reject"
msgstr "" msgstr ""
#: src/qml/InvitationView.qml:37 src/qml/KeyVerificationDialog.qml:92 #: src/qml/InvitationView.qml:40 src/qml/KeyVerificationDialog.qml:92
#, kde-format #, kde-format
msgid "Accept" msgid "Accept"
msgstr "" msgstr ""
@@ -3501,27 +3506,27 @@ msgctxt "'Space' is a matrix space"
msgid "Leave Space" msgid "Leave Space"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:195 #: src/qml/TimelineView.qml:196
#, kde-format #, kde-format
msgid "Jump to first unread message" msgid "Jump to first unread message"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:195 #: src/qml/TimelineView.qml:196
#, kde-format #, kde-format
msgid "Jump to oldest loaded message" msgid "Jump to oldest loaded message"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:235 #: src/qml/TimelineView.qml:236
#, kde-format #, kde-format
msgid "Jump to latest message" msgid "Jump to latest message"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:260 #: src/qml/TimelineView.qml:261
#, kde-format #, kde-format
msgid "Drag items here to share them" msgid "Drag items here to share them"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:267 #: src/qml/TimelineView.qml:268
#, kde-format #, kde-format
msgctxt "Message displayed when some users are typing" msgctxt "Message displayed when some users are typing"
msgid "%2 is typing" msgid "%2 is typing"
@@ -3907,27 +3912,27 @@ msgstr ""
msgid "Working" msgid "Working"
msgstr "" msgstr ""
#: src/roommanager.cpp:125 #: src/roommanager.cpp:138
#, kde-format #, kde-format
msgid "Malformed or empty Matrix id" msgid "Malformed or empty Matrix id"
msgstr "" msgstr ""
#: src/roommanager.cpp:125 #: src/roommanager.cpp:138
#, kde-format #, kde-format
msgid "%1 is not a correct Matrix identifier" msgid "%1 is not a correct Matrix identifier"
msgstr "" msgstr ""
#: src/roommanager.cpp:337 #: src/roommanager.cpp:345
#, kde-format #, kde-format
msgid "Failed to join room" msgid "Failed to join room"
msgstr "" msgstr ""
#: src/roommanager.cpp:369 #: src/roommanager.cpp:377
#, kde-format #, kde-format
msgid "You requested to join '%1'" msgid "You requested to join '%1'"
msgstr "" msgstr ""
#: src/roommanager.cpp:373 #: src/roommanager.cpp:381
#, kde-format #, kde-format
msgid "Failed to request joining room" msgid "Failed to request joining room"
msgstr "" msgstr ""
@@ -4326,7 +4331,7 @@ msgid "Keyword…"
msgstr "" msgstr ""
#: src/settings/GlobalNotificationsPage.qml:116 #: src/settings/GlobalNotificationsPage.qml:116
#: src/settings/Permissions.qml:391 src/settings/PushNotification.qml:119 #: src/settings/Permissions.qml:386 src/settings/PushNotification.qml:119
#, kde-format #, kde-format
msgid "Add keyword" msgid "Add keyword"
msgstr "" msgstr ""
@@ -4387,7 +4392,7 @@ msgid "Ignored Users"
msgstr "" msgstr ""
#: src/settings/IgnoredUsersDialog.qml:24 #: src/settings/IgnoredUsersDialog.qml:24
#: src/settings/NeoChatSecurityPage.qml:37 #: src/settings/NeoChatSecurityPage.qml:35
#, kde-format #, kde-format
msgctxt "@title:group" msgctxt "@title:group"
msgid "Ignored Users" msgid "Ignored Users"
@@ -4517,37 +4522,61 @@ msgstr ""
#: src/settings/NeoChatSecurityPage.qml:20 #: src/settings/NeoChatSecurityPage.qml:20
#, kde-format #, kde-format
msgctxt "@title" msgctxt "@title:group"
msgid "Keys" msgid "Invitations"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:24
#, kde-format
msgctxt "@option:check"
msgid "Reject invitations from unknown users"
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:25 #: src/settings/NeoChatSecurityPage.qml:25
#, kde-format #, kde-format
msgid "Device key" msgid ""
"If enabled, NeoChat will reject invitations from from users you don't share "
"a room with."
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:29 #: src/settings/NeoChatSecurityPage.qml:25
#, kde-format #, kde-format
msgid "Encryption key" msgid "Your server does not support this setting."
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:33 #: src/settings/NeoChatSecurityPage.qml:39
#, kde-format
msgid "Device id"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:41
#, kde-format #, kde-format
msgctxt "@action:button" msgctxt "@action:button"
msgid "Manage ignored users" msgid "Manage ignored users"
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:43 #: src/settings/NeoChatSecurityPage.qml:41
#, kde-format #, kde-format
msgctxt "@title:window" msgctxt "@title:window"
msgid "Ignored Users" msgid "Ignored Users"
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:46
#, kde-format
msgctxt "@title"
msgid "Keys"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:51
#, kde-format
msgid "Device key"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:55
#, kde-format
msgid "Encryption key"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:59
#, kde-format
msgid "Device id"
msgstr ""
#: src/settings/NeoChatSettingsView.qml:22 src/settings/RoomGeneralPage.qml:22 #: src/settings/NeoChatSettingsView.qml:22 src/settings/RoomGeneralPage.qml:22
#: src/settings/RoomSettingsView.qml:39 #: src/settings/RoomSettingsView.qml:39
#, kde-format #, kde-format
@@ -4701,27 +4730,27 @@ msgctxt "@label:textbox"
msgid "Password:" msgid "Password:"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:37 #: src/settings/Permissions.qml:32
#, kde-format #, kde-format
msgid "Privileged Users" msgid "Privileged Users"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:238 #: src/settings/Permissions.qml:233
#, kde-format #, kde-format
msgid "Default permissions" msgid "Default permissions"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:278 #: src/settings/Permissions.qml:273
#, kde-format #, kde-format
msgid "Basic permissions" msgid "Basic permissions"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:318 #: src/settings/Permissions.qml:313
#, kde-format #, kde-format
msgid "Event permissions" msgid "Event permissions"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:365 #: src/settings/Permissions.qml:360
#, kde-format #, kde-format
msgid "Event Type…" msgid "Event Type…"
msgstr "" msgstr ""
@@ -5189,14 +5218,14 @@ msgid ""
"device." "device."
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:107 src/timeline/FileComponent.qml:190 #: src/timeline/FileComponent.qml:103 src/timeline/FileComponent.qml:186
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; offers ability to download its file" "tooltip for a button on a message; offers ability to download its file"
msgid "Download" msgid "Download"
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:123 src/timeline/FileComponent.qml:180 #: src/timeline/FileComponent.qml:119 src/timeline/FileComponent.qml:176
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; offers ability to open its downloaded " "tooltip for a button on a message; offers ability to open its downloaded "
@@ -5204,13 +5233,13 @@ msgctxt ""
msgid "Open File" msgid "Open File"
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:138 #: src/timeline/FileComponent.qml:134
#, kde-format #, kde-format
msgctxt "file download progress" msgctxt "file download progress"
msgid "%1 / %2" msgid "%1 / %2"
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:143 #: src/timeline/FileComponent.qml:139
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; stops downloading the message's file" "tooltip for a button on a message; stops downloading the message's file"
@@ -5296,7 +5325,7 @@ msgctxt "as in 'this vote has ended'"
msgid "(Ended)" msgid "(Ended)"
msgstr "" msgstr ""
#: src/timeline/ReadMarkerDelegate.qml:39 #: src/timeline/ReadMarkerDelegate.qml:42
#, kde-format #, kde-format
msgctxt "Relative time since the room was last read" msgctxt "Relative time since the room was last read"
msgid "Last read: %1" msgid "Last read: %1"
@@ -5315,18 +5344,18 @@ msgstr ""
msgid "Pl. %1" msgid "Pl. %1"
msgstr "" msgstr ""
#: src/timeline/VideoComponent.qml:171 #: src/timeline/VideoComponent.qml:197
#, kde-format #, kde-format
msgid "Video" msgid "Video"
msgstr "" msgstr ""
#: src/timeline/VideoComponent.qml:235 #: src/timeline/VideoComponent.qml:261
#, kde-format #, kde-format
msgctxt "@action:button" msgctxt "@action:button"
msgid "Volume" msgid "Volume"
msgstr "" msgstr ""
#: src/timeline/VideoComponent.qml:319 #: src/timeline/VideoComponent.qml:345
#, kde-format #, kde-format
msgid "Maximize" msgid "Maximize"
msgstr "" msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: neochat\n" "Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2024-07-15 00:38+0000\n" "POT-Creation-Date: 2024-07-30 02:34+0000\n"
"PO-Revision-Date: 2023-02-25 01:00+0000\n" "PO-Revision-Date: 2023-02-25 01:00+0000\n"
"Last-Translator: Automatically generated\n" "Last-Translator: Automatically generated\n"
"Language-Team: none\n" "Language-Team: none\n"
@@ -366,7 +366,7 @@ msgid "Custom"
msgstr "" msgstr ""
#: src/enums/powerlevel.cpp:88 src/models/permissionsmodel.cpp:162 #: src/enums/powerlevel.cpp:88 src/models/permissionsmodel.cpp:162
#: src/models/userlistmodel.cpp:113 #: src/models/userlistmodel.cpp:114
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"%1 is the name of the power level, e.g. admin and %2 is the value that " "%1 is the name of the power level, e.g. admin and %2 is the value that "
@@ -374,370 +374,349 @@ msgctxt ""
msgid "%1 (%2)" msgid "%1 (%2)"
msgstr "" msgstr ""
#: src/eventhandler.cpp:304 src/eventhandler.cpp:509 #: src/eventhandler.cpp:297 src/eventhandler.cpp:505
#: src/models/messagecontentmodel.cpp:223 src/models/messageeventmodel.cpp:459 #: src/models/messagecontentmodel.cpp:230 src/models/messageeventmodel.cpp:438
#, kde-format #, kde-format
msgid "<i>[This message was deleted]</i>" msgid "<i>[This message was deleted]</i>"
msgstr "" msgstr ""
#: src/eventhandler.cpp:304 src/models/messagecontentmodel.cpp:224 #: src/eventhandler.cpp:297 src/models/messagecontentmodel.cpp:231
#: src/models/messageeventmodel.cpp:460 #: src/models/messageeventmodel.cpp:439
#, kde-format #, kde-format
msgid "<i>[This message was deleted: %1]</i>" msgid "<i>[This message was deleted: %1]</i>"
msgstr "" msgstr ""
#: src/eventhandler.cpp:335 #: src/eventhandler.cpp:331
#, kde-format #, kde-format
msgid "reinvited %1 to the room" msgid "reinvited %1 to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:337 #: src/eventhandler.cpp:333
#, kde-format #, kde-format
msgctxt "Optional reason for an invitation" msgctxt "Optional reason for an invitation"
msgid ": %1" msgid ": %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:346 src/eventhandler.cpp:533 #: src/eventhandler.cpp:342 src/eventhandler.cpp:529
#, kde-format #, kde-format
msgid "joined the room (repeated)" msgid "joined the room (repeated)"
msgstr "" msgstr ""
#: src/eventhandler.cpp:348 #: src/eventhandler.cpp:344
#, kde-format #, kde-format
msgid "invited %1 to the room" msgid "invited %1 to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:348 src/eventhandler.cpp:535 #: src/eventhandler.cpp:344 src/eventhandler.cpp:531
#, kde-format #, kde-format
msgid "joined the room" msgid "joined the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:352 #: src/eventhandler.cpp:348
#, kde-format #, kde-format
msgid ": %1" msgid ": %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:359 src/eventhandler.cpp:543 #: src/eventhandler.cpp:355 src/eventhandler.cpp:539
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "cleared their display name" msgid "cleared their display name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:362 #: src/eventhandler.cpp:358
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "changed their display name to %1" msgid "changed their display name to %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:368 src/eventhandler.cpp:550 #: src/eventhandler.cpp:364 src/eventhandler.cpp:546
#, kde-format #, kde-format
msgid " and " msgid " and "
msgstr "" msgstr ""
#: src/eventhandler.cpp:371 src/eventhandler.cpp:553 #: src/eventhandler.cpp:367 src/eventhandler.cpp:549
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "cleared their avatar" msgid "cleared their avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:373 src/eventhandler.cpp:555 #: src/eventhandler.cpp:369 src/eventhandler.cpp:551
#, kde-format #, kde-format
msgid "set an avatar" msgid "set an avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:375 src/eventhandler.cpp:557 #: src/eventhandler.cpp:371 src/eventhandler.cpp:553
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "updated their avatar" msgid "updated their avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:379 src/eventhandler.cpp:561 #: src/eventhandler.cpp:375 src/eventhandler.cpp:557
#, kde-format #, kde-format
msgctxt "<user> changed nothing" msgctxt "<user> changed nothing"
msgid "changed nothing" msgid "changed nothing"
msgstr "" msgstr ""
#: src/eventhandler.cpp:385 #: src/eventhandler.cpp:381
#, kde-format #, kde-format
msgid "withdrew %1's invitation" msgid "withdrew %1's invitation"
msgstr "" msgstr ""
#: src/eventhandler.cpp:385 src/eventhandler.cpp:567 #: src/eventhandler.cpp:381 src/eventhandler.cpp:563
#, kde-format #, kde-format
msgid "rejected the invitation" msgid "rejected the invitation"
msgstr "" msgstr ""
#: src/eventhandler.cpp:389 #: src/eventhandler.cpp:385
#, kde-format #, kde-format
msgid "unbanned %1" msgid "unbanned %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:389 src/eventhandler.cpp:571 #: src/eventhandler.cpp:385 src/eventhandler.cpp:567
#, kde-format #, kde-format
msgid "self-unbanned" msgid "self-unbanned"
msgstr "" msgstr ""
#: src/eventhandler.cpp:392 #: src/eventhandler.cpp:388
#, kde-format #, kde-format
msgid "has put %1 out of the room: %2" msgid "has put %1 out of the room: %2"
msgstr "" msgstr ""
#: src/eventhandler.cpp:393 src/eventhandler.cpp:573 #: src/eventhandler.cpp:389 src/eventhandler.cpp:569
#, kde-format #, kde-format
msgid "left the room" msgid "left the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:397 #: src/eventhandler.cpp:393
#, kde-format #, kde-format
msgid "banned %1 from the room" msgid "banned %1 from the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:399 #: src/eventhandler.cpp:395
#, kde-format #, kde-format
msgid "banned %1 from the room: %2" msgid "banned %1 from the room: %2"
msgstr "" msgstr ""
#: src/eventhandler.cpp:402 src/eventhandler.cpp:578 #: src/eventhandler.cpp:398 src/eventhandler.cpp:574
#, kde-format #, kde-format
msgid "self-banned from the room" msgid "self-banned from the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:406 src/eventhandler.cpp:581 #: src/eventhandler.cpp:402 src/eventhandler.cpp:577
#, kde-format #, kde-format
msgid "requested an invite" msgid "requested an invite"
msgstr "" msgstr ""
#: src/eventhandler.cpp:406 #: src/eventhandler.cpp:402
#, kde-format #, kde-format
msgid "requested an invite with reason: %1" msgid "requested an invite with reason: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:410 src/eventhandler.cpp:585 #: src/eventhandler.cpp:406 src/eventhandler.cpp:581
#, kde-format #, kde-format
msgid "made something unknown" msgid "made something unknown"
msgstr "" msgstr ""
#: src/eventhandler.cpp:413 src/eventhandler.cpp:588 #: src/eventhandler.cpp:409 src/eventhandler.cpp:584
#, kde-format #, kde-format
msgid "cleared the room main alias" msgid "cleared the room main alias"
msgstr "" msgstr ""
#: src/eventhandler.cpp:413 #: src/eventhandler.cpp:409
#, kde-format #, kde-format
msgid "set the room main alias to: %1" msgid "set the room main alias to: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:416 src/eventhandler.cpp:591 #: src/eventhandler.cpp:412 src/eventhandler.cpp:587
#, kde-format #, kde-format
msgid "cleared the room name" msgid "cleared the room name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:416 #: src/eventhandler.cpp:412
#, kde-format #, kde-format
msgid "set the room name to: %1" msgid "set the room name to: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:419 src/eventhandler.cpp:594 #: src/eventhandler.cpp:415 src/eventhandler.cpp:590
#, kde-format #, kde-format
msgid "cleared the topic" msgid "cleared the topic"
msgstr "" msgstr ""
#: src/eventhandler.cpp:420 #: src/eventhandler.cpp:416
#, kde-format #, kde-format
msgid "set the topic to: %1" msgid "set the topic to: %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:426 src/eventhandler.cpp:597 #: src/eventhandler.cpp:422 src/eventhandler.cpp:593
#, kde-format #, kde-format
msgid "changed the room avatar" msgid "changed the room avatar"
msgstr "" msgstr ""
#: src/eventhandler.cpp:429 src/eventhandler.cpp:600 #: src/eventhandler.cpp:425 src/eventhandler.cpp:596
#, kde-format #, kde-format
msgid "activated End-to-End Encryption" msgid "activated End-to-End Encryption"
msgstr "" msgstr ""
#: src/eventhandler.cpp:433 #: src/eventhandler.cpp:429
#, kde-format #, kde-format
msgid "upgraded the room to version %1" msgid "upgraded the room to version %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:434 #: src/eventhandler.cpp:430
#, kde-format #, kde-format
msgid "created the room, version %1" msgid "created the room, version %1"
msgstr "" msgstr ""
#: src/eventhandler.cpp:437 src/eventhandler.cpp:606 #: src/eventhandler.cpp:433 src/eventhandler.cpp:602
#, kde-format #, kde-format
msgctxt "'power level' means permission level" msgctxt "'power level' means permission level"
msgid "changed the power levels for this room" msgid "changed the power levels for this room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:443 src/eventhandler.cpp:612 #: src/eventhandler.cpp:439 src/eventhandler.cpp:608
#, kde-format #, kde-format
msgid "changed the server access control lists for this room" msgid "changed the server access control lists for this room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:447 #: src/eventhandler.cpp:443
#, kde-format #, kde-format
msgctxt "[User] added <name> widget" msgctxt "[User] added <name> widget"
msgid "added %1 widget" msgid "added %1 widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:450 #: src/eventhandler.cpp:446
#, kde-format #, kde-format
msgctxt "[User] removed <name> widget" msgctxt "[User] removed <name> widget"
msgid "removed %1 widget" msgid "removed %1 widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:452 #: src/eventhandler.cpp:448
#, kde-format #, kde-format
msgctxt "[User] configured <name> widget" msgctxt "[User] configured <name> widget"
msgid "configured %1 widget" msgid "configured %1 widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:455 #: src/eventhandler.cpp:451
#, kde-format #, kde-format
msgid "updated %1 state" msgid "updated %1 state"
msgstr "" msgstr ""
#: src/eventhandler.cpp:456 #: src/eventhandler.cpp:452
#, kde-format #, kde-format
msgid "updated %1 state for %2" msgid "updated %1 state for %2"
msgstr "" msgstr ""
#: src/eventhandler.cpp:461 src/eventhandler.cpp:630 #: src/eventhandler.cpp:457 src/eventhandler.cpp:626
#, kde-format #, kde-format
msgid "Unknown event" msgid "Unknown event"
msgstr "" msgstr ""
#: src/eventhandler.cpp:476 #: src/eventhandler.cpp:472
#, kde-format #, kde-format
msgid "a file" msgid "a file"
msgstr "" msgstr ""
#: src/eventhandler.cpp:516 #: src/eventhandler.cpp:512
#, kde-format #, kde-format
msgid "sent a message" msgid "sent a message"
msgstr "" msgstr ""
#: src/eventhandler.cpp:520 #: src/eventhandler.cpp:516
#, kde-format #, kde-format
msgid "sent a sticker" msgid "sent a sticker"
msgstr "" msgstr ""
#: src/eventhandler.cpp:526 #: src/eventhandler.cpp:522
#, kde-format #, kde-format
msgid "reinvited someone to the room" msgid "reinvited someone to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:535 #: src/eventhandler.cpp:531
#, kde-format #, kde-format
msgid "invited someone to the room" msgid "invited someone to the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:545 #: src/eventhandler.cpp:541
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "changed their display name" msgid "changed their display name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:567 #: src/eventhandler.cpp:563
#, kde-format #, kde-format
msgid "withdrew a user's invitation" msgid "withdrew a user's invitation"
msgstr "" msgstr ""
#: src/eventhandler.cpp:571 #: src/eventhandler.cpp:567
#, kde-format #, kde-format
msgid "unbanned a user" msgid "unbanned a user"
msgstr "" msgstr ""
#: src/eventhandler.cpp:573 #: src/eventhandler.cpp:569
#, kde-format #, kde-format
msgid "put a user out of the room" msgid "put a user out of the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:576 #: src/eventhandler.cpp:572
#, kde-format #, kde-format
msgid "banned a user from the room" msgid "banned a user from the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:588 #: src/eventhandler.cpp:584
#, kde-format #, kde-format
msgid "set the room main alias" msgid "set the room main alias"
msgstr "" msgstr ""
#: src/eventhandler.cpp:591 #: src/eventhandler.cpp:587
#, kde-format #, kde-format
msgid "set the room name" msgid "set the room name"
msgstr "" msgstr ""
#: src/eventhandler.cpp:594 #: src/eventhandler.cpp:590
#, kde-format #, kde-format
msgid "set the topic" msgid "set the topic"
msgstr "" msgstr ""
#: src/eventhandler.cpp:603 #: src/eventhandler.cpp:599
#, kde-format #, kde-format
msgid "upgraded the room version" msgid "upgraded the room version"
msgstr "" msgstr ""
#: src/eventhandler.cpp:603 #: src/eventhandler.cpp:599
#, kde-format #, kde-format
msgid "created the room" msgid "created the room"
msgstr "" msgstr ""
#: src/eventhandler.cpp:609 #: src/eventhandler.cpp:605
#, kde-format #, kde-format
msgid "sent a live location beacon" msgid "sent a live location beacon"
msgstr "" msgstr ""
#: src/eventhandler.cpp:616 #: src/eventhandler.cpp:612
#, kde-format #, kde-format
msgid "added a widget" msgid "added a widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:619 #: src/eventhandler.cpp:615
#, kde-format #, kde-format
msgid "removed a widget" msgid "removed a widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:621 #: src/eventhandler.cpp:617
#, kde-format #, kde-format
msgid "configured a widget" msgid "configured a widget"
msgstr "" msgstr ""
#: src/eventhandler.cpp:624 #: src/eventhandler.cpp:620
#, kde-format #, kde-format
msgid "updated the state" msgid "updated the state"
msgstr "" msgstr ""
#: src/eventhandler.cpp:628 #: src/eventhandler.cpp:624
#, kde-format #, kde-format
msgid "started a poll" msgid "started a poll"
msgstr "" msgstr ""
#: src/eventhandler.cpp:1035
#, kde-format
msgid "1 user: "
msgid_plural "%1 users: "
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
#: src/eventhandler.cpp:1040
#, kde-format
msgctxt "A member who is not in the room has been requested."
msgid "unknown member"
msgstr ""
#: src/eventhandler.cpp:1044
#, kde-format
msgctxt "list separator"
msgid ", "
msgstr ""
#: src/filetransferpseudojob.cpp:48 #: src/filetransferpseudojob.cpp:48
#, kde-format #, kde-format
msgctxt "Job heading, like 'Copying'" msgctxt "Job heading, like 'Copying'"
@@ -1403,67 +1382,67 @@ msgstr ""
msgid "Removes the user from the room" msgid "Removes the user from the room"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:153 src/models/emojimodel.cpp:211 #: src/models/emojimodel.cpp:155 src/models/emojimodel.cpp:213
#, kde-format #, kde-format
msgctxt "Previously used emojis" msgctxt "Previously used emojis"
msgid "History" msgid "History"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:158 #: src/models/emojimodel.cpp:160
#, kde-format #, kde-format
msgctxt "'Smileys' is a category of emoji" msgctxt "'Smileys' is a category of emoji"
msgid "Smileys" msgid "Smileys"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:163 #: src/models/emojimodel.cpp:165
#, kde-format #, kde-format
msgctxt "'People' is a category of emoji" msgctxt "'People' is a category of emoji"
msgid "People" msgid "People"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:168 #: src/models/emojimodel.cpp:170
#, kde-format #, kde-format
msgctxt "'Nature' is a category of emoji" msgctxt "'Nature' is a category of emoji"
msgid "Nature" msgid "Nature"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:173 #: src/models/emojimodel.cpp:175
#, kde-format #, kde-format
msgctxt "'Food' is a category of emoji" msgctxt "'Food' is a category of emoji"
msgid "Food" msgid "Food"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:178 #: src/models/emojimodel.cpp:180
#, kde-format #, kde-format
msgctxt "'Activities' is a category of emoji" msgctxt "'Activities' is a category of emoji"
msgid "Activities" msgid "Activities"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:183 #: src/models/emojimodel.cpp:185
#, kde-format #, kde-format
msgctxt "'Travel' is a category of emoji" msgctxt "'Travel' is a category of emoji"
msgid "Travel" msgid "Travel"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:188 #: src/models/emojimodel.cpp:190
#, kde-format #, kde-format
msgctxt "'Objects' is a category of emoji" msgctxt "'Objects' is a category of emoji"
msgid "Objects" msgid "Objects"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:193 #: src/models/emojimodel.cpp:195
#, kde-format #, kde-format
msgctxt "'Symbols' is a category of emoji" msgctxt "'Symbols' is a category of emoji"
msgid "Symbols" msgid "Symbols"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:198 #: src/models/emojimodel.cpp:200
#, kde-format #, kde-format
msgctxt "'Flags' is a category of emoji" msgctxt "'Flags' is a category of emoji"
msgid "Flags" msgid "Flags"
msgstr "" msgstr ""
#: src/models/emojimodel.cpp:217 #: src/models/emojimodel.cpp:219
#, kde-format #, kde-format
msgctxt "'Custom' is a category of emoji" msgctxt "'Custom' is a category of emoji"
msgid "Custom" msgid "Custom"
@@ -1481,13 +1460,13 @@ msgctxt "As in 'The user's own emojis"
msgid "Own Emojis" msgid "Own Emojis"
msgstr "" msgstr ""
#: src/models/messagecontentmodel.cpp:216 #: src/models/messagecontentmodel.cpp:223
#: src/timeline/LinkPreviewLoadComponent.qml:66 #: src/timeline/LinkPreviewLoadComponent.qml:66
#, kde-format #, kde-format
msgid "Loading reply" msgid "Loading reply"
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:162 #: src/models/messagefiltermodel.cpp:164
#, kde-format #, kde-format
msgctxt "%1: What's being done; %2: How often it is done." msgctxt "%1: What's being done; %2: How often it is done."
msgid " %1" msgid " %1"
@@ -1497,7 +1476,7 @@ msgstr[1] ""
msgstr[2] "" msgstr[2] ""
msgstr[3] "" msgstr[3] ""
#: src/models/messagefiltermodel.cpp:166 #: src/models/messagefiltermodel.cpp:168
#, kde-format #, kde-format
msgctxt "n users" msgctxt "n users"
msgid " %1 user " msgid " %1 user "
@@ -1506,25 +1485,25 @@ msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgstr[2] "" msgstr[2] ""
#: src/models/messagefiltermodel.cpp:175 #: src/models/messagefiltermodel.cpp:177
#, kde-format #, kde-format
msgctxt "[action 1], [action 2 and/or action 3]" msgctxt "[action 1], [action 2 and/or action 3]"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:179 #: src/models/messagefiltermodel.cpp:181
#, kde-format #, kde-format
msgctxt "[action 1, action 2] or [action 3]" msgctxt "[action 1, action 2] or [action 3]"
msgid " or " msgid " or "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:179 #: src/models/messagefiltermodel.cpp:181
#, kde-format #, kde-format
msgctxt "[action 1, action 2] and [action 3]" msgctxt "[action 1, action 2] and [action 3]"
msgid " and " msgid " and "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:185 #: src/models/messagefiltermodel.cpp:187
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"userText (%1) is either a Matrix username if a single user sent all the " "userText (%1) is either a Matrix username if a single user sent all the "
@@ -1743,103 +1722,124 @@ msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgstr[2] "" msgstr[2] ""
#: src/neochatconnection.cpp:85 #: src/models/readmarkermodel.cpp:110
#, kde-format
msgid "1 user: "
msgid_plural "%1 users: "
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
#: src/models/readmarkermodel.cpp:115
#, kde-format
msgctxt "A member who is not in the room has been requested."
msgid "unknown member"
msgstr ""
#: src/models/readmarkermodel.cpp:117
#, kde-format
msgctxt "list separator"
msgid ", "
msgstr ""
#: src/neochatconnection.cpp:86
#, kde-format #, kde-format
msgid "File too large to download." msgid "File too large to download."
msgstr "" msgstr ""
#: src/neochatconnection.cpp:85 #: src/neochatconnection.cpp:86
#, kde-format #, kde-format
msgid "Contact your matrix server administrator for support." msgid "Contact your matrix server administrator for support."
msgstr "" msgstr ""
#: src/neochatconnection.cpp:296 #: src/neochatconnection.cpp:317
#, kde-format #, kde-format
msgctxt "@info" msgctxt "@info"
msgid "No identity server configured" msgid "No identity server configured"
msgstr "" msgstr ""
#: src/neochatconnection.cpp:327 #: src/neochatconnection.cpp:348
#, kde-format #, kde-format
msgid "Room creation failed: %1" msgid "Room creation failed: %1"
msgstr "" msgstr ""
#: src/neochatconnection.cpp:364 #: src/neochatconnection.cpp:385
#, kde-format #, kde-format
msgid "Space creation failed: %1" msgid "Space creation failed: %1"
msgstr "" msgstr ""
#: src/neochatroom.cpp:1352 #: src/neochatroom.cpp:1403
#, kde-format #, kde-format
msgid "Report sent successfully." msgid "Report sent successfully."
msgstr "" msgstr ""
#: src/neochatroom.cpp:1622 src/neochatroom.cpp:1630 #: src/neochatroom.cpp:1724 src/neochatroom.cpp:1732
#, kde-format #, kde-format
msgctxt "'Lat' and 'Lon' as in Latitude and Longitude" msgctxt "'Lat' and 'Lon' as in Latitude and Longitude"
msgid "Lat: %1, Lon: %2" msgid "Lat: %1, Lon: %2"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:120 src/notificationsmanager.cpp:325 #: src/notificationsmanager.cpp:126 src/notificationsmanager.cpp:330
#, kde-format #, kde-format
msgid "Encrypted Message" msgid "Encrypted Message"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:204 src/qml/Main.qml:279 #: src/notificationsmanager.cpp:210 src/qml/Main.qml:279
#, kde-format #, kde-format
msgid "%1: %2" msgid "%1: %2"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:210 #: src/notificationsmanager.cpp:216
#, kde-format #, kde-format
msgid "Open NeoChat in this room" msgid "Open NeoChat in this room"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:223 src/qml/DelegateContextMenu.qml:98 #: src/notificationsmanager.cpp:229 src/qml/DelegateContextMenu.qml:98
#: src/qml/HoverActions.qml:111 #: src/qml/HoverActions.qml:111
#, kde-format #, kde-format
msgid "Reply" msgid "Reply"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:224 #: src/notificationsmanager.cpp:230
#, kde-format #, kde-format
msgid "Reply..." msgid "Reply..."
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:243 #: src/notificationsmanager.cpp:249
#, kde-format #, kde-format
msgid "%1 invited you to a room" msgid "%1 invited you to a room"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:247 #: src/notificationsmanager.cpp:252
#, kde-format #, kde-format
msgid "Open this invitation in NeoChat" msgid "Open this invitation in NeoChat"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:257 #: src/notificationsmanager.cpp:262
#, kde-format #, kde-format
msgctxt "@action:button The thing being accepted is an invitation to chat" msgctxt "@action:button The thing being accepted is an invitation to chat"
msgid "Accept" msgid "Accept"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:258 #: src/notificationsmanager.cpp:263
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject" msgid "Reject"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:259 #: src/notificationsmanager.cpp:264
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject and Ignore User" msgid "Reject and Ignore User"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:318 #: src/notificationsmanager.cpp:323
#, kde-format #, kde-format
msgid "%1 (%2)" msgid "%1 (%2)"
msgstr "" msgstr ""
#: src/notificationsmanager.cpp:329 #: src/notificationsmanager.cpp:334
#, kde-format #, kde-format
msgid "Open NeoChat" msgid "Open NeoChat"
msgstr "" msgstr ""
@@ -2757,18 +2757,23 @@ msgstr ""
msgid "Accept this invitation?" msgid "Accept this invitation?"
msgstr "" msgstr ""
#: src/qml/InvitationView.qml:21 #: src/qml/InvitationView.qml:18
#, kde-format
msgid "You can reject invitations from unknown users under Security settings."
msgstr ""
#: src/qml/InvitationView.qml:24
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject and ignore user" msgid "Reject and ignore user"
msgstr "" msgstr ""
#: src/qml/InvitationView.qml:30 #: src/qml/InvitationView.qml:33
#, kde-format #, kde-format
msgid "Reject" msgid "Reject"
msgstr "" msgstr ""
#: src/qml/InvitationView.qml:37 src/qml/KeyVerificationDialog.qml:92 #: src/qml/InvitationView.qml:40 src/qml/KeyVerificationDialog.qml:92
#, kde-format #, kde-format
msgid "Accept" msgid "Accept"
msgstr "" msgstr ""
@@ -3529,27 +3534,27 @@ msgctxt "'Space' is a matrix space"
msgid "Leave Space" msgid "Leave Space"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:195 #: src/qml/TimelineView.qml:196
#, kde-format #, kde-format
msgid "Jump to first unread message" msgid "Jump to first unread message"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:195 #: src/qml/TimelineView.qml:196
#, kde-format #, kde-format
msgid "Jump to oldest loaded message" msgid "Jump to oldest loaded message"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:235 #: src/qml/TimelineView.qml:236
#, kde-format #, kde-format
msgid "Jump to latest message" msgid "Jump to latest message"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:260 #: src/qml/TimelineView.qml:261
#, kde-format #, kde-format
msgid "Drag items here to share them" msgid "Drag items here to share them"
msgstr "" msgstr ""
#: src/qml/TimelineView.qml:267 #: src/qml/TimelineView.qml:268
#, kde-format #, kde-format
msgctxt "Message displayed when some users are typing" msgctxt "Message displayed when some users are typing"
msgid "%2 is typing" msgid "%2 is typing"
@@ -3937,27 +3942,27 @@ msgstr ""
msgid "Working" msgid "Working"
msgstr "" msgstr ""
#: src/roommanager.cpp:125 #: src/roommanager.cpp:138
#, kde-format #, kde-format
msgid "Malformed or empty Matrix id" msgid "Malformed or empty Matrix id"
msgstr "" msgstr ""
#: src/roommanager.cpp:125 #: src/roommanager.cpp:138
#, kde-format #, kde-format
msgid "%1 is not a correct Matrix identifier" msgid "%1 is not a correct Matrix identifier"
msgstr "" msgstr ""
#: src/roommanager.cpp:337 #: src/roommanager.cpp:345
#, kde-format #, kde-format
msgid "Failed to join room" msgid "Failed to join room"
msgstr "" msgstr ""
#: src/roommanager.cpp:369 #: src/roommanager.cpp:377
#, kde-format #, kde-format
msgid "You requested to join '%1'" msgid "You requested to join '%1'"
msgstr "" msgstr ""
#: src/roommanager.cpp:373 #: src/roommanager.cpp:381
#, kde-format #, kde-format
msgid "Failed to request joining room" msgid "Failed to request joining room"
msgstr "" msgstr ""
@@ -4356,7 +4361,7 @@ msgid "Keyword…"
msgstr "" msgstr ""
#: src/settings/GlobalNotificationsPage.qml:116 #: src/settings/GlobalNotificationsPage.qml:116
#: src/settings/Permissions.qml:391 src/settings/PushNotification.qml:119 #: src/settings/Permissions.qml:386 src/settings/PushNotification.qml:119
#, kde-format #, kde-format
msgid "Add keyword" msgid "Add keyword"
msgstr "" msgstr ""
@@ -4417,7 +4422,7 @@ msgid "Ignored Users"
msgstr "" msgstr ""
#: src/settings/IgnoredUsersDialog.qml:24 #: src/settings/IgnoredUsersDialog.qml:24
#: src/settings/NeoChatSecurityPage.qml:37 #: src/settings/NeoChatSecurityPage.qml:35
#, kde-format #, kde-format
msgctxt "@title:group" msgctxt "@title:group"
msgid "Ignored Users" msgid "Ignored Users"
@@ -4547,37 +4552,61 @@ msgstr ""
#: src/settings/NeoChatSecurityPage.qml:20 #: src/settings/NeoChatSecurityPage.qml:20
#, kde-format #, kde-format
msgctxt "@title" msgctxt "@title:group"
msgid "Keys" msgid "Invitations"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:24
#, kde-format
msgctxt "@option:check"
msgid "Reject invitations from unknown users"
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:25 #: src/settings/NeoChatSecurityPage.qml:25
#, kde-format #, kde-format
msgid "Device key" msgid ""
"If enabled, NeoChat will reject invitations from from users you don't share "
"a room with."
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:29 #: src/settings/NeoChatSecurityPage.qml:25
#, kde-format #, kde-format
msgid "Encryption key" msgid "Your server does not support this setting."
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:33 #: src/settings/NeoChatSecurityPage.qml:39
#, kde-format
msgid "Device id"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:41
#, kde-format #, kde-format
msgctxt "@action:button" msgctxt "@action:button"
msgid "Manage ignored users" msgid "Manage ignored users"
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:43 #: src/settings/NeoChatSecurityPage.qml:41
#, kde-format #, kde-format
msgctxt "@title:window" msgctxt "@title:window"
msgid "Ignored Users" msgid "Ignored Users"
msgstr "" msgstr ""
#: src/settings/NeoChatSecurityPage.qml:46
#, kde-format
msgctxt "@title"
msgid "Keys"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:51
#, kde-format
msgid "Device key"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:55
#, kde-format
msgid "Encryption key"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:59
#, kde-format
msgid "Device id"
msgstr ""
#: src/settings/NeoChatSettingsView.qml:22 src/settings/RoomGeneralPage.qml:22 #: src/settings/NeoChatSettingsView.qml:22 src/settings/RoomGeneralPage.qml:22
#: src/settings/RoomSettingsView.qml:39 #: src/settings/RoomSettingsView.qml:39
#, kde-format #, kde-format
@@ -4731,27 +4760,27 @@ msgctxt "@label:textbox"
msgid "Password:" msgid "Password:"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:37 #: src/settings/Permissions.qml:32
#, kde-format #, kde-format
msgid "Privileged Users" msgid "Privileged Users"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:238 #: src/settings/Permissions.qml:233
#, kde-format #, kde-format
msgid "Default permissions" msgid "Default permissions"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:278 #: src/settings/Permissions.qml:273
#, kde-format #, kde-format
msgid "Basic permissions" msgid "Basic permissions"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:318 #: src/settings/Permissions.qml:313
#, kde-format #, kde-format
msgid "Event permissions" msgid "Event permissions"
msgstr "" msgstr ""
#: src/settings/Permissions.qml:365 #: src/settings/Permissions.qml:360
#, kde-format #, kde-format
msgid "Event Type…" msgid "Event Type…"
msgstr "" msgstr ""
@@ -5219,14 +5248,14 @@ msgid ""
"device." "device."
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:107 src/timeline/FileComponent.qml:190 #: src/timeline/FileComponent.qml:103 src/timeline/FileComponent.qml:186
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; offers ability to download its file" "tooltip for a button on a message; offers ability to download its file"
msgid "Download" msgid "Download"
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:123 src/timeline/FileComponent.qml:180 #: src/timeline/FileComponent.qml:119 src/timeline/FileComponent.qml:176
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; offers ability to open its downloaded " "tooltip for a button on a message; offers ability to open its downloaded "
@@ -5234,13 +5263,13 @@ msgctxt ""
msgid "Open File" msgid "Open File"
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:138 #: src/timeline/FileComponent.qml:134
#, kde-format #, kde-format
msgctxt "file download progress" msgctxt "file download progress"
msgid "%1 / %2" msgid "%1 / %2"
msgstr "" msgstr ""
#: src/timeline/FileComponent.qml:143 #: src/timeline/FileComponent.qml:139
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; stops downloading the message's file" "tooltip for a button on a message; stops downloading the message's file"
@@ -5328,7 +5357,7 @@ msgctxt "as in 'this vote has ended'"
msgid "(Ended)" msgid "(Ended)"
msgstr "" msgstr ""
#: src/timeline/ReadMarkerDelegate.qml:39 #: src/timeline/ReadMarkerDelegate.qml:42
#, kde-format #, kde-format
msgctxt "Relative time since the room was last read" msgctxt "Relative time since the room was last read"
msgid "Last read: %1" msgid "Last read: %1"
@@ -5347,18 +5376,18 @@ msgstr ""
msgid "Pl. %1" msgid "Pl. %1"
msgstr "" msgstr ""
#: src/timeline/VideoComponent.qml:171 #: src/timeline/VideoComponent.qml:197
#, kde-format #, kde-format
msgid "Video" msgid "Video"
msgstr "" msgstr ""
#: src/timeline/VideoComponent.qml:235 #: src/timeline/VideoComponent.qml:261
#, kde-format #, kde-format
msgctxt "@action:button" msgctxt "@action:button"
msgid "Volume" msgid "Volume"
msgstr "" msgstr ""
#: src/timeline/VideoComponent.qml:319 #: src/timeline/VideoComponent.qml:345
#, kde-format #, kde-format
msgid "Maximize" msgid "Maximize"
msgstr "" msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -9,8 +9,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: neochat\n" "Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2024-07-15 00:38+0000\n" "POT-Creation-Date: 2024-07-30 02:34+0000\n"
"PO-Revision-Date: 2024-07-08 15:59+0900\n" "PO-Revision-Date: 2024-08-06 05:24+0900\n"
"Last-Translator: Kisaragi Hiu <mail@kisaragi-hiu.com>\n" "Last-Translator: Kisaragi Hiu <mail@kisaragi-hiu.com>\n"
"Language-Team: Traditional Chinese <zh-l10n@lists.slat.org>\n" "Language-Team: Traditional Chinese <zh-l10n@lists.slat.org>\n"
"Language: zh_TW\n" "Language: zh_TW\n"
@@ -365,7 +365,7 @@ msgid "Custom"
msgstr "自訂" msgstr "自訂"
#: src/enums/powerlevel.cpp:88 src/models/permissionsmodel.cpp:162 #: src/enums/powerlevel.cpp:88 src/models/permissionsmodel.cpp:162
#: src/models/userlistmodel.cpp:113 #: src/models/userlistmodel.cpp:114
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"%1 is the name of the power level, e.g. admin and %2 is the value that " "%1 is the name of the power level, e.g. admin and %2 is the value that "
@@ -373,367 +373,349 @@ msgctxt ""
msgid "%1 (%2)" msgid "%1 (%2)"
msgstr "%1 (%2)" msgstr "%1 (%2)"
#: src/eventhandler.cpp:304 src/eventhandler.cpp:509 #: src/eventhandler.cpp:297 src/eventhandler.cpp:505
#: src/models/messagecontentmodel.cpp:223 src/models/messageeventmodel.cpp:459 #: src/models/messagecontentmodel.cpp:230 src/models/messageeventmodel.cpp:438
#, kde-format #, kde-format
msgid "<i>[This message was deleted]</i>" msgid "<i>[This message was deleted]</i>"
msgstr "<i>[此訊息已被刪除]</i>" msgstr "<i>[此訊息已被刪除]</i>"
#: src/eventhandler.cpp:304 src/models/messagecontentmodel.cpp:224 #: src/eventhandler.cpp:297 src/models/messagecontentmodel.cpp:231
#: src/models/messageeventmodel.cpp:460 #: src/models/messageeventmodel.cpp:439
#, kde-format #, kde-format
msgid "<i>[This message was deleted: %1]</i>" msgid "<i>[This message was deleted: %1]</i>"
msgstr "<i>[此訊息已被刪除:%1]</i>" msgstr "<i>[此訊息已被刪除:%1]</i>"
#: src/eventhandler.cpp:335 #: src/eventhandler.cpp:331
#, kde-format #, kde-format
msgid "reinvited %1 to the room" msgid "reinvited %1 to the room"
msgstr "已重新邀請 %1 到聊天室裡" msgstr "已重新邀請 %1 到聊天室裡"
#: src/eventhandler.cpp:337 #: src/eventhandler.cpp:333
#, kde-format #, kde-format
msgctxt "Optional reason for an invitation" msgctxt "Optional reason for an invitation"
msgid ": %1" msgid ": %1"
msgstr "%1" msgstr "%1"
#: src/eventhandler.cpp:346 src/eventhandler.cpp:533 #: src/eventhandler.cpp:342 src/eventhandler.cpp:529
#, kde-format #, kde-format
msgid "joined the room (repeated)" msgid "joined the room (repeated)"
msgstr "已加入聊天室(重複)" msgstr "已加入聊天室(重複)"
#: src/eventhandler.cpp:348 #: src/eventhandler.cpp:344
#, kde-format #, kde-format
msgid "invited %1 to the room" msgid "invited %1 to the room"
msgstr "已邀請 %1 到聊天室裡" msgstr "已邀請 %1 到聊天室裡"
#: src/eventhandler.cpp:348 src/eventhandler.cpp:535 #: src/eventhandler.cpp:344 src/eventhandler.cpp:531
#, kde-format #, kde-format
msgid "joined the room" msgid "joined the room"
msgstr "已加入聊天室" msgstr "已加入聊天室"
#: src/eventhandler.cpp:352 #: src/eventhandler.cpp:348
#, kde-format #, kde-format
msgid ": %1" msgid ": %1"
msgstr "%1" msgstr "%1"
#: src/eventhandler.cpp:359 src/eventhandler.cpp:543 #: src/eventhandler.cpp:355 src/eventhandler.cpp:539
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "cleared their display name" msgid "cleared their display name"
msgstr "將其顯示名稱清除了" msgstr "將其顯示名稱清除了"
#: src/eventhandler.cpp:362 #: src/eventhandler.cpp:358
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "changed their display name to %1" msgid "changed their display name to %1"
msgstr "將其顯示名稱變更為 %1" msgstr "將其顯示名稱變更為 %1"
#: src/eventhandler.cpp:368 src/eventhandler.cpp:550 #: src/eventhandler.cpp:364 src/eventhandler.cpp:546
#, kde-format #, kde-format
msgid " and " msgid " and "
msgstr " 和 " msgstr " 和 "
#: src/eventhandler.cpp:371 src/eventhandler.cpp:553 #: src/eventhandler.cpp:367 src/eventhandler.cpp:549
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "cleared their avatar" msgid "cleared their avatar"
msgstr "將其頭貼清除了" msgstr "將其頭貼清除了"
#: src/eventhandler.cpp:373 src/eventhandler.cpp:555 #: src/eventhandler.cpp:369 src/eventhandler.cpp:551
#, kde-format #, kde-format
msgid "set an avatar" msgid "set an avatar"
msgstr "設定了頭貼" msgstr "設定了頭貼"
#: src/eventhandler.cpp:375 src/eventhandler.cpp:557 #: src/eventhandler.cpp:371 src/eventhandler.cpp:553
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "updated their avatar" msgid "updated their avatar"
msgstr "更新了他的頭貼" msgstr "更新了他的頭貼"
#: src/eventhandler.cpp:379 src/eventhandler.cpp:561 #: src/eventhandler.cpp:375 src/eventhandler.cpp:557
#, kde-format #, kde-format
msgctxt "<user> changed nothing" msgctxt "<user> changed nothing"
msgid "changed nothing" msgid "changed nothing"
msgstr "什麼都沒改" msgstr "什麼都沒改"
#: src/eventhandler.cpp:385 #: src/eventhandler.cpp:381
#, kde-format #, kde-format
msgid "withdrew %1's invitation" msgid "withdrew %1's invitation"
msgstr "撤回了 %1 的邀請" msgstr "撤回了 %1 的邀請"
#: src/eventhandler.cpp:385 src/eventhandler.cpp:567 #: src/eventhandler.cpp:381 src/eventhandler.cpp:563
#, kde-format #, kde-format
msgid "rejected the invitation" msgid "rejected the invitation"
msgstr "拒絕了邀請" msgstr "拒絕了邀請"
#: src/eventhandler.cpp:389 #: src/eventhandler.cpp:385
#, kde-format #, kde-format
msgid "unbanned %1" msgid "unbanned %1"
msgstr "解除了 %1 的封鎖" msgstr "解除了 %1 的封鎖"
#: src/eventhandler.cpp:389 src/eventhandler.cpp:571 #: src/eventhandler.cpp:385 src/eventhandler.cpp:567
#, kde-format #, kde-format
msgid "self-unbanned" msgid "self-unbanned"
msgstr "已自我解除封鎖" msgstr "已自我解除封鎖"
#: src/eventhandler.cpp:392 #: src/eventhandler.cpp:388
#, kde-format #, kde-format
msgid "has put %1 out of the room: %2" msgid "has put %1 out of the room: %2"
msgstr "已將 %1 移出聊天室:%2" msgstr "已將 %1 移出聊天室:%2"
#: src/eventhandler.cpp:393 src/eventhandler.cpp:573 #: src/eventhandler.cpp:389 src/eventhandler.cpp:569
#, kde-format #, kde-format
msgid "left the room" msgid "left the room"
msgstr "已離開聊天室" msgstr "已離開聊天室"
#: src/eventhandler.cpp:397 #: src/eventhandler.cpp:393
#, kde-format #, kde-format
msgid "banned %1 from the room" msgid "banned %1 from the room"
msgstr "已從聊天室封鎖 %1" msgstr "已從聊天室封鎖 %1"
#: src/eventhandler.cpp:399 #: src/eventhandler.cpp:395
#, kde-format #, kde-format
msgid "banned %1 from the room: %2" msgid "banned %1 from the room: %2"
msgstr "已從聊天室封鎖 %1%2" msgstr "已從聊天室封鎖 %1%2"
#: src/eventhandler.cpp:402 src/eventhandler.cpp:578 #: src/eventhandler.cpp:398 src/eventhandler.cpp:574
#, kde-format #, kde-format
msgid "self-banned from the room" msgid "self-banned from the room"
msgstr "已從聊天室自行封鎖" msgstr "已從聊天室自行封鎖"
#: src/eventhandler.cpp:406 src/eventhandler.cpp:581 #: src/eventhandler.cpp:402 src/eventhandler.cpp:577
#, kde-format #, kde-format
msgid "requested an invite" msgid "requested an invite"
msgstr "請求了邀請" msgstr "請求了邀請"
#: src/eventhandler.cpp:406 #: src/eventhandler.cpp:402
#, kde-format #, kde-format
msgid "requested an invite with reason: %1" msgid "requested an invite with reason: %1"
msgstr "請求了邀請,理由:%1" msgstr "請求了邀請,理由:%1"
#: src/eventhandler.cpp:410 src/eventhandler.cpp:585 #: src/eventhandler.cpp:406 src/eventhandler.cpp:581
#, kde-format #, kde-format
msgid "made something unknown" msgid "made something unknown"
msgstr "做了不明的東西" msgstr "做了不明的東西"
#: src/eventhandler.cpp:413 src/eventhandler.cpp:588 #: src/eventhandler.cpp:409 src/eventhandler.cpp:584
#, kde-format #, kde-format
msgid "cleared the room main alias" msgid "cleared the room main alias"
msgstr "清除了聊天室的主別名" msgstr "清除了聊天室的主別名"
#: src/eventhandler.cpp:413 #: src/eventhandler.cpp:409
#, kde-format #, kde-format
msgid "set the room main alias to: %1" msgid "set the room main alias to: %1"
msgstr "設定聊天室的主別名為:%1" msgstr "設定聊天室的主別名為:%1"
#: src/eventhandler.cpp:416 src/eventhandler.cpp:591 #: src/eventhandler.cpp:412 src/eventhandler.cpp:587
#, kde-format #, kde-format
msgid "cleared the room name" msgid "cleared the room name"
msgstr "清除了聊天室名稱" msgstr "清除了聊天室名稱"
#: src/eventhandler.cpp:416 #: src/eventhandler.cpp:412
#, kde-format #, kde-format
msgid "set the room name to: %1" msgid "set the room name to: %1"
msgstr "設定聊天室名稱為:%1" msgstr "設定聊天室名稱為:%1"
#: src/eventhandler.cpp:419 src/eventhandler.cpp:594 #: src/eventhandler.cpp:415 src/eventhandler.cpp:590
#, kde-format #, kde-format
msgid "cleared the topic" msgid "cleared the topic"
msgstr "清除了主題" msgstr "清除了主題"
#: src/eventhandler.cpp:420 #: src/eventhandler.cpp:416
#, kde-format #, kde-format
msgid "set the topic to: %1" msgid "set the topic to: %1"
msgstr "設定主題為:%1" msgstr "設定主題為:%1"
#: src/eventhandler.cpp:426 src/eventhandler.cpp:597 #: src/eventhandler.cpp:422 src/eventhandler.cpp:593
#, kde-format #, kde-format
msgid "changed the room avatar" msgid "changed the room avatar"
msgstr "變更了聊天室頭貼" msgstr "變更了聊天室頭貼"
#: src/eventhandler.cpp:429 src/eventhandler.cpp:600 #: src/eventhandler.cpp:425 src/eventhandler.cpp:596
#, kde-format #, kde-format
msgid "activated End-to-End Encryption" msgid "activated End-to-End Encryption"
msgstr "啟用了端對端加密" msgstr "啟用了端對端加密"
#: src/eventhandler.cpp:433 #: src/eventhandler.cpp:429
#, kde-format #, kde-format
msgid "upgraded the room to version %1" msgid "upgraded the room to version %1"
msgstr "更新了聊天室到版本 %1" msgstr "更新了聊天室到版本 %1"
#: src/eventhandler.cpp:434 #: src/eventhandler.cpp:430
#, kde-format #, kde-format
msgid "created the room, version %1" msgid "created the room, version %1"
msgstr "建立了聊天室,版本 %1" msgstr "建立了聊天室,版本 %1"
#: src/eventhandler.cpp:437 src/eventhandler.cpp:606 #: src/eventhandler.cpp:433 src/eventhandler.cpp:602
#, kde-format #, kde-format
msgctxt "'power level' means permission level" msgctxt "'power level' means permission level"
msgid "changed the power levels for this room" msgid "changed the power levels for this room"
msgstr "變更了這個聊天室的能力等級" msgstr "變更了這個聊天室的能力等級"
#: src/eventhandler.cpp:443 src/eventhandler.cpp:612 #: src/eventhandler.cpp:439 src/eventhandler.cpp:608
#, kde-format #, kde-format
msgid "changed the server access control lists for this room" msgid "changed the server access control lists for this room"
msgstr "變更了這個聊天室的伺服器存取控制清單 (ACL)" msgstr "變更了這個聊天室的伺服器存取控制清單 (ACL)"
#: src/eventhandler.cpp:447 #: src/eventhandler.cpp:443
#, kde-format #, kde-format
msgctxt "[User] added <name> widget" msgctxt "[User] added <name> widget"
msgid "added %1 widget" msgid "added %1 widget"
msgstr "新增了 %1 元件" msgstr "新增了 %1 元件"
#: src/eventhandler.cpp:450 #: src/eventhandler.cpp:446
#, kde-format #, kde-format
msgctxt "[User] removed <name> widget" msgctxt "[User] removed <name> widget"
msgid "removed %1 widget" msgid "removed %1 widget"
msgstr "移除了 %1 元件" msgstr "移除了 %1 元件"
#: src/eventhandler.cpp:452 #: src/eventhandler.cpp:448
#, kde-format #, kde-format
msgctxt "[User] configured <name> widget" msgctxt "[User] configured <name> widget"
msgid "configured %1 widget" msgid "configured %1 widget"
msgstr "設定了 %1 元件" msgstr "設定了 %1 元件"
#: src/eventhandler.cpp:455 #: src/eventhandler.cpp:451
#, kde-format #, kde-format
msgid "updated %1 state" msgid "updated %1 state"
msgstr "更新了 %1 狀態" msgstr "更新了 %1 狀態"
#: src/eventhandler.cpp:456 #: src/eventhandler.cpp:452
#, kde-format #, kde-format
msgid "updated %1 state for %2" msgid "updated %1 state for %2"
msgstr "為 %2 更新了 %1 狀態" msgstr "為 %2 更新了 %1 狀態"
#: src/eventhandler.cpp:461 src/eventhandler.cpp:630 #: src/eventhandler.cpp:457 src/eventhandler.cpp:626
#, kde-format #, kde-format
msgid "Unknown event" msgid "Unknown event"
msgstr "未知事件" msgstr "未知事件"
#: src/eventhandler.cpp:476 #: src/eventhandler.cpp:472
#, kde-format #, kde-format
msgid "a file" msgid "a file"
msgstr "一個檔案" msgstr "一個檔案"
#: src/eventhandler.cpp:516 #: src/eventhandler.cpp:512
#, kde-format #, kde-format
msgid "sent a message" msgid "sent a message"
msgstr "傳送了訊息" msgstr "傳送了訊息"
#: src/eventhandler.cpp:520 #: src/eventhandler.cpp:516
#, kde-format #, kde-format
msgid "sent a sticker" msgid "sent a sticker"
msgstr "傳送了貼圖" msgstr "傳送了貼圖"
#: src/eventhandler.cpp:526 #: src/eventhandler.cpp:522
#, kde-format #, kde-format
msgid "reinvited someone to the room" msgid "reinvited someone to the room"
msgstr "已重新邀請某人到聊天室裡" msgstr "已重新邀請某人到聊天室裡"
#: src/eventhandler.cpp:535 #: src/eventhandler.cpp:531
#, kde-format #, kde-format
msgid "invited someone to the room" msgid "invited someone to the room"
msgstr "已邀請某人到聊天室裡" msgstr "已邀請某人到聊天室裡"
#: src/eventhandler.cpp:545 #: src/eventhandler.cpp:541
#, kde-format #, kde-format
msgctxt "their refers to a singular user" msgctxt "their refers to a singular user"
msgid "changed their display name" msgid "changed their display name"
msgstr "變更了他的顯示名稱" msgstr "變更了他的顯示名稱"
#: src/eventhandler.cpp:567 #: src/eventhandler.cpp:563
#, kde-format #, kde-format
msgid "withdrew a user's invitation" msgid "withdrew a user's invitation"
msgstr "撤回了一個使用者的邀請" msgstr "撤回了一個使用者的邀請"
#: src/eventhandler.cpp:571 #: src/eventhandler.cpp:567
#, kde-format #, kde-format
msgid "unbanned a user" msgid "unbanned a user"
msgstr "已解除封鎖一個使用者" msgstr "已解除封鎖一個使用者"
#: src/eventhandler.cpp:573 #: src/eventhandler.cpp:569
#, kde-format #, kde-format
msgid "put a user out of the room" msgid "put a user out of the room"
msgstr "已將一個使用者移出聊天室" msgstr "已將一個使用者移出聊天室"
#: src/eventhandler.cpp:576 #: src/eventhandler.cpp:572
#, kde-format #, kde-format
msgid "banned a user from the room" msgid "banned a user from the room"
msgstr "已從聊天室封鎖一個使用者" msgstr "已從聊天室封鎖一個使用者"
#: src/eventhandler.cpp:588 #: src/eventhandler.cpp:584
#, kde-format #, kde-format
msgid "set the room main alias" msgid "set the room main alias"
msgstr "設定了聊天室的主別名" msgstr "設定了聊天室的主別名"
#: src/eventhandler.cpp:591 #: src/eventhandler.cpp:587
#, kde-format #, kde-format
msgid "set the room name" msgid "set the room name"
msgstr "設定了聊天室名稱" msgstr "設定了聊天室名稱"
#: src/eventhandler.cpp:594 #: src/eventhandler.cpp:590
#, kde-format #, kde-format
msgid "set the topic" msgid "set the topic"
msgstr "設定了主題" msgstr "設定了主題"
#: src/eventhandler.cpp:603 #: src/eventhandler.cpp:599
#, kde-format #, kde-format
msgid "upgraded the room version" msgid "upgraded the room version"
msgstr "更新了聊天室版本" msgstr "更新了聊天室版本"
#: src/eventhandler.cpp:603 #: src/eventhandler.cpp:599
#, kde-format #, kde-format
msgid "created the room" msgid "created the room"
msgstr "建立了聊天室" msgstr "建立了聊天室"
#: src/eventhandler.cpp:609 #: src/eventhandler.cpp:605
#, kde-format #, kde-format
msgid "sent a live location beacon" msgid "sent a live location beacon"
msgstr "傳送即時位置信標" msgstr "傳送即時位置信標"
#: src/eventhandler.cpp:616 #: src/eventhandler.cpp:612
#, kde-format #, kde-format
msgid "added a widget" msgid "added a widget"
msgstr "新增了一個元件" msgstr "新增了一個元件"
#: src/eventhandler.cpp:619 #: src/eventhandler.cpp:615
#, kde-format #, kde-format
msgid "removed a widget" msgid "removed a widget"
msgstr "移除了一個元件" msgstr "移除了一個元件"
#: src/eventhandler.cpp:621 #: src/eventhandler.cpp:617
#, kde-format #, kde-format
msgid "configured a widget" msgid "configured a widget"
msgstr "設定了一個元件" msgstr "設定了一個元件"
#: src/eventhandler.cpp:624 #: src/eventhandler.cpp:620
#, kde-format #, kde-format
msgid "updated the state" msgid "updated the state"
msgstr "更新了狀態" msgstr "更新了狀態"
#: src/eventhandler.cpp:628 #: src/eventhandler.cpp:624
#, kde-format #, kde-format
msgid "started a poll" msgid "started a poll"
msgstr "開始了投票" msgstr "開始了投票"
#: src/eventhandler.cpp:1035
#, kde-format
msgid "1 user: "
msgid_plural "%1 users: "
msgstr[0] "%1 名使用者:"
#: src/eventhandler.cpp:1040
#, kde-format
msgctxt "A member who is not in the room has been requested."
msgid "unknown member"
msgstr "未知成員"
#: src/eventhandler.cpp:1044
#, kde-format
msgctxt "list separator"
msgid ", "
msgstr ", "
#: src/filetransferpseudojob.cpp:48 #: src/filetransferpseudojob.cpp:48
#, kde-format #, kde-format
msgctxt "Job heading, like 'Copying'" msgctxt "Job heading, like 'Copying'"
@@ -1400,67 +1382,67 @@ msgstr "%1 已被踢出這個聊天室。"
msgid "Removes the user from the room" msgid "Removes the user from the room"
msgstr "從聊天室移除使用者" msgstr "從聊天室移除使用者"
#: src/models/emojimodel.cpp:153 src/models/emojimodel.cpp:211 #: src/models/emojimodel.cpp:155 src/models/emojimodel.cpp:213
#, kde-format #, kde-format
msgctxt "Previously used emojis" msgctxt "Previously used emojis"
msgid "History" msgid "History"
msgstr "歷史" msgstr "歷史"
#: src/models/emojimodel.cpp:158 #: src/models/emojimodel.cpp:160
#, kde-format #, kde-format
msgctxt "'Smileys' is a category of emoji" msgctxt "'Smileys' is a category of emoji"
msgid "Smileys" msgid "Smileys"
msgstr "微笑" msgstr "微笑"
#: src/models/emojimodel.cpp:163 #: src/models/emojimodel.cpp:165
#, kde-format #, kde-format
msgctxt "'People' is a category of emoji" msgctxt "'People' is a category of emoji"
msgid "People" msgid "People"
msgstr "人們" msgstr "人們"
#: src/models/emojimodel.cpp:168 #: src/models/emojimodel.cpp:170
#, kde-format #, kde-format
msgctxt "'Nature' is a category of emoji" msgctxt "'Nature' is a category of emoji"
msgid "Nature" msgid "Nature"
msgstr "自然" msgstr "自然"
#: src/models/emojimodel.cpp:173 #: src/models/emojimodel.cpp:175
#, kde-format #, kde-format
msgctxt "'Food' is a category of emoji" msgctxt "'Food' is a category of emoji"
msgid "Food" msgid "Food"
msgstr "食物" msgstr "食物"
#: src/models/emojimodel.cpp:178 #: src/models/emojimodel.cpp:180
#, kde-format #, kde-format
msgctxt "'Activities' is a category of emoji" msgctxt "'Activities' is a category of emoji"
msgid "Activities" msgid "Activities"
msgstr "活動" msgstr "活動"
#: src/models/emojimodel.cpp:183 #: src/models/emojimodel.cpp:185
#, kde-format #, kde-format
msgctxt "'Travel' is a category of emoji" msgctxt "'Travel' is a category of emoji"
msgid "Travel" msgid "Travel"
msgstr "旅行" msgstr "旅行"
#: src/models/emojimodel.cpp:188 #: src/models/emojimodel.cpp:190
#, kde-format #, kde-format
msgctxt "'Objects' is a category of emoji" msgctxt "'Objects' is a category of emoji"
msgid "Objects" msgid "Objects"
msgstr "物體" msgstr "物體"
#: src/models/emojimodel.cpp:193 #: src/models/emojimodel.cpp:195
#, kde-format #, kde-format
msgctxt "'Symbols' is a category of emoji" msgctxt "'Symbols' is a category of emoji"
msgid "Symbols" msgid "Symbols"
msgstr "符號" msgstr "符號"
#: src/models/emojimodel.cpp:198 #: src/models/emojimodel.cpp:200
#, kde-format #, kde-format
msgctxt "'Flags' is a category of emoji" msgctxt "'Flags' is a category of emoji"
msgid "Flags" msgid "Flags"
msgstr "旗幟" msgstr "旗幟"
#: src/models/emojimodel.cpp:217 #: src/models/emojimodel.cpp:219
#, kde-format #, kde-format
msgctxt "'Custom' is a category of emoji" msgctxt "'Custom' is a category of emoji"
msgid "Custom" msgid "Custom"
@@ -1478,45 +1460,45 @@ msgctxt "As in 'The user's own emojis"
msgid "Own Emojis" msgid "Own Emojis"
msgstr "自己的表情符號" msgstr "自己的表情符號"
#: src/models/messagecontentmodel.cpp:216 #: src/models/messagecontentmodel.cpp:223
#: src/timeline/LinkPreviewLoadComponent.qml:66 #: src/timeline/LinkPreviewLoadComponent.qml:66
#, kde-format #, kde-format
msgid "Loading reply" msgid "Loading reply"
msgstr "載入回覆中" msgstr "載入回覆中"
#: src/models/messagefiltermodel.cpp:162 #: src/models/messagefiltermodel.cpp:164
#, kde-format #, kde-format
msgctxt "%1: What's being done; %2: How often it is done." msgctxt "%1: What's being done; %2: How often it is done."
msgid " %1" msgid " %1"
msgid_plural " %1 %2 times" msgid_plural " %1 %2 times"
msgstr[0] " %1 %2 次" msgstr[0] " %1 %2 次"
#: src/models/messagefiltermodel.cpp:166 #: src/models/messagefiltermodel.cpp:168
#, kde-format #, kde-format
msgctxt "n users" msgctxt "n users"
msgid " %1 user " msgid " %1 user "
msgid_plural " %1 users " msgid_plural " %1 users "
msgstr[0] " %1 名使用者 " msgstr[0] " %1 名使用者 "
#: src/models/messagefiltermodel.cpp:175 #: src/models/messagefiltermodel.cpp:177
#, kde-format #, kde-format
msgctxt "[action 1], [action 2 and/or action 3]" msgctxt "[action 1], [action 2 and/or action 3]"
msgid ", " msgid ", "
msgstr "" msgstr ""
#: src/models/messagefiltermodel.cpp:179 #: src/models/messagefiltermodel.cpp:181
#, kde-format #, kde-format
msgctxt "[action 1, action 2] or [action 3]" msgctxt "[action 1, action 2] or [action 3]"
msgid " or " msgid " or "
msgstr " 或 " msgstr " 或 "
#: src/models/messagefiltermodel.cpp:179 #: src/models/messagefiltermodel.cpp:181
#, kde-format #, kde-format
msgctxt "[action 1, action 2] and [action 3]" msgctxt "[action 1, action 2] and [action 3]"
msgid " and " msgid " and "
msgstr " 和 " msgstr " 和 "
#: src/models/messagefiltermodel.cpp:185 #: src/models/messagefiltermodel.cpp:187
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"userText (%1) is either a Matrix username if a single user sent all the " "userText (%1) is either a Matrix username if a single user sent all the "
@@ -1731,103 +1713,121 @@ msgid "%2 reacted with %3"
msgid_plural "%2 reacted with %3" msgid_plural "%2 reacted with %3"
msgstr[0] "%2 用 %3 反應" msgstr[0] "%2 用 %3 反應"
#: src/neochatconnection.cpp:85 #: src/models/readmarkermodel.cpp:110
#, kde-format
msgid "1 user: "
msgid_plural "%1 users: "
msgstr[0] "%1 名使用者:"
#: src/models/readmarkermodel.cpp:115
#, kde-format
msgctxt "A member who is not in the room has been requested."
msgid "unknown member"
msgstr "未知成員"
#: src/models/readmarkermodel.cpp:117
#, kde-format
msgctxt "list separator"
msgid ", "
msgstr ", "
#: src/neochatconnection.cpp:86
#, kde-format #, kde-format
msgid "File too large to download." msgid "File too large to download."
msgstr "要下載的檔案太大了。" msgstr "要下載的檔案太大了。"
#: src/neochatconnection.cpp:85 #: src/neochatconnection.cpp:86
#, kde-format #, kde-format
msgid "Contact your matrix server administrator for support." msgid "Contact your matrix server administrator for support."
msgstr "請聯絡您的 matrix 伺服器管理員以求支援。" msgstr "請聯絡您的 matrix 伺服器管理員以求支援。"
#: src/neochatconnection.cpp:296 #: src/neochatconnection.cpp:317
#, kde-format #, kde-format
msgctxt "@info" msgctxt "@info"
msgid "No identity server configured" msgid "No identity server configured"
msgstr "未設定身份伺服器" msgstr "未設定身份伺服器"
#: src/neochatconnection.cpp:327 #: src/neochatconnection.cpp:348
#, kde-format #, kde-format
msgid "Room creation failed: %1" msgid "Room creation failed: %1"
msgstr "聊天室建立失敗:%1" msgstr "聊天室建立失敗:%1"
#: src/neochatconnection.cpp:364 #: src/neochatconnection.cpp:385
#, kde-format #, kde-format
msgid "Space creation failed: %1" msgid "Space creation failed: %1"
msgstr "聊天空間建立失敗:%1" msgstr "聊天空間建立失敗:%1"
#: src/neochatroom.cpp:1352 #: src/neochatroom.cpp:1403
#, kde-format #, kde-format
msgid "Report sent successfully." msgid "Report sent successfully."
msgstr "已成功傳送檢舉" msgstr "已成功傳送檢舉"
#: src/neochatroom.cpp:1622 src/neochatroom.cpp:1630 #: src/neochatroom.cpp:1724 src/neochatroom.cpp:1732
#, kde-format #, kde-format
msgctxt "'Lat' and 'Lon' as in Latitude and Longitude" msgctxt "'Lat' and 'Lon' as in Latitude and Longitude"
msgid "Lat: %1, Lon: %2" msgid "Lat: %1, Lon: %2"
msgstr "緯度:%2經度%1" msgstr "緯度:%2經度%1"
#: src/notificationsmanager.cpp:120 src/notificationsmanager.cpp:325 #: src/notificationsmanager.cpp:126 src/notificationsmanager.cpp:330
#, kde-format #, kde-format
msgid "Encrypted Message" msgid "Encrypted Message"
msgstr "已加密訊息" msgstr "已加密訊息"
#: src/notificationsmanager.cpp:204 src/qml/Main.qml:279 #: src/notificationsmanager.cpp:210 src/qml/Main.qml:279
#, kde-format #, kde-format
msgid "%1: %2" msgid "%1: %2"
msgstr "%1: %2" msgstr "%1: %2"
#: src/notificationsmanager.cpp:210 #: src/notificationsmanager.cpp:216
#, kde-format #, kde-format
msgid "Open NeoChat in this room" msgid "Open NeoChat in this room"
msgstr "在這個聊天室開啟 NeoChat" msgstr "在這個聊天室開啟 NeoChat"
#: src/notificationsmanager.cpp:223 src/qml/DelegateContextMenu.qml:98 #: src/notificationsmanager.cpp:229 src/qml/DelegateContextMenu.qml:98
#: src/qml/HoverActions.qml:111 #: src/qml/HoverActions.qml:111
#, kde-format #, kde-format
msgid "Reply" msgid "Reply"
msgstr "回覆" msgstr "回覆"
#: src/notificationsmanager.cpp:224 #: src/notificationsmanager.cpp:230
#, kde-format #, kde-format
msgid "Reply..." msgid "Reply..."
msgstr "回覆..." msgstr "回覆..."
#: src/notificationsmanager.cpp:243 #: src/notificationsmanager.cpp:249
#, kde-format #, kde-format
msgid "%1 invited you to a room" msgid "%1 invited you to a room"
msgstr "%1 邀請了您到聊天室" msgstr "%1 邀請了您到聊天室"
#: src/notificationsmanager.cpp:247 #: src/notificationsmanager.cpp:252
#, kde-format #, kde-format
msgid "Open this invitation in NeoChat" msgid "Open this invitation in NeoChat"
msgstr "在 NeoChat 開啟這個邀請" msgstr "在 NeoChat 開啟這個邀請"
#: src/notificationsmanager.cpp:257 #: src/notificationsmanager.cpp:262
#, kde-format #, kde-format
msgctxt "@action:button The thing being accepted is an invitation to chat" msgctxt "@action:button The thing being accepted is an invitation to chat"
msgid "Accept" msgid "Accept"
msgstr "接受" msgstr "接受"
#: src/notificationsmanager.cpp:258 #: src/notificationsmanager.cpp:263
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject" msgid "Reject"
msgstr "拒絕" msgstr "拒絕"
#: src/notificationsmanager.cpp:259 #: src/notificationsmanager.cpp:264
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject and Ignore User" msgid "Reject and Ignore User"
msgstr "拒絕並忽略使用者" msgstr "拒絕並忽略使用者"
#: src/notificationsmanager.cpp:318 #: src/notificationsmanager.cpp:323
#, kde-format #, kde-format
msgid "%1 (%2)" msgid "%1 (%2)"
msgstr "%1 (%2)" msgstr "%1 (%2)"
#: src/notificationsmanager.cpp:329 #: src/notificationsmanager.cpp:334
#, kde-format #, kde-format
msgid "Open NeoChat" msgid "Open NeoChat"
msgstr "開啟 NeoChat" msgstr "開啟 NeoChat"
@@ -2751,18 +2751,23 @@ msgstr "鏡射"
msgid "Accept this invitation?" msgid "Accept this invitation?"
msgstr "接收邀請嗎?" msgstr "接收邀請嗎?"
#: src/qml/InvitationView.qml:21 #: src/qml/InvitationView.qml:18
#, kde-format
msgid "You can reject invitations from unknown users under Security settings."
msgstr "您可以在安全性設定底下設定回絕來自未知使用者的邀請。"
#: src/qml/InvitationView.qml:24
#, kde-format #, kde-format
msgctxt "@action:button The thing being rejected is an invitation to chat" msgctxt "@action:button The thing being rejected is an invitation to chat"
msgid "Reject and ignore user" msgid "Reject and ignore user"
msgstr "拒絕並忽略使用者" msgstr "拒絕並忽略使用者"
#: src/qml/InvitationView.qml:30 #: src/qml/InvitationView.qml:33
#, kde-format #, kde-format
msgid "Reject" msgid "Reject"
msgstr "拒絕" msgstr "拒絕"
#: src/qml/InvitationView.qml:37 src/qml/KeyVerificationDialog.qml:92 #: src/qml/InvitationView.qml:40 src/qml/KeyVerificationDialog.qml:92
#, kde-format #, kde-format
msgid "Accept" msgid "Accept"
msgstr "接受" msgstr "接受"
@@ -3514,27 +3519,27 @@ msgctxt "'Space' is a matrix space"
msgid "Leave Space" msgid "Leave Space"
msgstr "離開聊天空間" msgstr "離開聊天空間"
#: src/qml/TimelineView.qml:195 #: src/qml/TimelineView.qml:196
#, kde-format #, kde-format
msgid "Jump to first unread message" msgid "Jump to first unread message"
msgstr "跳到第一個未讀訊息" msgstr "跳到第一個未讀訊息"
#: src/qml/TimelineView.qml:195 #: src/qml/TimelineView.qml:196
#, kde-format #, kde-format
msgid "Jump to oldest loaded message" msgid "Jump to oldest loaded message"
msgstr "跳到已載入的最舊的訊息" msgstr "跳到已載入的最舊的訊息"
#: src/qml/TimelineView.qml:235 #: src/qml/TimelineView.qml:236
#, kde-format #, kde-format
msgid "Jump to latest message" msgid "Jump to latest message"
msgstr "跳到最新訊息" msgstr "跳到最新訊息"
#: src/qml/TimelineView.qml:260 #: src/qml/TimelineView.qml:261
#, kde-format #, kde-format
msgid "Drag items here to share them" msgid "Drag items here to share them"
msgstr "拖曳項目至此來分享它" msgstr "拖曳項目至此來分享它"
#: src/qml/TimelineView.qml:267 #: src/qml/TimelineView.qml:268
#, kde-format #, kde-format
msgctxt "Message displayed when some users are typing" msgctxt "Message displayed when some users are typing"
msgid "%2 is typing" msgid "%2 is typing"
@@ -3925,27 +3930,27 @@ msgstr "繼續"
msgid "Working" msgid "Working"
msgstr "處理中" msgstr "處理中"
#: src/roommanager.cpp:125 #: src/roommanager.cpp:138
#, kde-format #, kde-format
msgid "Malformed or empty Matrix id" msgid "Malformed or empty Matrix id"
msgstr "不正確或空白的 Matrix ID" msgstr "不正確或空白的 Matrix ID"
#: src/roommanager.cpp:125 #: src/roommanager.cpp:138
#, kde-format #, kde-format
msgid "%1 is not a correct Matrix identifier" msgid "%1 is not a correct Matrix identifier"
msgstr "%1 不是一個正確的 Matrix ID" msgstr "%1 不是一個正確的 Matrix ID"
#: src/roommanager.cpp:337 #: src/roommanager.cpp:345
#, kde-format #, kde-format
msgid "Failed to join room" msgid "Failed to join room"
msgstr "加入聊天室失敗" msgstr "加入聊天室失敗"
#: src/roommanager.cpp:369 #: src/roommanager.cpp:377
#, kde-format #, kde-format
msgid "You requested to join '%1'" msgid "You requested to join '%1'"
msgstr "您已請求加入 '%1'" msgstr "您已請求加入 '%1'"
#: src/roommanager.cpp:373 #: src/roommanager.cpp:381
#, kde-format #, kde-format
msgid "Failed to request joining room" msgid "Failed to request joining room"
msgstr "請求加入聊天室失敗" msgstr "請求加入聊天室失敗"
@@ -4344,7 +4349,7 @@ msgid "Keyword…"
msgstr "關鍵字…" msgstr "關鍵字…"
#: src/settings/GlobalNotificationsPage.qml:116 #: src/settings/GlobalNotificationsPage.qml:116
#: src/settings/Permissions.qml:391 src/settings/PushNotification.qml:119 #: src/settings/Permissions.qml:386 src/settings/PushNotification.qml:119
#, kde-format #, kde-format
msgid "Add keyword" msgid "Add keyword"
msgstr "新增關鍵字" msgstr "新增關鍵字"
@@ -4405,7 +4410,7 @@ msgid "Ignored Users"
msgstr "已忽略的使用者" msgstr "已忽略的使用者"
#: src/settings/IgnoredUsersDialog.qml:24 #: src/settings/IgnoredUsersDialog.qml:24
#: src/settings/NeoChatSecurityPage.qml:37 #: src/settings/NeoChatSecurityPage.qml:35
#, kde-format #, kde-format
msgctxt "@title:group" msgctxt "@title:group"
msgid "Ignored Users" msgid "Ignored Users"
@@ -4535,37 +4540,61 @@ msgstr "安全性"
#: src/settings/NeoChatSecurityPage.qml:20 #: src/settings/NeoChatSecurityPage.qml:20
#, kde-format #, kde-format
msgctxt "@title" msgctxt "@title:group"
msgid "Keys" msgid "Invitations"
msgstr "金鑰" msgstr "邀請"
#: src/settings/NeoChatSecurityPage.qml:24
#, kde-format
msgctxt "@option:check"
msgid "Reject invitations from unknown users"
msgstr "回絕來自未知使用者的邀請"
#: src/settings/NeoChatSecurityPage.qml:25 #: src/settings/NeoChatSecurityPage.qml:25
#, kde-format #, kde-format
msgid "Device key" msgid ""
msgstr "裝置金鑰" "If enabled, NeoChat will reject invitations from from users you don't share "
"a room with."
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:29 #: src/settings/NeoChatSecurityPage.qml:25
#, kde-format #, kde-format
msgid "Encryption key" msgid "Your server does not support this setting."
msgstr "加密金鑰" msgstr "您的伺服器不支援這個設定。"
#: src/settings/NeoChatSecurityPage.qml:33 #: src/settings/NeoChatSecurityPage.qml:39
#, kde-format
msgid "Device id"
msgstr "裝置 ID"
#: src/settings/NeoChatSecurityPage.qml:41
#, kde-format #, kde-format
msgctxt "@action:button" msgctxt "@action:button"
msgid "Manage ignored users" msgid "Manage ignored users"
msgstr "管理已忽略的使用者" msgstr "管理已忽略的使用者"
#: src/settings/NeoChatSecurityPage.qml:43 #: src/settings/NeoChatSecurityPage.qml:41
#, kde-format #, kde-format
msgctxt "@title:window" msgctxt "@title:window"
msgid "Ignored Users" msgid "Ignored Users"
msgstr "已忽略的使用者" msgstr "已忽略的使用者"
#: src/settings/NeoChatSecurityPage.qml:46
#, kde-format
msgctxt "@title"
msgid "Keys"
msgstr "金鑰"
#: src/settings/NeoChatSecurityPage.qml:51
#, kde-format
msgid "Device key"
msgstr "裝置金鑰"
#: src/settings/NeoChatSecurityPage.qml:55
#, kde-format
msgid "Encryption key"
msgstr "加密金鑰"
#: src/settings/NeoChatSecurityPage.qml:59
#, kde-format
msgid "Device id"
msgstr "裝置 ID"
#: src/settings/NeoChatSettingsView.qml:22 src/settings/RoomGeneralPage.qml:22 #: src/settings/NeoChatSettingsView.qml:22 src/settings/RoomGeneralPage.qml:22
#: src/settings/RoomSettingsView.qml:39 #: src/settings/RoomSettingsView.qml:39
#, kde-format #, kde-format
@@ -4719,27 +4748,27 @@ msgctxt "@label:textbox"
msgid "Password:" msgid "Password:"
msgstr "密碼:" msgstr "密碼:"
#: src/settings/Permissions.qml:37 #: src/settings/Permissions.qml:32
#, kde-format #, kde-format
msgid "Privileged Users" msgid "Privileged Users"
msgstr "有權力的使用者" msgstr "有權力的使用者"
#: src/settings/Permissions.qml:238 #: src/settings/Permissions.qml:233
#, kde-format #, kde-format
msgid "Default permissions" msgid "Default permissions"
msgstr "預設權限" msgstr "預設權限"
#: src/settings/Permissions.qml:278 #: src/settings/Permissions.qml:273
#, kde-format #, kde-format
msgid "Basic permissions" msgid "Basic permissions"
msgstr "基本權限" msgstr "基本權限"
#: src/settings/Permissions.qml:318 #: src/settings/Permissions.qml:313
#, kde-format #, kde-format
msgid "Event permissions" msgid "Event permissions"
msgstr "事件fm0vu0" msgstr "事件fm0vu0"
#: src/settings/Permissions.qml:365 #: src/settings/Permissions.qml:360
#, kde-format #, kde-format
msgid "Event Type…" msgid "Event Type…"
msgstr "事件類型…" msgstr "事件類型…"
@@ -5207,14 +5236,14 @@ msgid ""
"device." "device."
msgstr "這個訊息已加密而傳送者並未與本裝置分享金鑰。" msgstr "這個訊息已加密而傳送者並未與本裝置分享金鑰。"
#: src/timeline/FileComponent.qml:107 src/timeline/FileComponent.qml:190 #: src/timeline/FileComponent.qml:103 src/timeline/FileComponent.qml:186
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; offers ability to download its file" "tooltip for a button on a message; offers ability to download its file"
msgid "Download" msgid "Download"
msgstr "下載" msgstr "下載"
#: src/timeline/FileComponent.qml:123 src/timeline/FileComponent.qml:180 #: src/timeline/FileComponent.qml:119 src/timeline/FileComponent.qml:176
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; offers ability to open its downloaded " "tooltip for a button on a message; offers ability to open its downloaded "
@@ -5222,13 +5251,13 @@ msgctxt ""
msgid "Open File" msgid "Open File"
msgstr "開啟檔案" msgstr "開啟檔案"
#: src/timeline/FileComponent.qml:138 #: src/timeline/FileComponent.qml:134
#, kde-format #, kde-format
msgctxt "file download progress" msgctxt "file download progress"
msgid "%1 / %2" msgid "%1 / %2"
msgstr "%1 / %2" msgstr "%1 / %2"
#: src/timeline/FileComponent.qml:143 #: src/timeline/FileComponent.qml:139
#, kde-format #, kde-format
msgctxt "" msgctxt ""
"tooltip for a button on a message; stops downloading the message's file" "tooltip for a button on a message; stops downloading the message's file"
@@ -5314,7 +5343,7 @@ msgctxt "as in 'this vote has ended'"
msgid "(Ended)" msgid "(Ended)"
msgstr "(已結束)" msgstr "(已結束)"
#: src/timeline/ReadMarkerDelegate.qml:39 #: src/timeline/ReadMarkerDelegate.qml:42
#, kde-format #, kde-format
msgctxt "Relative time since the room was last read" msgctxt "Relative time since the room was last read"
msgid "Last read: %1" msgid "Last read: %1"
@@ -5333,18 +5362,18 @@ msgstr "這是此聊天的開頭。沒有比這更早的歷史訊息。"
msgid "Pl. %1" msgid "Pl. %1"
msgstr "第 %1 月台" msgstr "第 %1 月台"
#: src/timeline/VideoComponent.qml:171 #: src/timeline/VideoComponent.qml:197
#, kde-format #, kde-format
msgid "Video" msgid "Video"
msgstr "影片" msgstr "影片"
#: src/timeline/VideoComponent.qml:235 #: src/timeline/VideoComponent.qml:261
#, kde-format #, kde-format
msgctxt "@action:button" msgctxt "@action:button"
msgid "Volume" msgid "Volume"
msgstr "音量" msgstr "音量"
#: src/timeline/VideoComponent.qml:319 #: src/timeline/VideoComponent.qml:345
#, kde-format #, kde-format
msgid "Maximize" msgid "Maximize"
msgstr "最大化" msgstr "最大化"

View File

@@ -134,6 +134,8 @@ add_library(neochat STATIC
jobs/neochatdeletedevicejob.h jobs/neochatdeletedevicejob.h
jobs/neochatchangepasswordjob.cpp jobs/neochatchangepasswordjob.cpp
jobs/neochatchangepasswordjob.h jobs/neochatchangepasswordjob.h
jobs/neochatgetcommonroomsjob.cpp
jobs/neochatgetcommonroomsjob.h
mediasizehelper.cpp mediasizehelper.cpp
mediasizehelper.h mediasizehelper.h
eventhandler.cpp eventhandler.cpp
@@ -186,6 +188,10 @@ add_library(neochat STATIC
models/permissionsmodel.h models/permissionsmodel.h
threepidbindhelper.cpp threepidbindhelper.cpp
threepidbindhelper.h threepidbindhelper.h
models/readmarkermodel.cpp
models/readmarkermodel.h
neochatroommember.cpp
neochatroommember.h
) )
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES

View File

@@ -61,20 +61,6 @@ MessageComponentType::Type EventHandler::messageComponentType() const
return MessageComponentType::typeForEvent(*m_event); return MessageComponentType::typeForEvent(*m_event);
} }
Quotient::RoomMember EventHandler::getAuthor(bool isPending) const
{
if (m_room == nullptr) {
qCWarning(EventHandling) << "getAuthor called with m_room set to nullptr.";
return {};
}
if (m_event == nullptr) {
qCWarning(EventHandling) << "getAuthor called with m_event set to nullptr. Returning empty user.";
return {};
}
return isPending ? m_room->localMember() : m_room->member(m_event->senderId());
}
QString EventHandler::getAuthorDisplayName(bool isPending) const QString EventHandler::getAuthorDisplayName(bool isPending) const
{ {
if (m_room == nullptr) { if (m_room == nullptr) {
@@ -157,6 +143,11 @@ QString EventHandler::getTimeString(bool relative, QLocale::FormatType format, b
return {}; return {};
} }
QString EventHandler::getTimeString(const QString &format, bool isPending, const QDateTime &lastUpdated)
{
return getTime(isPending, lastUpdated).toLocalTime().toString(format);
}
bool EventHandler::isHighlighted() bool EventHandler::isHighlighted()
{ {
if (m_room == nullptr) { if (m_room == nullptr) {
@@ -241,17 +232,19 @@ Qt::TextFormat EventHandler::messageBodyInputFormat(const Quotient::RoomMessageE
QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event) QString EventHandler::rawMessageBody(const Quotient::RoomMessageEvent &event)
{ {
QString body;
if (event.hasFileContent()) { if (event.hasFileContent()) {
auto fileCaption = event.content()->fileInfo()->originalName; // if filename is given or body is equal to filename,
if (fileCaption.isEmpty()) { // then body is a caption
fileCaption = event.plainBody(); QString filename = event.content()->fileInfo()->originalName;
} else if (event.content()->fileInfo()->originalName != event.plainBody()) { QString body = event.plainBody();
fileCaption = event.plainBody() + " | "_ls + fileCaption; if (filename.isEmpty() || filename == body) {
return QString();
} }
return fileCaption; return body;
} }
QString body;
if (event.hasTextContent() && event.content()) { if (event.hasTextContent() && event.content()) {
body = static_cast<const EventContent::TextContent *>(event.content())->body; body = static_cast<const EventContent::TextContent *>(event.content())->body;
} else { } else {
@@ -660,23 +653,30 @@ QVariantMap EventHandler::getMediaInfoForEvent(const Quotient::RoomEvent *event)
QString eventId = event->id(); QString eventId = event->id();
// Get the file info for the event. // Get the file info for the event.
const EventContent::FileInfo *fileInfo;
bool isSticker = false;
if (event->is<RoomMessageEvent>()) { if (event->is<RoomMessageEvent>()) {
auto roomMessageEvent = eventCast<const RoomMessageEvent>(event); auto roomMessageEvent = eventCast<const RoomMessageEvent>(event);
if (!roomMessageEvent->hasFileContent()) { if (!roomMessageEvent->hasFileContent()) {
return {}; return {};
} }
const EventContent::FileInfo *fileInfo;
fileInfo = roomMessageEvent->content()->fileInfo(); fileInfo = roomMessageEvent->content()->fileInfo();
QVariantMap mediaInfo = getMediaInfoFromFileInfo(fileInfo, eventId, false, false);
// if filename isn't specifically given, it is in body
// https://spec.matrix.org/latest/client-server-api/#mfile
mediaInfo["filename"_ls] = (fileInfo->originalName.isEmpty()) ? roomMessageEvent->plainBody() : fileInfo->originalName;
return mediaInfo;
} else if (event->is<StickerEvent>()) { } else if (event->is<StickerEvent>()) {
const EventContent::FileInfo *fileInfo;
auto stickerEvent = eventCast<const StickerEvent>(event); auto stickerEvent = eventCast<const StickerEvent>(event);
fileInfo = &stickerEvent->image(); fileInfo = &stickerEvent->image();
isSticker = true;
return getMediaInfoFromFileInfo(fileInfo, eventId, false, true);
} else { } else {
return {}; return {};
} }
return getMediaInfoFromFileInfo(fileInfo, eventId, false, isSticker);
} }
QVariantMap EventHandler::getMediaInfoFromFileInfo(const EventContent::FileInfo *fileInfo, const QString &eventId, bool isThumbnail, bool isSticker) const QVariantMap EventHandler::getMediaInfoFromFileInfo(const EventContent::FileInfo *fileInfo, const QString &eventId, bool isThumbnail, bool isSticker) const
@@ -952,102 +952,4 @@ QString EventHandler::getLocationAssetType() const
return assetType; return assetType;
} }
bool EventHandler::hasReadMarkers() const
{
if (m_room == nullptr) {
qCWarning(EventHandling) << "hasReadMarkers called with m_room set to nullptr.";
return false;
}
if (m_event == nullptr) {
qCWarning(EventHandling) << "hasReadMarkers called with m_event set to nullptr.";
return false;
}
auto userIds = m_room->userIdsAtEvent(m_event->id());
userIds.remove(m_room->localMember().id());
return userIds.size() > 0;
}
QList<Quotient::RoomMember> EventHandler::getReadMarkers(int maxMarkers) const
{
if (m_room == nullptr) {
qCWarning(EventHandling) << "getReadMarkers called with m_room set to nullptr.";
return {};
}
if (m_event == nullptr) {
qCWarning(EventHandling) << "getReadMarkers called with m_event set to nullptr.";
return {};
}
auto userIds_temp = m_room->userIdsAtEvent(m_event->id());
userIds_temp.remove(m_room->localMember().id());
auto userIds = userIds_temp.values();
if (userIds.count() > maxMarkers) {
userIds = userIds.mid(0, maxMarkers);
}
QList<Quotient::RoomMember> users;
users.reserve(userIds.size());
for (const auto &userId : userIds) {
users += m_room->member(userId);
}
return users;
}
QString EventHandler::getNumberExcessReadMarkers(int maxMarkers) const
{
if (m_room == nullptr) {
qCWarning(EventHandling) << "getNumberExcessReadMarkers called with m_room set to nullptr.";
return {};
}
if (m_event == nullptr) {
qCWarning(EventHandling) << "getNumberExcessReadMarkers called with m_event set to nullptr.";
return {};
}
auto userIds = m_room->userIdsAtEvent(m_event->id());
userIds.remove(m_room->localMember().id());
if (userIds.count() > maxMarkers) {
return QStringLiteral("+ ") + QString::number(userIds.count() - maxMarkers);
} else {
return QString();
}
}
QString EventHandler::getReadMarkersString() const
{
if (m_room == nullptr) {
qCWarning(EventHandling) << "getReadMarkersString called with m_room set to nullptr.";
return {};
}
if (m_event == nullptr) {
qCWarning(EventHandling) << "getReadMarkersString called with m_event set to nullptr.";
return {};
}
auto userIds = m_room->userIdsAtEvent(m_event->id());
userIds.remove(m_room->localMember().id());
/**
* The string ends up in the form
* "x users: user1DisplayName, user2DisplayName, etc."
*/
QString readMarkersString = i18np("1 user: ", "%1 users: ", userIds.size());
for (const auto &userId : userIds) {
auto member = m_room->member(userId);
QString displayName;
if (!m_room->memberIds().contains(userId)) {
displayName = i18nc("A member who is not in the room has been requested.", "unknown member");
} else {
displayName = member.displayName();
}
readMarkersString += displayName + i18nc("list separator", ", ");
}
readMarkersString.chop(2);
return readMarkersString;
}
#include "moc_eventhandler.cpp" #include "moc_eventhandler.cpp"

View File

@@ -53,25 +53,10 @@ public:
*/ */
MessageComponentType::Type messageComponentType() const; MessageComponentType::Type messageComponentType() const;
/**
* @brief Get the author of the event in context of the room.
*
* An empty Quotient::RoomMember will be returned if the EventHandler hasn't had
* the room or event initialised.
*
* @param isPending if the event is pending, i.e. has not been confirmed by
* the server.
*
* @return a Quotient::RoomMember object for the user.
*
* @sa Quotient::RoomMember
*/
Quotient::RoomMember getAuthor(bool isPending = false) const;
/** /**
* @brief Get the display name of the event author. * @brief Get the display name of the event author.
* *
* This method is separate from getAuthor() and special in that it will return * This method is special in that it will return
* the old display name of the author if the current event is one that caused it * the old display name of the author if the current event is one that caused it
* to change. This allows for scenarios where the UI wishes to notify that a * to change. This allows for scenarios where the UI wishes to notify that a
* user's display name has changed and what it changed from. * user's display name has changed and what it changed from.
@@ -113,6 +98,8 @@ public:
*/ */
QString getTimeString(bool relative, QLocale::FormatType format = QLocale::ShortFormat, bool isPending = false, QDateTime lastUpdated = {}) const; QString getTimeString(bool relative, QLocale::FormatType format = QLocale::ShortFormat, bool isPending = false, QDateTime lastUpdated = {}) const;
QString getTimeString(const QString &format, bool isPending = false, const QDateTime &lastUpdated = {});
/** /**
* @brief Whether the event should be highlighted in the timeline. * @brief Whether the event should be highlighted in the timeline.
* *
@@ -342,43 +329,6 @@ public:
*/ */
QString getLocationAssetType() const; QString getLocationAssetType() const;
/**
* @brief Whether the event has any read marker for other users.
*/
bool hasReadMarkers() const;
/**
* @brief Returns a list of user read marker for the event.
*
* @param maxMarkers the maximum number of users to return. Usually the number
* of user read makers shown is limited to not clutter the UI.
* This needs to be the same as used in getNumberExcessReadMarkers
* so that the markers line up with the number displayed, i.e.
* the number of users shown plus the excess number will be
* the total number of other user read markers at an event.
*/
QList<Quotient::RoomMember> getReadMarkers(int maxMarkers = 5) const;
/**
* @brief Returns the number of excess user read markers for the event.
*
* This returns a string in the form "+ x" ready for use in the UI.
*
* @param maxMarkers the maximum number of markers shown in the UI. This needs to
* be the same as used in getReadMarkers so that the value lines
* up with the number displayed, i.e. the number of users shown
* plus the excess number will be the total number of other user
* read markers at an event.
*/
QString getNumberExcessReadMarkers(int maxMarkers = 5) const;
/**
* @brief Returns a string with the names of the read markers at the event.
*
* This is in the form "x users: name 1, name 2, ...".
*/
QString getReadMarkersString() const;
private: private:
const NeoChatRoom *m_room = nullptr; const NeoChatRoom *m_room = nullptr;
const Quotient::RoomEvent *m_event = nullptr; const Quotient::RoomEvent *m_event = nullptr;

View File

@@ -51,9 +51,3 @@ struct ForeignSSSSHandler {
QML_FOREIGN(Quotient::SSSSHandler) QML_FOREIGN(Quotient::SSSSHandler)
QML_NAMED_ELEMENT(SSSSHandler) QML_NAMED_ELEMENT(SSSSHandler)
}; };
struct RoomMemberForeign {
Q_GADGET
QML_FOREIGN(Quotient::RoomMember)
QML_NAMED_ELEMENT(RoomMember)
};

View File

@@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "neochatgetcommonroomsjob.h"
using namespace Quotient;
NeochatGetCommonRoomsJob::NeochatGetCommonRoomsJob(const QString &userId)
: BaseJob(HttpVerb::Get,
QStringLiteral("GetCommonRoomsJob"),
QStringLiteral("/_matrix/client/unstable/uk.half-shot.msc2666/user/mutual_rooms").toLatin1(),
QUrlQuery({{QStringLiteral("user_id"), userId}}))
{
}

View File

@@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <Quotient/jobs/basejob.h>
#include <Quotient/omittable.h>
// TODO: Upstream to libQuotient
class NeochatGetCommonRoomsJob : public Quotient::BaseJob
{
public:
explicit NeochatGetCommonRoomsJob(const QString &userId);
};

View File

@@ -9,18 +9,16 @@
#include "customemojimodel.h" #include "customemojimodel.h"
#include "emojimodel.h" #include "emojimodel.h"
#include "neochatroom.h" #include "neochatroom.h"
#include "roommanager.h"
#include "userlistmodel.h" #include "userlistmodel.h"
CompletionModel::CompletionModel(QObject *parent) CompletionModel::CompletionModel(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_filterModel(new CompletionProxyModel()) , m_filterModel(new CompletionProxyModel())
, m_userListModel(new UserListModel(this)) , m_userListModel(RoomManager::instance().userListModel())
, m_emojiModel(new QConcatenateTablesProxyModel(this)) , m_emojiModel(new QConcatenateTablesProxyModel(this))
{ {
connect(this, &CompletionModel::textChanged, this, &CompletionModel::updateCompletion); connect(this, &CompletionModel::textChanged, this, &CompletionModel::updateCompletion);
connect(this, &CompletionModel::roomChanged, this, [this]() {
m_userListModel->setRoom(m_room);
});
m_emojiModel->addSourceModel(&CustomEmojiModel::instance()); m_emojiModel->addSourceModel(&CustomEmojiModel::instance());
m_emojiModel->addSourceModel(&EmojiModel::instance()); m_emojiModel->addSourceModel(&EmojiModel::instance());
} }

View File

@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "customemojimodel.h"
#include <QRegularExpression>
class NeoChatConnection;
struct CustomEmoji {
QString name; // with :semicolons:
QString url; // mxc://
QRegularExpression regexp;
};
struct CustomEmojiModel::Private {
QPointer<NeoChatConnection> connection;
QList<CustomEmoji> emojies;
};

View File

@@ -26,7 +26,7 @@ int EmojiModel::rowCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
int total = 0; int total = 0;
for (const auto &category : _emojis) { for (const auto &category : std::as_const(_emojis)) {
total += category.count(); total += category.count();
} }
return total; return total;
@@ -35,7 +35,7 @@ int EmojiModel::rowCount(const QModelIndex &parent) const
QVariant EmojiModel::data(const QModelIndex &index, int role) const QVariant EmojiModel::data(const QModelIndex &index, int role) const
{ {
auto row = index.row(); auto row = index.row();
for (const auto &category : _emojis) { for (const auto &category : std::as_const(_emojis)) {
if (row >= category.count()) { if (row >= category.count()) {
row -= category.count(); row -= category.count();
continue; continue;
@@ -79,7 +79,8 @@ QVariantList EmojiModel::filterModelNoCustom(const QString &filter, bool limit)
{ {
QVariantList result; QVariantList result;
for (const auto &e : _emojis.values()) { const auto &values = _emojis.values();
for (const auto &e : values) {
for (const auto &variant : e) { for (const auto &variant : e) {
const auto &emoji = qvariant_cast<Emoji>(variant); const auto &emoji = qvariant_cast<Emoji>(variant);
if (emoji.shortName.contains(filter, Qt::CaseInsensitive)) { if (emoji.shortName.contains(filter, Qt::CaseInsensitive)) {
@@ -121,7 +122,8 @@ QVariantList EmojiModel::emojis(Category category) const
} }
if (category == HistoryNoCustom) { if (category == HistoryNoCustom) {
QVariantList list; QVariantList list;
for (const auto &e : emojiHistory()) { const auto &history = emojiHistory();
for (const auto &e : history) {
auto emoji = qvariant_cast<Emoji>(e); auto emoji = qvariant_cast<Emoji>(e);
if (!emoji.isCustom) { if (!emoji.isCustom) {
list.append(e); list.append(e);
@@ -224,8 +226,9 @@ QVariantList EmojiModel::categoriesWithCustom() const
QVariantList EmojiModel::emojiHistory() const QVariantList EmojiModel::emojiHistory() const
{ {
QVariantList list; QVariantList list;
for (const auto &historicEmoji : lastUsedEmojis()) { const auto &lastUsed = lastUsedEmojis();
for (const auto &emojiCategory : _emojis) { for (const auto &historicEmoji : lastUsed) {
for (const auto &emojiCategory : std::as_const(_emojis)) {
for (const auto &emoji : emojiCategory) { for (const auto &emoji : emojiCategory) {
if (qvariant_cast<Emoji>(emoji).shortName == historicEmoji) { if (qvariant_cast<Emoji>(emoji).shortName == historicEmoji) {
list.append(emoji); list.append(emoji);

View File

@@ -30,40 +30,6 @@ bool MediaMessageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex
QVariant MediaMessageFilterModel::data(const QModelIndex &index, int role) const QVariant MediaMessageFilterModel::data(const QModelIndex &index, int role) const
{ {
if (role == SourceRole) {
if (mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QLatin1String("mimeType")].toString().contains(QLatin1String("image"))) {
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QStringLiteral("source")].toUrl();
} else if (mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QLatin1String("mimeType")].toString().contains(QLatin1String("video"))) {
auto progressInfo = mapToSource(index).data(MessageEventModel::ProgressInfoRole).value<Quotient::FileTransferInfo>();
if (progressInfo.completed()) {
return mapToSource(index).data(MessageEventModel::ProgressInfoRole).value<Quotient::FileTransferInfo>().localPath;
} else {
return QUrl();
}
} else {
return QUrl();
}
}
if (role == TempSourceRole) {
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QStringLiteral("tempInfo")].toMap()[QStringLiteral("source")].toUrl();
}
if (role == TypeRole) {
if (mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QLatin1String("mimeType")].toString().contains(QLatin1String("image"))) {
return MediaType::Image;
} else {
return MediaType::Video;
}
}
if (role == CaptionRole) {
return mapToSource(index).data(Qt::DisplayRole);
}
if (role == SourceWidthRole) {
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QStringLiteral("width")].toFloat();
}
if (role == SourceHeightRole) {
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()[QStringLiteral("height")].toFloat();
}
// We need to catch this one and return true if the next media object was // We need to catch this one and return true if the next media object was
// on a different day. // on a different day.
if (role == MessageEventModel::ShowSectionRole) { if (role == MessageEventModel::ShowSectionRole) {
@@ -80,6 +46,37 @@ QVariant MediaMessageFilterModel::data(const QModelIndex &index, int role) const
return QVariant::fromValue<MessageContentModel *>(model); return QVariant::fromValue<MessageContentModel *>(model);
} }
QVariantMap mediaInfo = mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap();
if (role == TempSourceRole) {
return mediaInfo[QStringLiteral("tempInfo")].toMap()[QStringLiteral("source")].toUrl();
}
if (role == CaptionRole) {
return mapToSource(index).data(Qt::DisplayRole);
}
if (role == SourceWidthRole) {
return mediaInfo[QStringLiteral("width")].toFloat();
}
if (role == SourceHeightRole) {
return mediaInfo[QStringLiteral("height")].toFloat();
}
bool isVideo = mediaInfo[QStringLiteral("mimeType")].toString().contains(QStringLiteral("video"));
if (role == TypeRole) {
return (isVideo) ? MediaType::Video : MediaType::Image;
}
if (role == SourceRole) {
if (isVideo) {
auto progressInfo = mapToSource(index).data(MessageEventModel::ProgressInfoRole).value<Quotient::FileTransferInfo>();
if (progressInfo.completed()) {
return mapToSource(index).data(MessageEventModel::ProgressInfoRole).value<Quotient::FileTransferInfo>().localPath;
}
} else {
return mediaInfo[QStringLiteral("source")].toUrl();
}
}
return sourceModel()->data(mapToSource(index), role); return sourceModel()->data(mapToSource(index), role);
} }

View File

@@ -3,6 +3,7 @@
#include "messagecontentmodel.h" #include "messagecontentmodel.h"
#include "neochatconfig.h" #include "neochatconfig.h"
#include "neochatroommember.h"
#include <QImageReader> #include <QImageReader>
@@ -35,10 +36,10 @@ MessageContentModel::MessageContentModel(NeoChatRoom *room, const Quotient::Room
, m_room(room) , m_room(room)
, m_eventId(event != nullptr ? event->id() : QString()) , m_eventId(event != nullptr ? event->id() : QString())
, m_eventSenderId(event != nullptr ? event->senderId() : QString()) , m_eventSenderId(event != nullptr ? event->senderId() : QString())
, m_event(loadEvent<RoomEvent>(event->fullJson()))
, m_isPending(isPending) , m_isPending(isPending)
, m_isReply(isReply) , m_isReply(isReply)
{ {
intiializeEvent(event);
initializeModel(); initializeModel();
} }
@@ -81,8 +82,7 @@ void MessageContentModel::initializeModel()
if (m_eventId == serverEvent->id()) { if (m_eventId == serverEvent->id()) {
beginResetModel(); beginResetModel();
m_isPending = false; m_isPending = false;
m_event = loadEvent<RoomEvent>(serverEvent->fullJson()); intiializeEvent(serverEvent);
Q_EMIT eventUpdated();
endResetModel(); endResetModel();
} }
} }
@@ -91,8 +91,7 @@ void MessageContentModel::initializeModel()
if (m_room != nullptr && m_event != nullptr) { if (m_room != nullptr && m_event != nullptr) {
if (m_eventId == newEvent->id()) { if (m_eventId == newEvent->id()) {
beginResetModel(); beginResetModel();
m_event = loadEvent<RoomEvent>(newEvent->fullJson()); intiializeEvent(newEvent);
Q_EMIT eventUpdated();
endResetModel(); endResetModel();
} }
} }
@@ -108,24 +107,9 @@ void MessageContentModel::initializeModel()
} }
}); });
connect(m_room, &NeoChatRoom::fileTransferCompleted, this, [this](const QString &eventId) { connect(m_room, &NeoChatRoom::fileTransferCompleted, this, [this](const QString &eventId) {
if (m_event != nullptr && eventId == m_eventId) { if (m_room != nullptr && m_event != nullptr && eventId == m_eventId) {
resetContent(); resetContent();
Q_EMIT dataChanged(index(0), index(rowCount() - 1), {FileTransferInfoRole}); Q_EMIT dataChanged(index(0), index(rowCount() - 1), {FileTransferInfoRole});
QString mxcUrl;
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
if (event->hasFileContent()) {
mxcUrl = event->content()->fileInfo()->url().toString();
}
} else if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) {
mxcUrl = event->image().fileInfo()->url().toString();
}
if (mxcUrl.isEmpty()) {
return;
}
auto localPath = m_room->fileTransferInfo(m_eventId).localPath.toLocalFile();
auto config = KSharedConfig::openStateConfig(QStringLiteral("neochatdownloads"))->group(QStringLiteral("downloads"));
config.writePathEntry(mxcUrl.mid(6), localPath);
} }
}); });
connect(m_room, &NeoChatRoom::fileTransferFailed, this, [this](const QString &eventId) { connect(m_room, &NeoChatRoom::fileTransferFailed, this, [this](const QString &eventId) {
@@ -169,6 +153,29 @@ void MessageContentModel::initializeModel()
resetModel(); resetModel();
} }
void MessageContentModel::intiializeEvent(const QString &eventId)
{
const auto newEvent = m_room->getEvent(eventId);
if (newEvent != nullptr) {
intiializeEvent(newEvent);
}
}
void MessageContentModel::intiializeEvent(const Quotient::RoomEvent *event)
{
m_event = loadEvent<RoomEvent>(event->fullJson());
auto senderId = event->senderId();
// A pending event might not have a sender ID set yet but in that case it must
// be the local member.
if (senderId.isEmpty()) {
senderId = m_room->localMember().id();
}
if (m_eventSenderObject == nullptr) {
m_eventSenderObject = std::unique_ptr<NeochatRoomMember>(new NeochatRoomMember(m_room, senderId));
}
Q_EMIT eventUpdated();
}
bool MessageContentModel::showAuthor() const bool MessageContentModel::showAuthor() const
{ {
return m_showAuthor; return m_showAuthor;
@@ -251,16 +258,16 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const
}); });
auto lastUpdated = pendingIt == m_room->pendingEvents().cend() ? QDateTime() : pendingIt->lastUpdated(); auto lastUpdated = pendingIt == m_room->pendingEvents().cend() ? QDateTime() : pendingIt->lastUpdated();
return eventHandler.getTimeString(false, QLocale::ShortFormat, m_isPending, lastUpdated); return eventHandler.getTimeString(QStringLiteral("hh:mm"), m_isPending, lastUpdated);
} }
if (role == AuthorRole) { if (role == AuthorRole) {
return QVariant::fromValue(eventHandler.getAuthor(m_isPending)); return QVariant::fromValue<NeochatRoomMember *>(m_eventSenderObject.get());
} }
if (role == MediaInfoRole) { if (role == MediaInfoRole) {
return eventHandler.getMediaInfo(); return eventHandler.getMediaInfo();
} }
if (role == FileTransferInfoRole) { if (role == FileTransferInfoRole) {
return QVariant::fromValue(fileInfo()); return QVariant::fromValue(m_room->cachedFileTransferInfo(m_event.get()));
} }
if (role == ItineraryModelRole) { if (role == ItineraryModelRole) {
return QVariant::fromValue<ItineraryModel *>(m_itineraryModel); return QVariant::fromValue<ItineraryModel *>(m_itineraryModel);
@@ -437,27 +444,37 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
QList<MessageComponent> components; QList<MessageComponent> components;
components += MessageComponent{MessageComponentType::File, QString(), {}}; components += MessageComponent{MessageComponentType::File, QString(), {}};
const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event); const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event);
auto body = EventHandler::rawMessageBody(*event);
components += TextHandler().textComponents(body, EventHandler::messageBodyInputFormat(*event), m_room, event, event->isReplaced());
if (m_emptyItinerary) { if (m_emptyItinerary) {
auto fileTransferInfo = fileInfo(); if (!m_isReply) {
auto fileTransferInfo = m_room->cachedFileTransferInfo(m_event.get());
#ifndef Q_OS_ANDROID #ifndef Q_OS_ANDROID
KSyntaxHighlighting::Repository repository; Q_ASSERT(event->content() != nullptr && event->content()->fileInfo() != nullptr);
const auto definitionForFile = repository.definitionForFileName(fileTransferInfo.localPath.toString()); const QMimeType mimeType = event->content()->fileInfo()->mimeType;
if (definitionForFile.isValid() || QFileInfo(fileTransferInfo.localPath.path()).suffix() == QStringLiteral("txt")) { if (mimeType.name() == QStringLiteral("text/plain") || mimeType.parentMimeTypes().contains(QStringLiteral("text/plain"))) {
QFile file(fileTransferInfo.localPath.path()); QString originalName = event->content()->fileInfo()->originalName;
file.open(QIODevice::ReadOnly); if (originalName.isEmpty()) {
components += MessageComponent{MessageComponentType::Code, originalName = event->plainBody();
QString::fromStdString(file.readAll().toStdString()), }
{{QStringLiteral("class"), definitionForFile.name()}}}; KSyntaxHighlighting::Repository repository;
} KSyntaxHighlighting::Definition definitionForFile = repository.definitionForFileName(originalName);
if (!definitionForFile.isValid()) {
definitionForFile = repository.definitionForMimeType(mimeType.name());
}
QFile file(fileTransferInfo.localPath.path());
file.open(QIODevice::ReadOnly);
components += MessageComponent{MessageComponentType::Code,
QString::fromStdString(file.readAll().toStdString()),
{{QStringLiteral("class"), definitionForFile.name()}}};
}
#endif #endif
if (FileType::instance().fileHasImage(fileTransferInfo.localPath)) { if (FileType::instance().fileHasImage(fileTransferInfo.localPath)) {
QImageReader reader(fileTransferInfo.localPath.path()); QImageReader reader(fileTransferInfo.localPath.path());
components += MessageComponent{MessageComponentType::Pdf, QString(), {{QStringLiteral("size"), reader.size()}}}; components += MessageComponent{MessageComponentType::Pdf, QString(), {{QStringLiteral("size"), reader.size()}}};
}
} }
} else if (m_itineraryModel != nullptr) { } else if (m_itineraryModel != nullptr) {
components += MessageComponent{MessageComponentType::Itinerary, QString(), {}}; components += MessageComponent{MessageComponentType::Itinerary, QString(), {}};
@@ -467,9 +484,12 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
} else { } else {
updateItineraryModel(); updateItineraryModel();
} }
auto body = EventHandler::rawMessageBody(*event);
components += TextHandler().textComponents(body, EventHandler::messageBodyInputFormat(*event), m_room, event, event->isReplaced());
return components; return components;
} }
case MessageComponentType::Image: case MessageComponentType::Image:
case MessageComponentType::Audio:
case MessageComponentType::Video: { case MessageComponentType::Video: {
if (!m_event->is<StickerEvent>()) { if (!m_event->is<StickerEvent>()) {
const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event); const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event);
@@ -552,7 +572,7 @@ void MessageContentModel::updateItineraryModel()
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) { if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
if (event->hasFileContent()) { if (event->hasFileContent()) {
auto filePath = fileInfo().localPath; auto filePath = m_room->cachedFileTransferInfo(m_event.get()).localPath;
if (filePath.isEmpty() && m_itineraryModel != nullptr) { if (filePath.isEmpty() && m_itineraryModel != nullptr) {
delete m_itineraryModel; delete m_itineraryModel;
m_itineraryModel = nullptr; m_itineraryModel = nullptr;
@@ -580,42 +600,4 @@ void MessageContentModel::updateItineraryModel()
} }
} }
FileTransferInfo MessageContentModel::fileInfo() const
{
if (m_room == nullptr || m_event == nullptr) {
return {};
}
QString mxcUrl;
int total;
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
if (event->hasFileContent()) {
mxcUrl = event->content()->fileInfo()->url().toString();
total = event->content()->fileInfo()->payloadSize;
}
} else if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) {
mxcUrl = event->image().fileInfo()->url().toString();
total = event->image().fileInfo()->payloadSize;
}
auto config = KSharedConfig::openStateConfig(QStringLiteral("neochatdownloads"))->group(QStringLiteral("downloads"));
if (!config.hasKey(mxcUrl.mid(6))) {
return m_room->fileTransferInfo(m_eventId);
}
const auto path = config.readPathEntry(mxcUrl.mid(6), QString());
QFileInfo info(path);
if (!info.isFile()) {
config.deleteEntry(mxcUrl);
return m_room->fileTransferInfo(m_eventId);
}
// TODO: we could check the hash here
return FileTransferInfo{
.status = FileTransferInfo::Completed,
.isUpload = false,
.progress = total,
.total = total,
.localDir = QUrl(info.dir().path()),
.localPath = QUrl::fromLocalFile(path),
};
}
#include "moc_messagecontentmodel.cpp" #include "moc_messagecontentmodel.cpp"

View File

@@ -6,11 +6,13 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QQmlEngine> #include <QQmlEngine>
#include <Quotient/events/roomevent.h>
#include <Quotient/room.h> #include <Quotient/room.h>
#include "enums/messagecomponenttype.h" #include "enums/messagecomponenttype.h"
#include "eventhandler.h" #include "eventhandler.h"
#include "itinerarymodel.h" #include "itinerarymodel.h"
#include "neochatroommember.h"
struct MessageComponent { struct MessageComponent {
MessageComponentType::Type type = MessageComponentType::Other; MessageComponentType::Type type = MessageComponentType::Other;
@@ -115,6 +117,7 @@ private:
QPointer<NeoChatRoom> m_room; QPointer<NeoChatRoom> m_room;
QString m_eventId; QString m_eventId;
QString m_eventSenderId; QString m_eventSenderId;
std::unique_ptr<NeochatRoomMember> m_eventSenderObject = nullptr;
Quotient::RoomEventPtr m_event; Quotient::RoomEventPtr m_event;
bool m_isPending; bool m_isPending;
@@ -122,6 +125,8 @@ private:
bool m_isReply; bool m_isReply;
void initializeModel(); void initializeModel();
void intiializeEvent(const QString &eventId);
void intiializeEvent(const Quotient::RoomEvent *event);
QList<MessageComponent> m_components; QList<MessageComponent> m_components;
void resetModel(); void resetModel();
@@ -141,6 +146,4 @@ private:
void updateItineraryModel(); void updateItineraryModel();
bool m_emptyItinerary = false; bool m_emptyItinerary = false;
Quotient::FileTransferInfo fileInfo() const;
}; };

View File

@@ -26,6 +26,9 @@
#include "messagecontentmodel.h" #include "messagecontentmodel.h"
#include "models/messagefiltermodel.h" #include "models/messagefiltermodel.h"
#include "models/reactionmodel.h" #include "models/reactionmodel.h"
#include "neochatroom.h"
#include "neochatroommember.h"
#include "readmarkermodel.h"
#include "texthandler.h" #include "texthandler.h"
using namespace Quotient; using namespace Quotient;
@@ -45,8 +48,6 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
roles[ThreadRootRole] = "threadRoot"; roles[ThreadRootRole] = "threadRoot";
roles[ShowSectionRole] = "showSection"; roles[ShowSectionRole] = "showSection";
roles[ReadMarkersRole] = "readMarkers"; roles[ReadMarkersRole] = "readMarkers";
roles[ExcessReadMarkersRole] = "excessReadMarkers";
roles[ReadMarkersStringRole] = "readMarkersString";
roles[ShowReadMarkersRole] = "showReadMarkers"; roles[ShowReadMarkersRole] = "showReadMarkers";
roles[ReactionRole] = "reaction"; roles[ReactionRole] = "reaction";
roles[ShowReactionsRole] = "showReactions"; roles[ShowReactionsRole] = "showReactions";
@@ -87,9 +88,14 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
// HACK: Reset the model to a null room first to make sure QML dismantles // HACK: Reset the model to a null room first to make sure QML dismantles
// last room's objects before the room is actually changed // last room's objects before the room is actually changed
beginResetModel(); beginResetModel();
m_readMarkerModels.clear();
m_currentRoom->disconnect(this); m_currentRoom->disconnect(this);
m_currentRoom = nullptr; m_currentRoom = nullptr;
endResetModel(); endResetModel();
// Don't clear the member objects until the model has been fully reset and all
// refs cleared.
m_memberObjects.clear();
} }
beginResetModel(); beginResetModel();
@@ -100,9 +106,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
room->setDisplayed(); room->setDisplayed();
for (auto event = m_currentRoom->messageEvents().begin(); event != m_currentRoom->messageEvents().end(); ++event) { for (auto event = m_currentRoom->messageEvents().begin(); event != m_currentRoom->messageEvents().end(); ++event) {
if (const auto &roomMessageEvent = &*event->viewAs<RoomMessageEvent>()) { createEventObjects(&*event->viewAs<RoomEvent>());
createEventObjects(roomMessageEvent);
}
if (event->event()->is<PollStartEvent>()) { if (event->event()->is<PollStartEvent>()) {
m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(event->event())); m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(event->event()));
} }
@@ -115,11 +119,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
connect(m_currentRoom, &Room::aboutToAddNewMessages, this, [this](RoomEventsRange events) { connect(m_currentRoom, &Room::aboutToAddNewMessages, this, [this](RoomEventsRange events) {
for (auto &&event : events) { for (auto &&event : events) {
const RoomMessageEvent *message = dynamic_cast<RoomMessageEvent *>(event.get()); createEventObjects(event.get());
if (message != nullptr) {
createEventObjects(message);
}
if (event->is<PollStartEvent>()) { if (event->is<PollStartEvent>()) {
m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(event.get())); m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(event.get()));
} }
@@ -129,9 +129,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
}); });
connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this, [this](RoomEventsRange events) { connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this, [this](RoomEventsRange events) {
for (auto &event : events) { for (auto &event : events) {
if (const auto &roomMessageEvent = dynamic_cast<RoomMessageEvent *>(event.get())) { createEventObjects(event.get());
createEventObjects(roomMessageEvent);
}
if (event->is<PollStartEvent>()) { if (event->is<PollStartEvent>()) {
m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(event.get())); m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(event.get()));
} }
@@ -158,8 +156,9 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
refreshLastUserEvents(i); refreshLastUserEvents(i);
} }
}); });
connect(m_currentRoom, &Room::pendingEventAboutToAdd, this, [this] { connect(m_currentRoom, &Room::pendingEventAboutToAdd, this, [this](Quotient::RoomEvent *event) {
m_initialized = true; m_initialized = true;
createEventObjects(event);
beginInsertRows({}, 0, 0); beginInsertRows({}, 0, 0);
}); });
connect(m_currentRoom, &Room::pendingEventAdded, this, &MessageEventModel::endInsertRows); connect(m_currentRoom, &Room::pendingEventAdded, this, &MessageEventModel::endInsertRows);
@@ -195,10 +194,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
moveReadMarker(toEventId); moveReadMarker(toEventId);
}); });
connect(m_currentRoom, &Room::replacedEvent, this, [this](const RoomEvent *newEvent) { connect(m_currentRoom, &Room::replacedEvent, this, [this](const RoomEvent *newEvent) {
const RoomMessageEvent *message = eventCast<const RoomMessageEvent>(newEvent); createEventObjects(newEvent);
if (message != nullptr) {
createEventObjects(message);
}
}); });
connect(m_currentRoom, &Room::updatedEvent, this, [this](const QString &eventId) { connect(m_currentRoom, &Room::updatedEvent, this, [this](const QString &eventId) {
if (eventId.isEmpty()) { // How did we get here? if (eventId.isEmpty()) { // How did we get here?
@@ -206,9 +202,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
} }
const auto eventIt = m_currentRoom->findInTimeline(eventId); const auto eventIt = m_currentRoom->findInTimeline(eventId);
if (eventIt != m_currentRoom->historyEdge()) { if (eventIt != m_currentRoom->historyEdge()) {
if (const auto &event = dynamic_cast<const RoomMessageEvent *>(&**eventIt)) { createEventObjects(eventIt->event());
createEventObjects(event);
}
if (eventIt->event()->is<PollStartEvent>()) { if (eventIt->event()->is<PollStartEvent>()) {
m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(eventIt->event())); m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(eventIt->event()));
} }
@@ -216,11 +210,10 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
refreshEventRoles(eventId, {Qt::DisplayRole}); refreshEventRoles(eventId, {Qt::DisplayRole});
}); });
connect(m_currentRoom, &Room::changed, this, [this](Room::Changes changes) { connect(m_currentRoom, &Room::changed, this, [this](Room::Changes changes) {
if (changes & (Room::Change::PartiallyReadStats | Room::Change::UnreadStats | Room::Change::Other | Room::Change::Members)) { if (changes.testFlag(Quotient::Room::Change::Other)) {
// this is slow // this is slow
for (auto it = m_currentRoom->messageEvents().rbegin(); it != m_currentRoom->messageEvents().rend(); ++it) { for (auto it = m_currentRoom->messageEvents().rbegin(); it != m_currentRoom->messageEvents().rend(); ++it) {
auto event = it->event(); createEventObjects(it->event());
refreshEventRoles(event->id(), {ReadMarkersRole, ReadMarkersStringRole, ExcessReadMarkersRole});
} }
} }
}); });
@@ -228,22 +221,6 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
beginResetModel(); beginResetModel();
endResetModel(); endResetModel();
}); });
connect(m_currentRoom, &Room::memberNameUpdated, this, [this](RoomMember member) {
for (auto it = m_currentRoom->messageEvents().rbegin(); it != m_currentRoom->messageEvents().rend(); ++it) {
auto event = it->event();
if (event->senderId() == member.id()) {
refreshEventRoles(event->id(), {AuthorRole});
}
}
});
connect(m_currentRoom, &Room::memberAvatarUpdated, this, [this](RoomMember member) {
for (auto it = m_currentRoom->messageEvents().rbegin(); it != m_currentRoom->messageEvents().rend(); ++it) {
auto event = it->event();
if (event->senderId() == member.id()) {
refreshEventRoles(event->id(), {AuthorRole});
}
}
});
qCDebug(MessageEvent) << "Connected to room" << room->id() << "as" << room->localMember().id(); qCDebug(MessageEvent) << "Connected to room" << room->id() << "as" << room->localMember().id();
} else { } else {
@@ -411,6 +388,8 @@ void MessageEventModel::fetchMore(const QModelIndex &parent)
} }
} }
static NeochatRoomMember *emptyNeochatRoomMember = new NeochatRoomMember;
QVariant MessageEventModel::data(const QModelIndex &idx, int role) const QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
{ {
if (!checkIndex(idx, QAbstractItemModel::CheckIndexOption::IndexIsValid)) { if (!checkIndex(idx, QAbstractItemModel::CheckIndexOption::IndexIsValid)) {
@@ -483,7 +462,18 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
} }
if (role == AuthorRole) { if (role == AuthorRole) {
return QVariant::fromValue(eventHandler.getAuthor(isPending)); QString mId;
if (isPending) {
mId = m_currentRoom->localMember().id();
} else {
mId = evt.senderId();
}
if (!m_memberObjects.contains(mId)) {
return QVariant::fromValue<NeochatRoomMember *>(emptyNeochatRoomMember);
}
return QVariant::fromValue<NeochatRoomMember *>(m_memberObjects.at(mId).get());
} }
if (role == HighlightRole) { if (role == HighlightRole) {
@@ -514,11 +504,11 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
if (role == ProgressInfoRole) { if (role == ProgressInfoRole) {
if (auto e = eventCast<const RoomMessageEvent>(&evt)) { if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
if (e->hasFileContent()) { if (e->hasFileContent()) {
return QVariant::fromValue(m_currentRoom->fileTransferInfo(e->id())); return QVariant::fromValue(m_currentRoom->cachedFileTransferInfo(&evt));
} }
} }
if (auto e = eventCast<const StickerEvent>(&evt)) { if (eventCast<const StickerEvent>(&evt)) {
return QVariant::fromValue(m_currentRoom->fileTransferInfo(e->id())); return QVariant::fromValue(m_currentRoom->cachedFileTransferInfo(&evt));
} }
} }
@@ -557,19 +547,15 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
} }
if (role == ReadMarkersRole) { if (role == ReadMarkersRole) {
return QVariant::fromValue(eventHandler.getReadMarkers()); if (m_readMarkerModels.contains(evt.id())) {
} return QVariant::fromValue<ReadMarkerModel *>(m_readMarkerModels[evt.id()].get());
} else {
if (role == ExcessReadMarkersRole) { return QVariantList();
return eventHandler.getNumberExcessReadMarkers(); }
}
if (role == ReadMarkersStringRole) {
return eventHandler.getReadMarkersString();
} }
if (role == ShowReadMarkersRole) { if (role == ShowReadMarkersRole) {
return eventHandler.hasReadMarkers(); return m_readMarkerModels.contains(evt.id());
} }
if (role == ReactionRole) { if (role == ReactionRole) {
@@ -630,30 +616,71 @@ int MessageEventModel::eventIdToRow(const QString &eventID) const
return it - m_currentRoom->messageEvents().rbegin() + timelineBaseIndex(); return it - m_currentRoom->messageEvents().rbegin() + timelineBaseIndex();
} }
void MessageEventModel::createEventObjects(const Quotient::RoomMessageEvent *event) void MessageEventModel::createEventObjects(const Quotient::RoomEvent *event)
{ {
auto eventId = event->id(); if (event == nullptr) {
return;
}
// ReactionModel handles updates to add and remove reactions, we only need to auto eventId = event->id();
auto senderId = event->senderId();
// A pending event might not have a sender ID set yet but in that case it must
// be the local member.
if (senderId.isEmpty()) {
senderId = m_currentRoom->localMember().id();
}
if (!m_memberObjects.contains(senderId)) {
m_memberObjects[senderId] = std::unique_ptr<NeochatRoomMember>(new NeochatRoomMember(m_currentRoom, senderId));
}
// ReadMarkerModel handles updates to add and remove markers, we only need to
// handle adding and removing whole models here. // handle adding and removing whole models here.
if (m_reactionModels.contains(eventId)) { if (m_readMarkerModels.contains(eventId)) {
// If a model already exists but now has no reactions remove it // If a model already exists but now has no reactions remove it
if (m_reactionModels[eventId]->rowCount() <= 0) { if (m_readMarkerModels[eventId]->rowCount() <= 0) {
m_reactionModels.remove(eventId); m_readMarkerModels.remove(eventId);
if (!resetting) { if (!resetting) {
refreshEventRoles(eventId, {ReactionRole, ShowReactionsRole}); refreshEventRoles(eventId, {ReadMarkersRole, ShowReadMarkersRole});
} }
} }
} else { } else {
if (m_currentRoom->relatedEvents(*event, Quotient::EventRelation::AnnotationType).count() > 0) { auto memberIds = m_currentRoom->userIdsAtEvent(eventId);
memberIds.remove(m_currentRoom->localMember().id());
if (memberIds.size() > 0) {
// If a model doesn't exist and there are reactions add it. // If a model doesn't exist and there are reactions add it.
auto reactionModel = QSharedPointer<ReactionModel>(new ReactionModel(event, m_currentRoom)); auto newModel = QSharedPointer<ReadMarkerModel>(new ReadMarkerModel(eventId, m_currentRoom));
if (reactionModel->rowCount() > 0) { if (newModel->rowCount() > 0) {
m_reactionModels[eventId] = reactionModel; m_readMarkerModels[eventId] = newModel;
if (!resetting) {
refreshEventRoles(eventId, {ReadMarkersRole, ShowReadMarkersRole});
}
}
}
}
if (const auto roomEvent = eventCast<const RoomMessageEvent>(event)) {
// ReactionModel handles updates to add and remove reactions, we only need to
// handle adding and removing whole models here.
if (m_reactionModels.contains(eventId)) {
// If a model already exists but now has no reactions remove it
if (m_reactionModels[eventId]->rowCount() <= 0) {
m_reactionModels.remove(eventId);
if (!resetting) { if (!resetting) {
refreshEventRoles(eventId, {ReactionRole, ShowReactionsRole}); refreshEventRoles(eventId, {ReactionRole, ShowReactionsRole});
} }
} }
} else {
if (m_currentRoom->relatedEvents(*event, Quotient::EventRelation::AnnotationType).count() > 0) {
// If a model doesn't exist and there are reactions add it.
auto reactionModel = QSharedPointer<ReactionModel>(new ReactionModel(roomEvent, m_currentRoom));
if (reactionModel->rowCount() > 0) {
m_reactionModels[eventId] = reactionModel;
if (!resetting) {
refreshEventRoles(eventId, {ReactionRole, ShowReactionsRole});
}
}
}
} }
} }
} }

View File

@@ -9,7 +9,9 @@
#include "linkpreviewer.h" #include "linkpreviewer.h"
#include "neochatroom.h" #include "neochatroom.h"
#include "neochatroommember.h"
#include "pollhandler.h" #include "pollhandler.h"
#include "readmarkermodel.h"
class ReactionModel; class ReactionModel;
@@ -58,8 +60,6 @@ public:
ShowSectionRole, /**< Whether the section header should be shown. */ ShowSectionRole, /**< Whether the section header should be shown. */
ReadMarkersRole, /**< The first 5 other users at the event for read marker tracking. */ ReadMarkersRole, /**< The first 5 other users at the event for read marker tracking. */
ExcessReadMarkersRole, /**< The number of other users at the event after the first 5. */
ReadMarkersStringRole, /**< String with the display name and mxID of the users at the event. */
ShowReadMarkersRole, /**< Whether there are any other user read markers to be shown. */ ShowReadMarkersRole, /**< Whether there are any other user read markers to be shown. */
ReactionRole, /**< List model for this event. */ ReactionRole, /**< List model for this event. */
ShowReactionsRole, /**< Whether there are any reactions to be shown. */ ShowReactionsRole, /**< Whether there are any reactions to be shown. */
@@ -116,6 +116,8 @@ private:
bool movingEvent = false; bool movingEvent = false;
KFormat m_format; KFormat m_format;
std::map<QString, std::unique_ptr<NeochatRoomMember>> m_memberObjects;
QMap<QString, QSharedPointer<ReadMarkerModel>> m_readMarkerModels;
QMap<QString, QSharedPointer<ReactionModel>> m_reactionModels; QMap<QString, QSharedPointer<ReactionModel>> m_reactionModels;
[[nodiscard]] int timelineBaseIndex() const; [[nodiscard]] int timelineBaseIndex() const;
@@ -130,7 +132,7 @@ private:
int refreshEventRoles(const QString &eventId, const QList<int> &roles = {}); int refreshEventRoles(const QString &eventId, const QList<int> &roles = {});
void moveReadMarker(const QString &toEventId); void moveReadMarker(const QString &toEventId);
void createEventObjects(const Quotient::RoomMessageEvent *event); void createEventObjects(const Quotient::RoomEvent *event);
// Hack to ensure that we don't call endInsertRows when we haven't called beginInsertRows // Hack to ensure that we don't call endInsertRows when we haven't called beginInsertRows
bool m_initialized = false; bool m_initialized = false;

View File

@@ -4,11 +4,13 @@
#include "messagefiltermodel.h" #include "messagefiltermodel.h"
#include <KLocalizedString> #include <KLocalizedString>
#include <QVariant>
#include "enums/delegatetype.h" #include "enums/delegatetype.h"
#include "messagecontentmodel.h" #include "messagecontentmodel.h"
#include "messageeventmodel.h" #include "messageeventmodel.h"
#include "neochatconfig.h" #include "neochatconfig.h"
#include "neochatroommember.h"
#include "timelinemodel.h" #include "timelinemodel.h"
using namespace Quotient; using namespace Quotient;

View File

@@ -99,7 +99,7 @@ void PushRuleModel::setRules(QList<Quotient::PushRule> rules, PushRuleKind::Kind
for (const auto &rule : rules) { for (const auto &rule : rules) {
QString roomId; QString roomId;
if (rule.conditions.size() > 0) { if (rule.conditions.size() > 0) {
for (const auto &condition : rule.conditions) { for (const auto &condition : std::as_const(rule.conditions)) {
if (condition.key == QStringLiteral("room_id")) { if (condition.key == QStringLiteral("room_id")) {
roomId = condition.pattern; roomId = condition.pattern;
} }
@@ -163,7 +163,7 @@ PushRuleSection::Section PushRuleModel::getSection(Quotient::PushRule rule)
} }
// If the rule has push conditions and one is a room ID it is a room only keyword. // If the rule has push conditions and one is a room ID it is a room only keyword.
if (!rule.conditions.isEmpty()) { if (!rule.conditions.isEmpty()) {
for (auto condition : rule.conditions) { for (const auto &condition : std::as_const(rule.conditions)) {
if (condition.key == QStringLiteral("room_id")) { if (condition.key == QStringLiteral("room_id")) {
return PushRuleSection::RoomKeywords; return PushRuleSection::RoomKeywords;
} }

View File

@@ -0,0 +1,136 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include "readmarkermodel.h"
#include <KLocalizedString>
#include <Quotient/roommember.h>
#define MAXMARKERS 5
ReadMarkerModel::ReadMarkerModel(const QString &eventId, NeoChatRoom *room)
: QAbstractListModel(nullptr)
, m_room(room)
, m_eventId(eventId)
{
Q_ASSERT(!m_eventId.isEmpty());
Q_ASSERT(m_room != nullptr);
connect(m_room, &NeoChatRoom::changed, this, [this](Quotient::Room::Changes changes) {
if (m_room != nullptr && changes.testFlag(Quotient::Room::Change::Other)) {
auto memberIds = m_room->userIdsAtEvent(m_eventId).values();
if (memberIds == m_markerIds) {
return;
}
beginResetModel();
m_markerIds.clear();
endResetModel();
beginResetModel();
memberIds.removeAll(m_room->localMember().id());
m_markerIds = memberIds;
endResetModel();
Q_EMIT reactionUpdated();
}
});
connect(m_room, &NeoChatRoom::memberNameUpdated, this, [this](Quotient::RoomMember member) {
if (m_markerIds.contains(member.id())) {
const auto memberIndex = index(m_markerIds.indexOf(member.id()));
Q_EMIT dataChanged(memberIndex, memberIndex);
}
});
connect(m_room, &NeoChatRoom::memberAvatarUpdated, this, [this](Quotient::RoomMember member) {
if (m_markerIds.contains(member.id())) {
const auto memberIndex = index(m_markerIds.indexOf(member.id()));
Q_EMIT dataChanged(memberIndex, memberIndex);
}
});
beginResetModel();
auto userIds = m_room->userIdsAtEvent(m_eventId);
userIds.remove(m_room->localMember().id());
m_markerIds = userIds.values();
endResetModel();
Q_EMIT reactionUpdated();
}
QVariant ReadMarkerModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return {};
}
if (index.row() >= rowCount()) {
qDebug() << "ReactionModel, something's wrong: index.row() >= rowCount()";
return {};
}
const auto member = m_room->member(m_markerIds.value(index.row()));
if (role == DisplayNameRole) {
return member.htmlSafeDisplayName();
}
if (role == AvatarUrlRole) {
return member.avatarUrl();
}
if (role == ColorRole) {
return member.color();
}
return {};
}
int ReadMarkerModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return std::min(int(m_markerIds.size()), MAXMARKERS);
}
QHash<int, QByteArray> ReadMarkerModel::roleNames() const
{
return {
{DisplayNameRole, "displayName"},
{AvatarUrlRole, "avatarUrl"},
{ColorRole, "memberColor"},
};
}
QString ReadMarkerModel::readMarkersString()
{
/**
* The string ends up in the form
* "x users: user1DisplayName, user2DisplayName, etc."
*/
QString readMarkersString = i18np("1 user: ", "%1 users: ", m_markerIds.size());
for (const auto &memberId : m_markerIds) {
auto member = m_room->member(memberId);
QString displayName = member.htmlSafeDisambiguatedName();
if (displayName.isEmpty()) {
displayName = i18nc("A member who is not in the room has been requested.", "unknown member");
}
readMarkersString += displayName + i18nc("list separator", ", ");
}
readMarkersString.chop(2);
return readMarkersString;
}
QString ReadMarkerModel::excessReadMarkersString()
{
if (m_room == nullptr) {
return {};
}
if (m_markerIds.size() > MAXMARKERS) {
return QStringLiteral("+ ") + QString::number(m_markerIds.size() - MAXMARKERS);
} else {
return QString();
}
}
#include "moc_readmarkermodel.cpp"

View File

@@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: 2024 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 <QAbstractListModel>
#include <qtmetamacros.h>
#include "neochatroom.h"
/**
* @class ReadMarkerModel
*
* This class defines the model for visualising a list of reactions to an event.
*/
class ReadMarkerModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
/**
* @brief Returns a string with the names of the read markers at the event.
*
* This is in the form "x users: name 1, name 2, ...".
*/
Q_PROPERTY(QString readMarkersString READ readMarkersString NOTIFY reactionUpdated)
/**
* @brief Returns the number of excess user read markers for the event.
*
* This returns a string in the form "+ x" ready for use in the UI.
*/
Q_PROPERTY(QString excessReadMarkersString READ excessReadMarkersString NOTIFY reactionUpdated)
public:
/**
* @brief Defines the model roles.
*/
enum Roles {
DisplayNameRole = Qt::DisplayRole, /**< The display name of the member in the room. */
AvatarUrlRole, /**< The avatar for the member in the room. */
ColorRole, /**< The color for the member. */
};
explicit ReadMarkerModel(const QString &eventId, NeoChatRoom *room);
QString readMarkersString();
QString excessReadMarkersString();
/**
* @brief Get the given role value at the given index.
*
* @sa QAbstractItemModel::data
*/
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
/**
* @brief Number of rows in the model.
*
* @sa QAbstractItemModel::rowCount
*/
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
/**
* @brief Returns a mapping from Role enum values to role names.
*
* @sa Roles, QAbstractItemModel::roleNames()
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Q_SIGNALS:
void reactionUpdated();
private:
QPointer<NeoChatRoom> m_room;
QString m_eventId;
QList<QString> m_markerIds;
};

View File

@@ -7,6 +7,7 @@
#include "eventhandler.h" #include "eventhandler.h"
#include "models/messagecontentmodel.h" #include "models/messagecontentmodel.h"
#include "neochatroom.h" #include "neochatroom.h"
#include "neochatroommember.h"
#include <QGuiApplication> #include <QGuiApplication>
@@ -66,7 +67,17 @@ void SearchModel::search()
m_job = job; m_job = job;
connect(job, &BaseJob::finished, this, [this, job] { connect(job, &BaseJob::finished, this, [this, job] {
beginResetModel(); beginResetModel();
m_memberObjects.clear();
m_result = job->searchCategories().roomEvents; m_result = job->searchCategories().roomEvents;
if (m_result.has_value()) {
for (const auto &result : m_result.value().results) {
if (!m_memberObjects.contains(result.result->senderId())) {
m_memberObjects[result.result->senderId()] = std::unique_ptr<NeochatRoomMember>(new NeochatRoomMember(m_room, result.result->senderId()));
}
}
}
endResetModel(); endResetModel();
setSearching(false); setSearching(false);
m_job = nullptr; m_job = nullptr;
@@ -83,7 +94,7 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const
switch (role) { switch (role) {
case AuthorRole: case AuthorRole:
return QVariant::fromValue(eventHandler.getAuthor()); return QVariant::fromValue<NeochatRoomMember *>(m_memberObjects.at(event.senderId()).get());
case ShowSectionRole: case ShowSectionRole:
if (row == 0) { if (row == 0) {
return true; return true;

View File

@@ -9,6 +9,8 @@
#include <Quotient/csapi/search.h> #include <Quotient/csapi/search.h>
#include "neochatroommember.h"
namespace Quotient namespace Quotient
{ {
class Connection; class Connection;
@@ -123,4 +125,6 @@ private:
std::optional<Quotient::SearchJob::ResultRoomEvents> m_result = std::nullopt; std::optional<Quotient::SearchJob::ResultRoomEvents> m_result = std::nullopt;
Quotient::SearchJob *m_job = nullptr; Quotient::SearchJob *m_job = nullptr;
bool m_searching = false; bool m_searching = false;
std::map<QString, std::unique_ptr<NeochatRoomMember>> m_memberObjects;
}; };

View File

@@ -33,6 +33,7 @@ void UserListModel::setRoom(NeoChatRoom *room)
m_currentRoom->disconnect(this); m_currentRoom->disconnect(this);
m_currentRoom->connection()->disconnect(this); m_currentRoom->connection()->disconnect(this);
m_currentRoom = nullptr; m_currentRoom = nullptr;
m_members.clear();
endResetModel(); endResetModel();
} }
@@ -56,7 +57,7 @@ void UserListModel::setRoom(NeoChatRoom *room)
}); });
} }
refreshAllMembers(); m_active = false;
Q_EMIT roomChanged(); Q_EMIT roomChanged();
} }
@@ -169,7 +170,6 @@ void UserListModel::refreshMember(const Quotient::RoomMember &member, const QLis
void UserListModel::refreshAllMembers() void UserListModel::refreshAllMembers()
{ {
beginResetModel(); beginResetModel();
m_members.clear();
if (m_currentRoom != nullptr) { if (m_currentRoom != nullptr) {
m_members = m_currentRoom->joinedMemberIds(); m_members = m_currentRoom->joinedMemberIds();
@@ -179,8 +179,17 @@ void UserListModel::refreshAllMembers()
MemberSorter sorter(m_currentRoom); MemberSorter sorter(m_currentRoom);
#endif #endif
std::sort(m_members.begin(), m_members.end(), [&sorter, this](const auto &left, const auto &right) { std::sort(m_members.begin(), m_members.end(), [&sorter, this](const auto &left, const auto &right) {
const auto leftPl = m_currentRoom->getUserPowerLevel(left);
const auto rightPl = m_currentRoom->getUserPowerLevel(right);
if (leftPl > rightPl) {
return true;
} else if (rightPl > leftPl) {
return false;
}
return sorter(m_currentRoom->member(left), m_currentRoom->member(right)); return sorter(m_currentRoom->member(left), m_currentRoom->member(right));
}); });
} }
endResetModel(); endResetModel();
Q_EMIT usersRefreshed(); Q_EMIT usersRefreshed();
@@ -216,4 +225,14 @@ QHash<int, QByteArray> UserListModel::roleNames() const
return roles; return roles;
} }
void UserListModel::activate()
{
if (m_active) {
return;
}
m_active = true;
refreshAllMembers();
}
#include "moc_userlistmodel.cpp" #include "moc_userlistmodel.cpp"

View File

@@ -77,6 +77,8 @@ public:
*/ */
[[nodiscard]] QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
void activate();
Q_SIGNALS: Q_SIGNALS:
void roomChanged(); void roomChanged();
void usersRefreshed(); void usersRefreshed();
@@ -94,6 +96,8 @@ private:
QPointer<NeoChatRoom> m_currentRoom; QPointer<NeoChatRoom> m_currentRoom;
QList<QString> m_members; QList<QString> m_members;
bool m_active = false;
int findUserPos(const Quotient::RoomMember &member) const; int findUserPos(const Quotient::RoomMember &member) const;
[[nodiscard]] int findUserPos(const QString &username) const; [[nodiscard]] int findUserPos(const QString &username) const;
}; };

View File

@@ -16,6 +16,7 @@ Name[eu]=NeoChat
Name[fi]=NeoChat Name[fi]=NeoChat
Name[fr]=NeoChat Name[fr]=NeoChat
Name[gl]=NeoChat Name[gl]=NeoChat
Name[he]=NeoChat
Name[hu]=NeoChat Name[hu]=NeoChat
Name[ia]=Neochat Name[ia]=Neochat
Name[id]=NeoChat Name[id]=NeoChat
@@ -58,6 +59,7 @@ Comment[eu]=Matrix, deszentralizatutako komunikazio protokolorako, bezero bat
Comment[fi]=Hajautetun Matrix-viestintäyhteyskäytännön asiakasohjelma Comment[fi]=Hajautetun Matrix-viestintäyhteyskäytännön asiakasohjelma
Comment[fr]=Un client pour « Matrix », le protocole décentralisé de communications. Comment[fr]=Un client pour « Matrix », le protocole décentralisé de communications.
Comment[gl]=Un cliente para Matrix, o protocolo de comunicación descentralizada. Comment[gl]=Un cliente para Matrix, o protocolo de comunicación descentralizada.
Comment[he]=לקוח ל־matrix, פרוטוקול התקשורת המבוזר
Comment[hu]=Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz Comment[hu]=Kliens a matrixhoz, a decentralizált kommunikációs protokollhoz
Comment[ia]=Un cliente per Matrix, le protocollo de communication decentralisate Comment[ia]=Un cliente per Matrix, le protocollo de communication decentralisate
Comment[id]=Sebuah klien untuk matrix, protokol komunikasi terdecentralisasi Comment[id]=Sebuah klien untuk matrix, protokol komunikasi terdecentralisasi
@@ -102,6 +104,7 @@ Name[eu]=Mezu berria
Name[fi]=Uusi viesti Name[fi]=Uusi viesti
Name[fr]=Nouveau message Name[fr]=Nouveau message
Name[gl]=Nova mensaxe Name[gl]=Nova mensaxe
Name[he]=הודעה חדשה
Name[hu]=Új üzenet Name[hu]=Új üzenet
Name[ia]=Nove message Name[ia]=Nove message
Name[id]=Pesan baru Name[id]=Pesan baru
@@ -142,6 +145,7 @@ Comment[eu]=Mezu berri bat dago
Comment[fi]=Saapui uusi viesti Comment[fi]=Saapui uusi viesti
Comment[fr]=Il y a un nouveau message Comment[fr]=Il y a un nouveau message
Comment[gl]=Hai unha nova mensaxe. Comment[gl]=Hai unha nova mensaxe.
Comment[he]=יש הודעה חדשה
Comment[hu]=Új üzenet érkezett Comment[hu]=Új üzenet érkezett
Comment[ia]=Il ha un nove message Comment[ia]=Il ha un nove message
Comment[id]=Ada pesan baru Comment[id]=Ada pesan baru
@@ -186,6 +190,7 @@ Name[eu]=Gonbidapen berria
Name[fi]=Uusi kutsu Name[fi]=Uusi kutsu
Name[fr]=Nouvelle invitation Name[fr]=Nouvelle invitation
Name[gl]=Novo convite Name[gl]=Novo convite
Name[he]=הזמנה חדשה
Name[hu]=Új meghívó Name[hu]=Új meghívó
Name[ia]=Nove invitation Name[ia]=Nove invitation
Name[id]=Undangan Baru Name[id]=Undangan Baru
@@ -225,6 +230,7 @@ Comment[eu]=Gela baterako gonbidapen berri bat dago
Comment[fi]=Uusi kutsu huoneeseen Comment[fi]=Uusi kutsu huoneeseen
Comment[fr]=Il y a une nouvelle invitation dans un salon. Comment[fr]=Il y a une nouvelle invitation dans un salon.
Comment[gl]=Tes un novo convite para unha sala. Comment[gl]=Tes un novo convite para unha sala.
Comment[he]=יש הזמנה חדשה לחדר
Comment[hu]=Új meghívó érkezett egy szobába Comment[hu]=Új meghívó érkezett egy szobába
Comment[ia]=Il ha un nove invitation a un sala Comment[ia]=Il ha un nove invitation a un sala
Comment[id]=Ada undangan baru ke sebuah ruangan Comment[id]=Ada undangan baru ke sebuah ruangan
@@ -255,7 +261,7 @@ Action=Popup
Name=Share Name=Share
Name[ar]=شارك Name[ar]=شارك
Name[ca]=Compartició Name[ca]=Compartició
Name[ca@valencia]=Compartició Name[ca@valencia]=Compartiu
Name[cs]=Sdílet Name[cs]=Sdílet
Name[en_GB]=Share Name[en_GB]=Share
Name[eo]=Kundividi Name[eo]=Kundividi
@@ -263,6 +269,8 @@ Name[es]=Compartir
Name[eu]=Partekatu Name[eu]=Partekatu
Name[fi]=Jaa Name[fi]=Jaa
Name[fr]=Partager Name[fr]=Partager
Name[gl]=Compartir
Name[he]=שיתוף
Name[hu]=Megosztás Name[hu]=Megosztás
Name[ia]=Comparti Name[ia]=Comparti
Name[it]=Condivisione Name[it]=Condivisione
@@ -271,6 +279,7 @@ Name[lv]=Kopīgot
Name[nl]=Gedeelde Name[nl]=Gedeelde
Name[nn]=Del Name[nn]=Del
Name[pl]=Udostępnij Name[pl]=Udostępnij
Name[pt_BR]=Compartilhar
Name[sl]=Deli Name[sl]=Deli
Name[sv]=Dela Name[sv]=Dela
Name[ta]=பகிர் Name[ta]=பகிர்
@@ -288,6 +297,8 @@ Comment[es]=El resultado de compartir una parte de contenido
Comment[eu]=Eduki pieza bat partekatzearen emaitza Comment[eu]=Eduki pieza bat partekatzearen emaitza
Comment[fi]=Tulos yhden sisältöosasen jakamisesta Comment[fi]=Tulos yhden sisältöosasen jakamisesta
Comment[fr]=Le résultat du partage d'une partie de contenu. Comment[fr]=Le résultat du partage d'une partie de contenu.
Comment[gl]=O resultado de compartir un fragmento de contido.
Comment[he]=תוצאת שיתוף פיסת תוכן
Comment[hu]=Tartalom megosztásának eredménye Comment[hu]=Tartalom megosztásának eredménye
Comment[ia]=Le exito de compartir un pecietta de contento Comment[ia]=Le exito de compartir un pecietta de contento
Comment[it]=Il risultato della condivisione di un contenuto Comment[it]=Il risultato della condivisione di un contenuto
@@ -296,6 +307,7 @@ Comment[lv]=Satura kopīgošanas rezultāts
Comment[nl]=Het resultaat van het delen van een stukje inhoud Comment[nl]=Het resultaat van het delen van een stukje inhoud
Comment[nn]=Resultatet av deling av innhald Comment[nn]=Resultatet av deling av innhald
Comment[pl]=Wynik udostępniania kawałka treści Comment[pl]=Wynik udostępniania kawałka treści
Comment[pt_BR]=O resultado de compartilhar um conteúdo
Comment[sl]=Rezultat deljenega kosa vsebine Comment[sl]=Rezultat deljenega kosa vsebine
Comment[sv]=Resultatet av att dela innehåll Comment[sv]=Resultatet av att dela innehåll
Comment[ta]=எதையோ பகிர்ந்த‍தன் விளைவு Comment[ta]=எதையோ பகிர்ந்த‍தன் விளைவு

View File

@@ -187,5 +187,11 @@
<default>false</default> <default>false</default>
</entry> </entry>
</group> </group>
<group name="Security">
<entry name="RejectUnknownInvites" type="bool">
<label>Reject unknown invites</label>
<default>false</default>
</entry>
</group>
</kcfg> </kcfg>

View File

@@ -25,6 +25,7 @@
#include <Quotient/csapi/content-repo.h> #include <Quotient/csapi/content-repo.h>
#include <Quotient/csapi/profile.h> #include <Quotient/csapi/profile.h>
#include <Quotient/csapi/versions.h>
#include <Quotient/database.h> #include <Quotient/database.h>
#include <Quotient/jobs/downloadfilejob.h> #include <Quotient/jobs/downloadfilejob.h>
#include <Quotient/qt_connection_util.h> #include <Quotient/qt_connection_util.h>
@@ -132,6 +133,21 @@ void NeoChatConnection::connectSignals()
Q_EMIT homeNotificationsChanged(); Q_EMIT homeNotificationsChanged();
Q_EMIT homeHaveHighlightNotificationsChanged(); Q_EMIT homeHaveHighlightNotificationsChanged();
}); });
// Fetch unstable features
// TODO: Expose unstableFeatures() in libQuotient
connect(
this,
&Connection::connected,
this,
[this] {
auto job = callApi<GetVersionsJob>(BackgroundRequest);
connect(job, &GetVersionsJob::success, this, [this, job] {
m_canCheckMutualRooms = job->unstableFeatures().contains("uk.half-shot.msc2666.query_mutual_rooms"_ls);
Q_EMIT canCheckMutualRoomsChanged();
});
},
Qt::SingleShotConnection);
} }
int NeoChatConnection::badgeNotificationCount() const int NeoChatConnection::badgeNotificationCount() const
@@ -200,6 +216,11 @@ QVariantList NeoChatConnection::getSupportedRoomVersions() const
return supportedRoomVersions; return supportedRoomVersions;
} }
bool NeoChatConnection::canCheckMutualRooms() const
{
return m_canCheckMutualRooms;
}
void NeoChatConnection::changePassword(const QString &currentPassword, const QString &newPassword) void NeoChatConnection::changePassword(const QString &currentPassword, const QString &newPassword)
{ {
auto job = callApi<NeochatChangePasswordJob>(newPassword, false); auto job = callApi<NeochatChangePasswordJob>(newPassword, false);

View File

@@ -79,6 +79,11 @@ class NeoChatConnection : public Quotient::Connection
*/ */
Q_PROPERTY(bool isOnline READ isOnline WRITE setIsOnline NOTIFY isOnlineChanged) Q_PROPERTY(bool isOnline READ isOnline WRITE setIsOnline NOTIFY isOnlineChanged)
/**
* @brief Whether the server supports querying a user's mutual rooms.
*/
Q_PROPERTY(bool canCheckMutualRooms READ canCheckMutualRooms NOTIFY canCheckMutualRoomsChanged)
public: public:
/** /**
* @brief Defines the status after an attempt to change the password on an account. * @brief Defines the status after an attempt to change the password on an account.
@@ -95,6 +100,7 @@ public:
Q_INVOKABLE void logout(bool serverSideLogout); Q_INVOKABLE void logout(bool serverSideLogout);
Q_INVOKABLE QVariantList getSupportedRoomVersions() const; Q_INVOKABLE QVariantList getSupportedRoomVersions() const;
bool canCheckMutualRooms() const;
/** /**
* @brief Change the password for an account. * @brief Change the password for an account.
@@ -196,6 +202,7 @@ Q_SIGNALS:
void passwordStatus(NeoChatConnection::PasswordStatus status); void passwordStatus(NeoChatConnection::PasswordStatus status);
void userConsentRequired(QUrl url); void userConsentRequired(QUrl url);
void badgeNotificationCountChanged(NeoChatConnection *connection, int count); void badgeNotificationCountChanged(NeoChatConnection *connection, int count);
void canCheckMutualRoomsChanged();
private: private:
bool m_isOnline = true; bool m_isOnline = true;
@@ -208,4 +215,6 @@ private:
int m_badgeNotificationCount = 0; int m_badgeNotificationCount = 0;
QHash<QUrl, LinkPreviewer *> m_linkPreviewers; QHash<QUrl, LinkPreviewer *> m_linkPreviewers;
bool m_canCheckMutualRooms = false;
}; };

View File

@@ -41,6 +41,7 @@
#include "events/joinrulesevent.h" #include "events/joinrulesevent.h"
#include "events/pollevent.h" #include "events/pollevent.h"
#include "filetransferpseudojob.h" #include "filetransferpseudojob.h"
#include "jobs/neochatgetcommonroomsjob.h"
#include "neochatconfig.h" #include "neochatconfig.h"
#include "notificationsmanager.h" #include "notificationsmanager.h"
#include "roomlastmessageprovider.h" #include "roomlastmessageprovider.h"
@@ -69,6 +70,26 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
setFileUploadingProgress(0); setFileUploadingProgress(0);
setHasFileUploading(false); setHasFileUploading(false);
}); });
connect(this, &Room::fileTransferCompleted, this, [this](QString eventId) {
const auto evtIt = findInTimeline(eventId);
if (evtIt != messageEvents().rend()) {
const auto m_event = evtIt->viewAs<RoomEvent>();
QString mxcUrl;
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) {
if (event->hasFileContent()) {
mxcUrl = event->content()->fileInfo()->url().toString();
}
} else if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) {
mxcUrl = event->image().fileInfo()->url().toString();
}
if (mxcUrl.isEmpty()) {
return;
}
auto localPath = this->fileTransferInfo(eventId).localPath.toLocalFile();
auto config = KSharedConfig::openStateConfig(QStringLiteral("neochatdownloads"))->group(QStringLiteral("downloads"));
config.writePathEntry(mxcUrl.mid(6), localPath);
}
});
connect(this, &Room::addedMessages, this, &NeoChatRoom::readMarkerLoadedChanged); connect(this, &Room::addedMessages, this, &NeoChatRoom::readMarkerLoadedChanged);
connect(this, &Room::aboutToAddHistoricalMessages, this, &NeoChatRoom::cleanupExtraEventRange); connect(this, &Room::aboutToAddHistoricalMessages, this, &NeoChatRoom::cleanupExtraEventRange);
@@ -109,14 +130,38 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
return; return;
} }
auto roomMemberEvent = currentState().get<RoomMemberEvent>(localMember().id()); auto roomMemberEvent = currentState().get<RoomMemberEvent>(localMember().id());
QImage avatar_image;
if (roomMemberEvent && !member(roomMemberEvent->senderId()).avatarUrl().isEmpty()) { auto showNotification = [this, roomMemberEvent] {
avatar_image = memberAvatar(roomMemberEvent->senderId()).get(this->connection(), 128, [] {}); QImage avatar_image;
if (roomMemberEvent && !member(roomMemberEvent->senderId()).avatarUrl().isEmpty()) {
avatar_image = memberAvatar(roomMemberEvent->senderId()).get(this->connection(), 128, [] {});
} else {
qWarning() << "using this room's avatar";
avatar_image = avatar(128);
}
NotificationsManager::instance().postInviteNotification(this,
displayName(),
member(roomMemberEvent->senderId()).htmlSafeDisplayName(),
avatar_image);
};
if (NeoChatConfig::rejectUnknownInvites()) {
auto job = this->connection()->callApi<NeochatGetCommonRoomsJob>(roomMemberEvent->senderId());
connect(job, &BaseJob::result, this, [this, job, roomMemberEvent, showNotification] {
QJsonObject replyData = job->jsonData();
if (replyData.contains(QStringLiteral("joined"))) {
const bool inAnyOfOurRooms = !replyData[QStringLiteral("joined")].toArray().isEmpty();
if (inAnyOfOurRooms) {
showNotification();
} else {
leaveRoom();
}
}
});
} else { } else {
qWarning() << "using this room's avatar"; showNotification();
avatar_image = avatar(128);
} }
NotificationsManager::instance().postInviteNotification(this, displayName(), member(roomMemberEvent->senderId()).htmlSafeDisplayName(), avatar_image);
}, },
Qt::SingleShotConnection); Qt::SingleShotConnection);
connect(this, &Room::changed, this, [this] { connect(this, &Room::changed, this, [this] {
@@ -846,11 +891,18 @@ void NeoChatRoom::setUserPowerLevel(const QString &userID, const int &powerLevel
int NeoChatRoom::getUserPowerLevel(const QString &userId) const int NeoChatRoom::getUserPowerLevel(const QString &userId) const
{ {
auto powerLevelEvent = currentState().get<RoomPowerLevelsEvent>(); if (!successorId().isEmpty()) {
if (!powerLevelEvent) { return 0; // No one can upgrade a room that's already upgraded
return 0;
} }
return powerLevelEvent->powerLevelForUser(userId);
const auto &mId = userId.isEmpty() ? connection()->userId() : userId;
if (const auto *plEvent = currentState().get<RoomPowerLevelsEvent>()) {
return plEvent->powerLevelForUser(mId);
}
if (const auto *createEvent = creation()) {
return createEvent->senderId() == mId ? 100 : 0;
}
return 0; // That's rather weird but may happen, according to rvdh
} }
QCoro::Task<void> NeoChatRoom::doDeleteMessagesByUser(const QString &user, QString reason) QCoro::Task<void> NeoChatRoom::doDeleteMessagesByUser(const QString &user, QString reason)
@@ -1286,7 +1338,6 @@ void NeoChatRoom::setPushNotificationState(PushNotificationState::State state)
m_currentPushNotificationState = state; m_currentPushNotificationState = state;
Q_EMIT pushNotificationStateChanged(m_currentPushNotificationState); Q_EMIT pushNotificationStateChanged(m_currentPushNotificationState);
} }
void NeoChatRoom::updatePushNotificationState(QString type) void NeoChatRoom::updatePushNotificationState(QString type)
@@ -1370,7 +1421,7 @@ void NeoChatRoom::openEventMediaExternally(const QString &eventId)
if (evtIt != messageEvents().rend() && is<RoomMessageEvent>(**evtIt)) { if (evtIt != messageEvents().rend() && is<RoomMessageEvent>(**evtIt)) {
const auto event = evtIt->viewAs<RoomMessageEvent>(); const auto event = evtIt->viewAs<RoomMessageEvent>();
if (event->hasFileContent()) { if (event->hasFileContent()) {
const auto transferInfo = fileTransferInfo(eventId); const auto transferInfo = cachedFileTransferInfo(event);
if (transferInfo.completed()) { if (transferInfo.completed()) {
UrlHelper helper; UrlHelper helper;
helper.openUrl(transferInfo.localPath); helper.openUrl(transferInfo.localPath);
@@ -1378,15 +1429,20 @@ void NeoChatRoom::openEventMediaExternally(const QString &eventId)
downloadFile(eventId, downloadFile(eventId,
QUrl(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + u'/' QUrl(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + u'/'
+ event->id().replace(u':', u'_').replace(u'/', u'_').replace(u'+', u'_') + fileNameToDownload(eventId))); + 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) { connect(
Q_UNUSED(localFile); this,
Q_UNUSED(fileMetadata); &Room::fileTransferCompleted,
if (id == eventId) { this,
auto transferInfo = fileTransferInfo(eventId); [this, eventId](QString id, QUrl localFile, FileSourceInfo fileMetadata) {
UrlHelper helper; Q_UNUSED(localFile);
helper.openUrl(transferInfo.localPath); Q_UNUSED(fileMetadata);
} if (id == eventId) {
}); auto transferInfo = fileTransferInfo(eventId);
UrlHelper helper;
helper.openUrl(transferInfo.localPath);
}
},
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
} }
} }
} }
@@ -1406,20 +1462,66 @@ void NeoChatRoom::copyEventMedia(const QString &eventId)
downloadFile(eventId, downloadFile(eventId,
QUrl(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + u'/' QUrl(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + u'/'
+ event->id().replace(u':', u'_').replace(u'/', u'_').replace(u'+', u'_') + fileNameToDownload(eventId))); + 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) { connect(
Q_UNUSED(localFile); this,
Q_UNUSED(fileMetadata); &Room::fileTransferCompleted,
if (id == eventId) { this,
auto transferInfo = fileTransferInfo(eventId); [this, eventId](QString id, QUrl localFile, FileSourceInfo fileMetadata) {
Clipboard clipboard; Q_UNUSED(localFile);
clipboard.setImage(transferInfo.localPath); Q_UNUSED(fileMetadata);
} if (id == eventId) {
}); auto transferInfo = fileTransferInfo(eventId);
Clipboard clipboard;
clipboard.setImage(transferInfo.localPath);
}
},
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
} }
} }
} }
} }
FileTransferInfo NeoChatRoom::cachedFileTransferInfo(const Quotient::RoomEvent *event) const
{
QString mxcUrl;
int total = 0;
if (auto evt = eventCast<const Quotient::RoomMessageEvent>(event)) {
if (evt->hasFileContent()) {
mxcUrl = evt->content()->fileInfo()->url().toString();
total = evt->content()->fileInfo()->payloadSize;
}
} else if (auto evt = eventCast<const Quotient::StickerEvent>(event)) {
mxcUrl = evt->image().fileInfo()->url().toString();
total = evt->image().fileInfo()->payloadSize;
}
FileTransferInfo transferInfo = fileTransferInfo(event->id());
if (transferInfo.active()) {
return transferInfo;
}
auto config = KSharedConfig::openStateConfig(QStringLiteral("neochatdownloads"))->group(QStringLiteral("downloads"));
if (!config.hasKey(mxcUrl.mid(6))) {
return transferInfo;
}
const auto path = config.readPathEntry(mxcUrl.mid(6), QString());
QFileInfo info(path);
if (!info.isFile()) {
config.deleteEntry(mxcUrl);
return transferInfo;
}
// TODO: we could check the hash here
return FileTransferInfo{
.status = FileTransferInfo::Completed,
.isUpload = false,
.progress = total,
.total = total,
.localDir = QUrl(info.dir().path()),
.localPath = QUrl::fromLocalFile(path),
};
}
ChatBarCache *NeoChatRoom::mainCache() const ChatBarCache *NeoChatRoom::mainCache() const
{ {
return m_mainCache; return m_mainCache;
@@ -1665,6 +1767,11 @@ const RoomEvent *NeoChatRoom::getEvent(const QString &eventId) const
return timelineIt->get(); return timelineIt->get();
} }
const auto pendingIt = findPendingEvent(eventId);
if (pendingIt != pendingEvents().end()) {
return pendingIt->event();
}
auto extraIt = std::find_if(m_extraEvents.begin(), m_extraEvents.end(), [eventId](const Quotient::event_ptr_tt<Quotient::RoomEvent> &event) { auto extraIt = std::find_if(m_extraEvents.begin(), m_extraEvents.end(), [eventId](const Quotient::event_ptr_tt<Quotient::RoomEvent> &event) {
return event->id() == eventId; return event->id() == eventId;
}); });

View File

@@ -579,6 +579,14 @@ public:
*/ */
Q_INVOKABLE QString invitingUserId() const; Q_INVOKABLE QString invitingUserId() const;
/**
* @brief Return the cached file transfer information for the event.
*
* If we downloaded the file previously, return a struct with Completed status
* and the local file path stored in KSharedCOnfig
*/
Quotient::FileTransferInfo cachedFileTransferInfo(const Quotient::RoomEvent *event) const;
private: private:
QSet<const Quotient::RoomEvent *> highlights; QSet<const Quotient::RoomEvent *> highlights;

166
src/neochatroommember.cpp Normal file
View File

@@ -0,0 +1,166 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include "neochatroommember.h"
#include "neochatroom.h"
NeochatRoomMember::NeochatRoomMember(NeoChatRoom *room, const QString &memberId)
: m_room(room)
, m_memberId(memberId)
{
Q_ASSERT(!m_memberId.isEmpty());
if (m_room != nullptr) {
connect(m_room, &NeoChatRoom::memberNameUpdated, this, [this](Quotient::RoomMember member) {
if (member.id() == m_memberId) {
Q_EMIT displayNameUpdated();
}
});
connect(m_room, &NeoChatRoom::memberAvatarUpdated, this, [this](Quotient::RoomMember member) {
if (member.id() == m_memberId) {
Q_EMIT avatarUpdated();
}
});
}
}
QString NeochatRoomMember::id() const
{
return m_memberId;
}
Quotient::Uri NeochatRoomMember::uri() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return {};
}
return m_room->member(m_memberId).uri();
}
bool NeochatRoomMember::isLocalMember() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return false;
}
return m_room->member(m_memberId).isLocalMember();
}
Quotient::Membership NeochatRoomMember::membershipState() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return Quotient::Membership::Leave;
}
return m_room->member(m_memberId).membershipState();
}
QString NeochatRoomMember::name() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return id();
}
return m_room->member(m_memberId).name();
}
QString NeochatRoomMember::displayName() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return id();
}
return m_room->member(m_memberId).displayName();
}
QString NeochatRoomMember::htmlSafeDisplayName() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return id();
}
return m_room->member(m_memberId).htmlSafeDisplayName();
}
QString NeochatRoomMember::fullName() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return id();
}
return m_room->member(m_memberId).fullName();
}
QString NeochatRoomMember::htmlSafeFullName() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return id();
}
return m_room->member(m_memberId).htmlSafeFullName();
}
QString NeochatRoomMember::disambiguatedName() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return id();
}
return m_room->member(m_memberId).disambiguatedName();
}
QString NeochatRoomMember::htmlSafeDisambiguatedName() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return id();
}
return m_room->member(m_memberId).htmlSafeDisambiguatedName();
}
int NeochatRoomMember::hue() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return 0;
}
return m_room->member(m_memberId).hue();
}
qreal NeochatRoomMember::hueF() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return 0.0;
}
return m_room->member(m_memberId).hueF();
}
QColor NeochatRoomMember::color() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return {};
}
return m_room->member(m_memberId).color();
}
QString NeochatRoomMember::avatarMediaId() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return {};
}
return m_room->member(m_memberId).avatarMediaId();
}
QUrl NeochatRoomMember::avatarUrl() const
{
if (m_room == nullptr || m_memberId.isEmpty()) {
return {};
}
return m_room->member(m_memberId).avatarUrl();
}

83
src/neochatroommember.h Normal file
View File

@@ -0,0 +1,83 @@
// SPDX-FileCopyrightText: 2024 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 <QPointer>
#include <qqmlintegration.h>
#include <Quotient/roommember.h>
#include <Quotient/uri.h>
class NeoChatRoom;
/**
* @class NeochatRoomMember
*
* This class is a shim around RoomMember that can be safety passed to QML.
*
* Because RoomMember has an internal pointer to a RoomMemberEvent it is
* designed to be created used then quickly discarded as the stste event is changed
* every time the member updates. Passing these to QML which will hold onto them
* can lead to accessing an already deleted Quotient::RoomMemberEvent relatively easily.
*
* This class instead holds a member ID and can therefore always safely create and
* access Quotient::RoomMember objects while being used as long as needed by QML.
*
* @note This is only needed to pass to QML if only accessing in CPP RoomMmeber can
* be used safely.
*
* @note The interface is the same as Quotient::RoomMember.
*
* @sa Quotient::RoomMember
*/
class NeochatRoomMember : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_PROPERTY(QString id READ id CONSTANT)
Q_PROPERTY(Quotient::Uri uri READ uri CONSTANT)
Q_PROPERTY(bool isLocalMember READ isLocalMember CONSTANT)
Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameUpdated)
Q_PROPERTY(QString htmlSafeDisplayName READ htmlSafeDisplayName NOTIFY displayNameUpdated)
Q_PROPERTY(QString fullName READ fullName NOTIFY displayNameUpdated)
Q_PROPERTY(QString htmlSafeFullName READ htmlSafeFullName NOTIFY displayNameUpdated)
Q_PROPERTY(QString disambiguatedName READ disambiguatedName NOTIFY displayNameUpdated)
Q_PROPERTY(QString htmlSafeDisambiguatedName READ htmlSafeDisambiguatedName NOTIFY displayNameUpdated)
Q_PROPERTY(int hue READ hue CONSTANT)
Q_PROPERTY(qreal hueF READ hueF CONSTANT)
Q_PROPERTY(QColor color READ color CONSTANT)
Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY avatarUpdated)
public:
NeochatRoomMember() = default;
explicit NeochatRoomMember(NeoChatRoom *room, const QString &memberId);
QString id() const;
Quotient::Uri uri() const;
bool isLocalMember() const;
Quotient::Membership membershipState() const;
QString name() const;
QString displayName() const;
QString htmlSafeDisplayName() const;
QString fullName() const;
QString htmlSafeFullName() const;
QString disambiguatedName() const;
QString htmlSafeDisambiguatedName() const;
int hue() const;
qreal hueF() const;
QColor color() const;
QString avatarMediaId() const;
QUrl avatarUrl() const;
Q_SIGNALS:
void displayNameUpdated();
void avatarUpdated();
private:
QPointer<NeoChatRoom> m_room;
const QString m_memberId = QString();
};

View File

@@ -110,6 +110,12 @@ void NotificationsManager::processNotificationJob(QPointer<NeoChatConnection> co
} }
auto sender = room->member(notification["event"_ls]["sender"_ls].toString()); auto sender = room->member(notification["event"_ls]["sender"_ls].toString());
// Don't display notifications for events in invited rooms
// This should prevent empty notifications from appearing when they shouldn't
if (room->joinState() == JoinState::Invite) {
continue;
}
QString body; QString body;
if (notification["event"_ls]["type"_ls].toString() == "org.matrix.msc3381.poll.start"_ls) { if (notification["event"_ls]["type"_ls].toString() == "org.matrix.msc3381.poll.start"_ls) {
body = notification["event"_ls]["content"_ls]["org.matrix.msc3381.poll.start"_ls]["question"_ls]["body"_ls].toString(); body = notification["event"_ls]["content"_ls]["org.matrix.msc3381.poll.start"_ls]["question"_ls]["body"_ls].toString();
@@ -243,7 +249,6 @@ void NotificationsManager::postInviteNotification(NeoChatRoom *rawRoom, const QS
notification->setText(i18n("%1 invited you to a room", sender)); notification->setText(i18n("%1 invited you to a room", sender));
notification->setTitle(title); notification->setTitle(title);
notification->setPixmap(createNotificationImage(icon, nullptr)); notification->setPixmap(createNotificationImage(icon, nullptr));
notification->setFlags(KNotification::Persistent);
auto defaultAction = notification->addDefaultAction(i18n("Open this invitation in NeoChat")); auto defaultAction = notification->addDefaultAction(i18n("Open this invitation in NeoChat"));
connect(defaultAction, &KNotificationAction::activated, this, [notification, room]() { connect(defaultAction, &KNotificationAction::activated, this, [notification, room]() {
if (!room) { if (!room) {

View File

@@ -17,6 +17,7 @@ Name[eu]=NeoChat
Name[fi]=NeoChat Name[fi]=NeoChat
Name[fr]=NeoChat Name[fr]=NeoChat
Name[gl]=NeoChat Name[gl]=NeoChat
Name[he]=NeoChat
Name[hu]=NeoChat Name[hu]=NeoChat
Name[ia]=Neochat Name[ia]=Neochat
Name[id]=NeoChat Name[id]=NeoChat
@@ -57,6 +58,7 @@ Comment[eu]=Bilatu gelak NeoChat-en
Comment[fi]=Etsi huoneita NeoChatissä Comment[fi]=Etsi huoneita NeoChatissä
Comment[fr]=Trouver des salons dans NeoChat Comment[fr]=Trouver des salons dans NeoChat
Comment[gl]=Atopa salas en NeoChat. Comment[gl]=Atopa salas en NeoChat.
Comment[he]=איתור חדרים ב־NeoChat
Comment[hu]=Szobák keresése a NeoChatben Comment[hu]=Szobák keresése a NeoChatben
Comment[ia]=Trova salas in NeoChat Comment[ia]=Trova salas in NeoChat
Comment[id]=Cari ruangan di NeoChat Comment[id]=Cari ruangan di NeoChat

View File

@@ -28,6 +28,7 @@
"Description[nl]": "Delen via NeoChat", "Description[nl]": "Delen via NeoChat",
"Description[nn]": "Del via NeoChat", "Description[nn]": "Del via NeoChat",
"Description[pl]": "Udostępnij przez NeoChat", "Description[pl]": "Udostępnij przez NeoChat",
"Description[pt_BR]": "Compartilhar via NeoChat",
"Description[ru]": "Опубликовать в NeoChat", "Description[ru]": "Опубликовать в NeoChat",
"Description[sl]": "Deli prek NeoChat", "Description[sl]": "Deli prek NeoChat",
"Description[sv]": "Dela via NeoChat", "Description[sv]": "Dela via NeoChat",

View File

@@ -17,7 +17,7 @@ Components.AbstractMaximizeComponent {
/** /**
* @brief The message author. * @brief The message author.
*/ */
property RoomMember author property NeochatRoomMember author
/** /**
* @brief The timestamp of the message. * @brief The timestamp of the message.

View File

@@ -15,7 +15,10 @@ Kirigami.PlaceholderMessage {
required property NeoChatRoom currentRoom required property NeoChatRoom currentRoom
text: i18n("Accept this invitation?") text: i18n("Accept this invitation?")
explanation: root.currentRoom.connection.canCheckMutualRooms ? i18n("You can reject invitations from unknown users under Security settings.") : ""
RowLayout { RowLayout {
Layout.alignment: Qt.AlignHCenter
QQC2.Button { QQC2.Button {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: i18nc("@action:button The thing being rejected is an invitation to chat", "Reject and ignore user") text: i18nc("@action:button The thing being rejected is an invitation to chat", "Reject and ignore user")

View File

@@ -192,20 +192,7 @@ QQC2.ScrollView {
} }
} }
KSortFilterProxyModel { model: root.room.isDirectChat() ? 0 : RoomManager.userListModel
id: sortedMessageEventModel
sourceModel: UserListModel {
room: root.room
}
sortRoleName: "powerLevel"
sortOrder: Qt.DescendingOrder
filterRoleName: "name"
filterCaseSensitivity: Qt.CaseInsensitive
}
model: root.room.isDirectChat() ? 0 : sortedMessageEventModel
clip: true clip: true
focus: true focus: true

View File

@@ -108,6 +108,7 @@ QQC2.ScrollView {
onTriggered: { onTriggered: {
root.roomChanging = false; root.roomChanging = false;
markReadIfVisibleTimer.reset(); markReadIfVisibleTimer.reset();
RoomManager.activateUserModel();
} }
} }
onAtYEndChanged: if (!root.roomChanging) { onAtYEndChanged: if (!root.roomChanging) {
@@ -190,7 +191,7 @@ QQC2.ScrollView {
implicitHeight: Kirigami.Units.gridUnit * 2 implicitHeight: Kirigami.Units.gridUnit * 2
z: 2 z: 2
visible: root.currentRoom && root.currentRoom.hasUnreadMessages visible: (root.currentRoom?.hasUnreadMessages ?? false)
text: root.currentRoom.readMarkerLoaded ? i18n("Jump to first unread message") : i18n("Jump to oldest loaded message") text: root.currentRoom.readMarkerLoaded ? i18n("Jump to first unread message") : i18n("Jump to oldest loaded message")
action: Kirigami.Action { action: Kirigami.Action {

View File

@@ -11,6 +11,7 @@
#include "neochatconfig.h" #include "neochatconfig.h"
#include "neochatconnection.h" #include "neochatconnection.h"
#include "neochatroom.h" #include "neochatroom.h"
#include "neochatroommember.h"
#include "spacehierarchycache.h" #include "spacehierarchycache.h"
#include "urlhelper.h" #include "urlhelper.h"
@@ -39,6 +40,7 @@ RoomManager::RoomManager(QObject *parent)
, m_timelineModel(new TimelineModel(this)) , m_timelineModel(new TimelineModel(this))
, m_messageFilterModel(new MessageFilterModel(this, m_timelineModel)) , m_messageFilterModel(new MessageFilterModel(this, m_timelineModel))
, m_mediaMessageFilterModel(new MediaMessageFilterModel(this, m_messageFilterModel)) , m_mediaMessageFilterModel(new MediaMessageFilterModel(this, m_messageFilterModel))
, m_userListModel(new UserListModel(this))
{ {
m_lastRoomConfig = m_config->group(QStringLiteral("LastOpenRoom")); m_lastRoomConfig = m_config->group(QStringLiteral("LastOpenRoom"));
m_lastSpaceConfig = m_config->group(QStringLiteral("LastOpenSpace")); m_lastSpaceConfig = m_config->group(QStringLiteral("LastOpenSpace"));
@@ -46,6 +48,7 @@ RoomManager::RoomManager(QObject *parent)
connect(this, &RoomManager::currentRoomChanged, this, [this]() { connect(this, &RoomManager::currentRoomChanged, this, [this]() {
m_timelineModel->setRoom(m_currentRoom); m_timelineModel->setRoom(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) {
@@ -113,6 +116,16 @@ MediaMessageFilterModel *RoomManager::mediaMessageFilterModel() const
return m_mediaMessageFilterModel; return m_mediaMessageFilterModel;
} }
UserListModel *RoomManager::userListModel() const
{
return m_userListModel;
}
void RoomManager::activateUserModel()
{
m_userListModel->activate();
}
UriResolveResult RoomManager::resolveResource(const Uri &uri) UriResolveResult RoomManager::resolveResource(const Uri &uri)
{ {
return UriResolverBase::visitResource(m_connection, uri); return UriResolverBase::visitResource(m_connection, uri);
@@ -172,7 +185,7 @@ void RoomManager::maximizeMedia(int index)
Q_EMIT showMaximizedMedia(index); Q_EMIT showMaximizedMedia(index);
} }
void RoomManager::maximizeCode(const RoomMember &author, const QDateTime &time, const QString &codeText, const QString &language) void RoomManager::maximizeCode(NeochatRoomMember *author, const QDateTime &time, const QString &codeText, const QString &language)
{ {
if (codeText.isEmpty()) { if (codeText.isEmpty()) {
return; return;
@@ -190,14 +203,14 @@ void RoomManager::viewEventSource(const QString &eventId)
Q_EMIT showEventSource(eventId); Q_EMIT showEventSource(eventId);
} }
void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, const QString &selectedText) void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText)
{ {
const auto &event = **room->findInTimeline(eventId); const auto &event = **room->findInTimeline(eventId);
const auto eventHandler = EventHandler(room, &event); const auto eventHandler = EventHandler(room, &event);
if (eventHandler.getMediaInfo().contains("mimeType"_ls)) { if (eventHandler.getMediaInfo().contains("mimeType"_ls)) {
Q_EMIT showFileMenu(eventId, Q_EMIT showFileMenu(eventId,
eventHandler.getAuthor(), sender,
eventHandler.messageComponentType(), eventHandler.messageComponentType(),
eventHandler.getPlainBody(), eventHandler.getPlainBody(),
eventHandler.getMediaInfo()["mimeType"_ls].toString(), eventHandler.getMediaInfo()["mimeType"_ls].toString(),
@@ -205,12 +218,7 @@ void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, const
return; return;
} }
Q_EMIT showMessageMenu(eventId, Q_EMIT showMessageMenu(eventId, sender, eventHandler.messageComponentType(), eventHandler.getPlainBody(), eventHandler.getRichBody(), selectedText);
eventHandler.getAuthor(),
eventHandler.messageComponentType(),
eventHandler.getPlainBody(),
eventHandler.getRichBody(),
selectedText);
} }
bool RoomManager::hasOpenRoom() const bool RoomManager::hasOpenRoom() const

View File

@@ -22,6 +22,8 @@
#include "models/sortfilterroomtreemodel.h" #include "models/sortfilterroomtreemodel.h"
#include "models/sortfilterspacelistmodel.h" #include "models/sortfilterspacelistmodel.h"
#include "models/timelinemodel.h" #include "models/timelinemodel.h"
#include "models/userlistmodel.h"
#include "neochatroommember.h"
class NeoChatRoom; class NeoChatRoom;
class NeoChatConnection; class NeoChatConnection;
@@ -120,6 +122,14 @@ class RoomManager : public QObject, public UriResolverBase
*/ */
Q_PROPERTY(MediaMessageFilterModel *mediaMessageFilterModel READ mediaMessageFilterModel CONSTANT) Q_PROPERTY(MediaMessageFilterModel *mediaMessageFilterModel READ mediaMessageFilterModel CONSTANT)
/**
* @brief The UserListModel that should be used for room member visualisation.
*
* @note Available here so that the room page and drawer both have access to the
* same model.
*/
Q_PROPERTY(UserListModel *userListModel READ userListModel CONSTANT)
/** /**
* @brief Whether a room is currently open in NeoChat. * @brief Whether a room is currently open in NeoChat.
* *
@@ -155,6 +165,9 @@ public:
MessageFilterModel *messageFilterModel() const; MessageFilterModel *messageFilterModel() const;
MediaMessageFilterModel *mediaMessageFilterModel() const; MediaMessageFilterModel *mediaMessageFilterModel() const;
UserListModel *userListModel() const;
Q_INVOKABLE void activateUserModel();
/** /**
* @brief Resolve the given URI resource. * @brief Resolve the given URI resource.
* *
@@ -204,7 +217,7 @@ public:
*/ */
Q_INVOKABLE void maximizeMedia(int index); Q_INVOKABLE void maximizeMedia(int index);
Q_INVOKABLE void maximizeCode(const RoomMember &author, const QDateTime &time, const QString &codeText, const QString &language); Q_INVOKABLE void maximizeCode(NeochatRoomMember *author, const QDateTime &time, const QString &codeText, const QString &language);
/** /**
* @brief Request that any full screen overlay currently open closes. * @brief Request that any full screen overlay currently open closes.
@@ -219,7 +232,7 @@ public:
/** /**
* @brief Show a context menu for the given event. * @brief Show a context menu for the given event.
*/ */
Q_INVOKABLE void viewEventMenu(const QString &eventId, NeoChatRoom *room, const QString &selectedText = {}); Q_INVOKABLE void viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText = {});
ChatDocumentHandler *chatDocumentHandler() const; ChatDocumentHandler *chatDocumentHandler() const;
void setChatDocumentHandler(ChatDocumentHandler *handler); void setChatDocumentHandler(ChatDocumentHandler *handler);
@@ -275,7 +288,7 @@ Q_SIGNALS:
/** /**
* @brief Request a block of code is shown maximized. * @brief Request a block of code is shown maximized.
*/ */
void showMaximizedCode(const RoomMember &author, const QDateTime &time, const QString &codeText, const QString &language); void showMaximizedCode(NeochatRoomMember *author, const QDateTime &time, const QString &codeText, const QString &language);
/** /**
* @brief Request that any full screen overlay closes. * @brief Request that any full screen overlay closes.
@@ -291,7 +304,7 @@ Q_SIGNALS:
* @brief Request to show a menu for the given event. * @brief Request to show a menu for the given event.
*/ */
void showMessageMenu(const QString &eventId, void showMessageMenu(const QString &eventId,
const Quotient::RoomMember &author, const NeochatRoomMember *author,
MessageComponentType::Type messageComponentType, MessageComponentType::Type messageComponentType,
const QString &plainText, const QString &plainText,
const QString &htmlText, const QString &htmlText,
@@ -301,7 +314,7 @@ Q_SIGNALS:
* @brief Request to show a menu for the given media event. * @brief Request to show a menu for the given media event.
*/ */
void showFileMenu(const QString &eventId, void showFileMenu(const QString &eventId,
const Quotient::RoomMember &author, const NeochatRoomMember *author,
MessageComponentType::Type messageComponentType, MessageComponentType::Type messageComponentType,
const QString &plainText, const QString &plainText,
const QString &mimeType, const QString &mimeType,
@@ -359,6 +372,9 @@ private:
TimelineModel *m_timelineModel; TimelineModel *m_timelineModel;
MessageFilterModel *m_messageFilterModel; MessageFilterModel *m_messageFilterModel;
MediaMessageFilterModel *m_mediaMessageFilterModel; MediaMessageFilterModel *m_mediaMessageFilterModel;
UserListModel *m_userListModel;
QPointer<NeoChatConnection> m_connection; QPointer<NeoChatConnection> m_connection;
void setCurrentRoom(const QString &roomId); void setCurrentRoom(const QString &roomId);

View File

@@ -41,7 +41,7 @@ FormCard.FormCard {
width: stickerFlow.width / 4 width: stickerFlow.width / 4
height: width height: width
onClicked: pageStack.pushDialogLayer(emoticonEditorPage, { onClicked: root.QQC2.ApplicationWindow.window.pageStack.pushDialogLayer(emoticonEditorPage, {
description: model.body ?? "", description: model.body ?? "",
index: model.index, index: model.index,
url: model.url, url: model.url,
@@ -90,7 +90,7 @@ FormCard.FormCard {
width: stickerFlow.width / 4 width: stickerFlow.width / 4
height: width height: width
onClicked: pageStack.pushDialogLayer(emoticonEditorPage, { onClicked: root.QQC2.ApplicationWindow.window.pageStack.pushDialogLayer(emoticonEditorPage, {
description: "", description: "",
index: -1, index: -1,
url: "", url: "",

View File

@@ -50,7 +50,7 @@ FormCard.FormCardPage {
QQC2.ToolButton { QQC2.ToolButton {
text: i18nc("@action:button", "Unignore this user") text: i18nc("@action:button", "Unignore this user")
icon.name: "list-remove-symbolic" icon.name: "list-remove-symbolic"
onClicked: root.connection.removeFromIgnoredUsers(root.connection.user(modelData)) onClicked: root.connection.removeFromIgnoredUsers(modelData)
display: QQC2.Button.IconOnly display: QQC2.Button.IconOnly
QQC2.ToolTip.text: text QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered QQC2.ToolTip.visible: hovered

View File

@@ -16,6 +16,32 @@ FormCard.FormCardPage {
title: i18nc("@title", "Security") title: i18nc("@title", "Security")
FormCard.FormHeader {
title: i18nc("@title:group", "Invitations")
}
FormCard.FormCard {
FormCard.FormCheckDelegate {
text: i18nc("@option:check", "Reject invitations from unknown users")
description: connection.canCheckMutualRooms ? i18n("If enabled, NeoChat will reject invitations from from users you don't share a room with.") : i18n("Your server does not support this setting.")
checked: Config.rejectUnknownInvites
enabled: !Config.isRejectUnknownInvitesImmutable && connection.canCheckMutualRooms
onToggled: {
Config.rejectUnknownInvites = checked;
Config.save();
}
}
}
FormCard.FormHeader {
title: i18nc("@title:group", "Ignored Users")
}
FormCard.FormCard {
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "Manage ignored users")
onClicked: root.ApplicationWindow.window.pageStack.push(ignoredUsersDialogComponent, {}, {
title: i18nc("@title:window", "Ignored Users")
});
}
}
FormCard.FormHeader { FormCard.FormHeader {
title: i18nc("@title", "Keys") title: i18nc("@title", "Keys")
} }
@@ -33,17 +59,6 @@ FormCard.FormCardPage {
description: i18n("Device id") description: i18n("Device id")
} }
} }
FormCard.FormHeader {
title: i18nc("@title:group", "Ignored Users")
}
FormCard.FormCard {
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "Manage ignored users")
onClicked: pageStack.pushDialogLayer(ignoredUsersDialogComponent, {}, {
title: i18nc("@title:window", "Ignored Users")
});
}
}
Component { Component {
id: ignoredUsersDialogComponent id: ignoredUsersDialogComponent

View File

@@ -20,11 +20,6 @@ FormCard.FormCardPage {
title: i18nc('@title:window', 'Permissions') title: i18nc('@title:window', 'Permissions')
property UserListModel userListModel: UserListModel {
id: userListModel
room: root.room
}
readonly property PowerLevelModel powerLevelModel: PowerLevelModel { readonly property PowerLevelModel powerLevelModel: PowerLevelModel {
showMute: false showMute: false
} }
@@ -39,7 +34,7 @@ FormCard.FormCardPage {
FormCard.FormCard { FormCard.FormCard {
Repeater { Repeater {
model: KSortFilterProxyModel { model: KSortFilterProxyModel {
sourceModel: userListModel sourceModel: RoomManager.userListModel
sortRoleName: "powerLevel" sortRoleName: "powerLevel"
sortOrder: Qt.DescendingOrder sortOrder: Qt.DescendingOrder
filterRowCallback: function (source_row, source_parent) { filterRowCallback: function (source_row, source_parent) {
@@ -158,7 +153,7 @@ FormCard.FormCardPage {
model: UserFilterModel { model: UserFilterModel {
id: userListFilterModel id: userListFilterModel
sourceModel: userListModel sourceModel: RoomManager.userListModel
filterText: userListSearchField.text filterText: userListSearchField.text
onFilterTextChanged: { onFilterTextChanged: {

View File

@@ -28,11 +28,6 @@ ColumnLayout {
*/ */
required property string eventId required property string eventId
/**
* @brief The display text of the message.
*/
required property string display
/** /**
* @brief The media info for the event. * @brief The media info for the event.
* *
@@ -44,6 +39,7 @@ ColumnLayout {
* - width - The width in pixels of the audio media. * - width - The width in pixels of the audio media.
* - height - The height in pixels of the audio media. * - height - The height in pixels of the audio media.
* - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads. * - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads.
* - filename - original filename of the media
*/ */
required property var mediaInfo required property var mediaInfo
@@ -138,7 +134,7 @@ ColumnLayout {
id: playButton id: playButton
} }
QQC2.Label { QQC2.Label {
text: root.display text: root.mediaInfo.filename
wrapMode: Text.Wrap wrapMode: Text.Wrap
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -159,7 +155,7 @@ ColumnLayout {
from: 0 from: 0
to: audio.duration to: audio.duration
value: audio.position value: audio.position
onMoved: audio.seek(value) onMoved: audio.setPosition(value)
} }
QQC2.Label { QQC2.Label {

View File

@@ -60,7 +60,7 @@ RowLayout {
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
color: Kirigami.Theme.disabledTextColor color: Kirigami.Theme.disabledTextColor
QQC2.ToolTip.visible: timeHoverHandler.hovered QQC2.ToolTip.visible: timeHoverHandler.hovered
QQC2.ToolTip.text: root.time.toLocaleString(Qt.locale(), Locale.LongFormat) QQC2.ToolTip.text: root.time.toLocaleString(Qt.locale(), Locale.ShortFormat)
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
HoverHandler { HoverHandler {

View File

@@ -13,20 +13,21 @@ Flow {
property var avatarSize: Kirigami.Units.iconSizes.small property var avatarSize: Kirigami.Units.iconSizes.small
property alias model: avatarFlowRepeater.model property alias model: avatarFlowRepeater.model
property string toolTipText property string toolTipText
property alias excessAvatars: excessAvatarsLabel.text
spacing: -avatarSize / 2 spacing: -avatarSize / 2
Repeater { Repeater {
id: avatarFlowRepeater id: avatarFlowRepeater
delegate: KirigamiComponents.Avatar { delegate: KirigamiComponents.Avatar {
required property var modelData required property string displayName
required property url avatarUrl
required property color memberColor
implicitWidth: root.avatarSize implicitWidth: root.avatarSize
implicitHeight: root.avatarSize implicitHeight: root.avatarSize
name: modelData.displayName name: displayName
source: modelData.avatarUrl source: avatarUrl
color: modelData.color color: memberColor
} }
} }
QQC2.Label { QQC2.Label {
@@ -34,6 +35,9 @@ Flow {
visible: text !== "" visible: text !== ""
color: Kirigami.Theme.textColor color: Kirigami.Theme.textColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: root.model?.excessReadMarkersString ?? ""
background: Kirigami.ShadowedRectangle { background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor color: Kirigami.Theme.backgroundColor
Kirigami.Theme.inherit: false Kirigami.Theme.inherit: false
@@ -54,7 +58,7 @@ Flow {
} }
} }
QQC2.ToolTip.text: toolTipText QQC2.ToolTip.text: root.model?.readMarkersString ?? ""
QQC2.ToolTip.visible: hoverHandler.hovered QQC2.ToolTip.visible: hoverHandler.hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay

View File

@@ -20,7 +20,7 @@ QQC2.Control {
* *
* @sa Quotient::RoomMember * @sa Quotient::RoomMember
*/ */
required property RoomMember author required property NeochatRoomMember author
/** /**
* @brief The timestamp of the message. * @brief The timestamp of the message.

View File

@@ -29,11 +29,6 @@ ColumnLayout {
*/ */
required property string eventId required property string eventId
/**
* @brief The display text of the message.
*/
required property string display
/** /**
* @brief The media info for the event. * @brief The media info for the event.
* *
@@ -45,6 +40,7 @@ ColumnLayout {
* - width - The width in pixels of the audio media. * - width - The width in pixels of the audio media.
* - height - The height in pixels of the audio media. * - height - The height in pixels of the audio media.
* - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads. * - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads.
* - filename - original filename of the media
*/ */
required property var mediaInfo required property var mediaInfo
@@ -155,7 +151,7 @@ ColumnLayout {
spacing: 0 spacing: 0
QQC2.Label { QQC2.Label {
Layout.fillWidth: true Layout.fillWidth: true
text: root.display text: root.mediaInfo.filename
wrapMode: Text.Wrap wrapMode: Text.Wrap
elide: Text.ElideRight elide: Text.ElideRight
} }

View File

@@ -26,7 +26,7 @@ TimelineDelegate {
/** /**
* @brief The message author. * @brief The message author.
*/ */
required property RoomMember author required property NeochatRoomMember author
width: parent?.width width: parent?.width
rightPadding: Config.compactLayout && root.ListView.view.width >= Kirigami.Units.gridUnit * 20 ? Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing : Kirigami.Units.largeSpacing rightPadding: Config.compactLayout && root.ListView.view.width >= Kirigami.Units.gridUnit * 20 ? Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing : Kirigami.Units.largeSpacing
@@ -88,7 +88,7 @@ TimelineDelegate {
QtObject { QtObject {
id: _private id: _private
function showMessageMenu() { function showMessageMenu() {
RoomManager.viewEventMenu(root.eventId, root.room, ""); RoomManager.viewEventMenu(root.eventId, root.room, root.author, "");
} }
} }
} }

View File

@@ -50,7 +50,7 @@ TimelineDelegate {
* *
* @sa Quotient::RoomMember * @sa Quotient::RoomMember
*/ */
required property var author required property NeochatRoomMember author
/** /**
* @brief The model to visualise the content of the message. * @brief The model to visualise the content of the message.
@@ -82,16 +82,6 @@ TimelineDelegate {
*/ */
required property var readMarkers required property var readMarkers
/**
* @brief String with the display name and matrix ID of the other user read markers.
*/
required property string readMarkersString
/**
* @brief The number of other users at the event after the first 5.
*/
required property var excessReadMarkers
/** /**
* @brief Whether the other user read marker component should be shown. * @brief Whether the other user read marker component should be shown.
*/ */
@@ -245,7 +235,7 @@ TimelineDelegate {
topMargin: Kirigami.Units.smallSpacing topMargin: Kirigami.Units.smallSpacing
} }
visible: root.contentModel?.showAuthor && Config.showAvatarInTimeline && (Config.compactLayout || !_private.showUserMessageOnRight) visible: (root.contentModel?.showAuthor ?? false) && Config.showAvatarInTimeline && (Config.compactLayout || !_private.showUserMessageOnRight)
name: root.author.displayName name: root.author.displayName
source: root.author.avatarUrl source: root.author.avatarUrl
color: root.author.color color: root.author.color
@@ -342,8 +332,6 @@ TimelineDelegate {
Layout.rightMargin: Kirigami.Units.largeSpacing Layout.rightMargin: Kirigami.Units.largeSpacing
visible: root.showReadMarkers visible: root.showReadMarkers
model: root.readMarkers model: root.readMarkers
toolTipText: root.readMarkersString
excessAvatars: root.excessReadMarkers
} }
DelegateSizeHelper { DelegateSizeHelper {
@@ -377,7 +365,7 @@ TimelineDelegate {
property bool showUserMessageOnRight: Config.showLocalMessagesOnRight && root.author.isLocalMember && !Config.compactLayout && !root.alwaysFillWidth property bool showUserMessageOnRight: Config.showLocalMessagesOnRight && root.author.isLocalMember && !Config.compactLayout && !root.alwaysFillWidth
function showMessageMenu() { function showMessageMenu() {
RoomManager.viewEventMenu(root.eventId, root.room, root.selectedText); RoomManager.viewEventMenu(root.eventId, root.room, root.author, root.selectedText);
} }
} }
} }

View File

@@ -5,6 +5,7 @@ import QtQuick
import QtQuick.Controls as QQC2 import QtQuick.Controls as QQC2
import QtQuick.Layouts import QtQuick.Layouts
import org.kde.coreaddons
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
/** /**
@@ -13,13 +14,14 @@ import org.kde.kirigami as Kirigami
RowLayout { RowLayout {
property alias mimeIconSource: icon.source property alias mimeIconSource: icon.source
property alias label: nameLabel.text property alias label: nameLabel.text
property alias subLabel: subLabel.text property string subLabel: ""
property int size: 0
property int duration: 0
spacing: Kirigami.Units.largeSpacing spacing: Kirigami.Units.largeSpacing
Kirigami.Icon { Kirigami.Icon {
id: icon id: icon
fallback: "unknown" fallback: "unknown"
} }
ColumnLayout { ColumnLayout {
@@ -32,15 +34,21 @@ RowLayout {
id: nameLabel id: nameLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: subLabel.visible ? Qt.AlignLeft | Qt.AlignBottom : Qt.AlignLeft | Qt.AlignVCenter Layout.alignment: caption.visible ? Qt.AlignLeft | Qt.AlignBottom : Qt.AlignLeft | Qt.AlignVCenter
elide: Text.ElideRight elide: Text.ElideRight
} }
QQC2.Label { QQC2.Label {
id: subLabel id: caption
Layout.fillWidth: true Layout.fillWidth: true
text: (subLabel || size || duration || '') && [
subLabel,
size && Format.formatByteSize(size),
duration > 0 && Format.formatDuration(duration),
].filter(Boolean).join(" | ")
elide: Text.ElideRight elide: Text.ElideRight
visible: text.length > 0 visible: text.length > 0
opacity: 0.7 opacity: 0.7

View File

@@ -52,7 +52,7 @@ ColumnLayout {
delegate: RowLayout { delegate: RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
CheckBox { CheckBox {
checked: root.pollHandler.answers[root.room.localember.id] ? root.pollHandler.answers[root.room.localMember.id].includes(modelData["id"]) : false checked: root.pollHandler.answers[root.room.localMember.id] ? root.pollHandler.answers[root.room.localMember.id].includes(modelData["id"]) : false
onClicked: root.pollHandler.sendPollAnswer(root.eventId, modelData["id"]) onClicked: root.pollHandler.sendPollAnswer(root.eventId, modelData["id"])
enabled: !root.pollHandler.hasEnded enabled: !root.pollHandler.hasEnded
} }

View File

@@ -27,6 +27,9 @@ TimelineDelegate {
padding: Kirigami.Units.largeSpacing padding: Kirigami.Units.largeSpacing
topInset: Kirigami.Units.largeSpacing topInset: Kirigami.Units.largeSpacing
topPadding: Kirigami.Units.largeSpacing * 2 topPadding: Kirigami.Units.largeSpacing * 2
bottomPadding: Kirigami.Units.largeSpacing * 2
leftPadding: Kirigami.Units.largeSpacing * 2
bottomInset: Kirigami.Units.largeSpacing
Timer { Timer {
id: temporaryHighlightTimer id: temporaryHighlightTimer

View File

@@ -69,13 +69,12 @@ DelegateChooser {
DelegateChoice { DelegateChoice {
roleValue: MessageComponentType.Video roleValue: MessageComponentType.Video
delegate: MimeComponent { delegate: MimeComponent {
required property string display
required property var mediaInfo required property var mediaInfo
required property int componentType
mimeIconSource: mediaInfo.mimeIcon mimeIconSource: mediaInfo.mimeIcon
label: display size: mediaInfo.size
subLabel: componentType === MessageComponentType.File ? Format.formatByteSize(mediaInfo.size) : Format.formatDuration(mediaInfo.duration) duration: mediaInfo.duration
label: mediaInfo.filename
} }
} }
@@ -112,11 +111,11 @@ DelegateChooser {
delegate: MimeComponent { delegate: MimeComponent {
required property string display required property string display
required property var mediaInfo required property var mediaInfo
required property int componentType
mimeIconSource: mediaInfo.mimeIcon mimeIconSource: mediaInfo.mimeIcon
label: display size: mediaInfo.size
subLabel: componentType === MessageComponentType.File ? Format.formatByteSize(mediaInfo.size) : Format.formatDuration(mediaInfo.duration) duration: mediaInfo.duration
label: mediaInfo.filename
} }
} }
@@ -125,11 +124,10 @@ DelegateChooser {
delegate: MimeComponent { delegate: MimeComponent {
required property string display required property string display
required property var mediaInfo required property var mediaInfo
required property int componentType
mimeIconSource: mediaInfo.mimeIcon mimeIconSource: mediaInfo.mimeIcon
label: display size: mediaInfo.size
subLabel: componentType === MessageComponentType.File ? Format.formatByteSize(mediaInfo.size) : Format.formatDuration(mediaInfo.duration) label: mediaInfo.filename
} }
} }
@@ -143,16 +141,17 @@ DelegateChooser {
DelegateChoice { DelegateChoice {
roleValue: MessageComponentType.Location roleValue: MessageComponentType.Location
delegate: LocationComponent { delegate: MimeComponent {
maxContentWidth: root.maxContentWidth mimeIconSource: "mark-location"
label: display
} }
} }
DelegateChoice { DelegateChoice {
roleValue: MessageComponentType.LiveLocation roleValue: MessageComponentType.LiveLocation
delegate: LiveLocationComponent { delegate: MimeComponent {
room: root.room mimeIconSource: "mark-location"
maxContentWidth: root.maxContentWidth label: display
} }
} }

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