Compare commits

...

53 Commits

Author SHA1 Message Date
Tobias Fella
68a917e385 Comletely redo emoticon handling 2024-11-22 14:52:12 +01:00
l10n daemon script
39046632aa GIT_SILENT Sync po/docbooks with svn 2024-11-19 01:30:50 +00:00
Carl Schwan
fbb2afdb49 Remove layout attached properties
They don't do anything
2024-11-18 12:32:00 +00:00
James Graham
aff0402f71 Make sure the loading text for a new login wraps
Title

BUG: 493869
2024-11-18 08:42:19 +00:00
James Graham
cee9058c77 Fix Sed Edits
Make sure that for multiple sed edits we grab the eventID of the original message not the replacement

BUG: 496313
2024-11-18 08:41:52 +00:00
l10n daemon script
3f922b4c90 GIT_SILENT Sync po/docbooks with svn 2024-11-18 01:34:10 +00:00
l10n daemon script
02d2d31cf3 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-11-18 01:25:11 +00:00
Thiago Sueto
240cf6a0ed Make height of chatbar, userinfo bar and side tab bar the same
|Current state|With this MR|
|-|-|
|![Screenshot_20241115_171736](/uploads/858a8ca21a6f4024a20f6ba32225aece/Screenshot_20241115_171736.png)|![Screenshot_20241115_171650](/uploads/115f99c7bb2b93a542c42647f9cc25c7/Screenshot_20241115_171650.png)|
2024-11-17 18:47:45 +00:00
Tobias Fella
dcd9ee93de Escape display name in WelcomePage 2024-11-17 19:26:04 +01:00
Joshua Goins
2a8cd74ab1 Fix undefined access when loading stickers in chat
We need a check here, because stickers (and really, any images without a
tempSource) will try to access an undefined object.

This fixes the error:
"qrc:/qt/qml/org/kde/neochat/timeline/ImageComponent.qml:106: TypeError: Cannot read property 'source' of undefined"
2024-11-16 21:30:59 +00:00
Joshua Goins
63bc7055c2 Default to a more sensible sticker size
If we do not set the width/height for stickers (which don't have any)
then the height is okay, but the message has the maximum width which
looks odd.

Instead, let's limit all stickers to 256px and it makes them look much
nicer in chat.
2024-11-16 16:12:56 -05:00
Joshua Goins
1cca9733d6 Add a comment that these are not normal quotation marks
It can be hard to tell depending on which font you're viewing the code
with.
2024-11-16 16:02:12 -05:00
Joshua Goins
1104da5e2c TextHandler: Use the fancy Unicode quotation characters
As per our HIG, we should use these in quotations instead of the normal
quote characters.
2024-11-16 21:01:04 +00:00
Joshua Goins
3a9718c09d Limit the width of a user's QR code
This fixes the lopsided layout in the user details dialog.
2024-11-16 21:00:39 +00:00
Joshua Goins
55362c5573 RoomManager: Unify the resolveResource overloads
Every time I look at how resource resolving works, I always trip over
this unused overload. This behaves *different* than the other overload,
which has special cases for handling invalid Uris.

Now whether you pass in a Uri or a QString, it should behave the same.
2024-11-16 21:00:29 +00:00
Joshua Goins
0bba2299b3 Set the size of custom emoticons to the font height, and fix alignment
Currently custom emojis render weirdly in NeoChat. Not only are they
large, they're also in charge and like to mess up the layout of the
text.

Now that's fixed and they'll take up the same height as the surrounding
text. It's now centered in the text too.
2024-11-16 21:00:11 +00:00
Joshua Goins
45685af9e9 Add icons to the recommended space actions, fix spacing of the items 2024-11-16 20:59:57 +00:00
Joshua Goins
6c416a9338 Fix restoring the last used space on desktop
This was supposed to work, but it's done in the wrong order. We need to
set the current space first, and then select the room - otherwise
it doesn't get restored.
2024-11-16 20:59:45 +00:00
Joshua Goins
1b0027e1d2 Ensure it's not possible for the recommended space avatar to assert 2024-11-16 20:59:02 +00:00
Joshua Goins
2409adf516 Fix avatars not loading in the room completion model 2024-11-16 20:59:02 +00:00
Joshua Goins
554801dfe4 Make sure RoomInformation's source is type url 2024-11-16 20:59:02 +00:00
Joshua Goins
20c23917e9 Remove now unused NeoChatRoomMember::avatarMediaId() 2024-11-16 20:59:02 +00:00
Joshua Goins
ef953b7574 Remove more needless usages of makeMediaUrl
This is only really needed in specific cases, e.g. localUser which isn't
attached to a connection and thus needs a little help. Notes for when
this is needed is added for future readers.
2024-11-16 20:59:02 +00:00
Joshua Goins
6b79795229 Change how room avatars are passed, fix friend avatars not loading
The problem lies in how media URLs work, in this case it the old
NeoChatRoom::avatarMediaId could pass a mxc url *or* a path that can
be put into root.connection.makeMediaUrl. So normal rooms with avatars
loaded, but never friends because room members gave the mxc URL.

Instead, change everything to use avatarMediaUrl which corrects this
issue by always passing a mxc URL to QML. This also removes the need to
call makeMediaUrl.

Fixes #675
2024-11-16 20:59:02 +00:00
Joshua Goins
9cb7ec2348 Add ellipses to the "Forward" message action, because it opens a dialog 2024-11-16 18:53:53 +00:00
Joshua Goins
437c981d30 Don't show the file name underneath the image
This still keeps custom image descriptions, but no longer shows it for
images where it was the same as their filename.
2024-11-16 13:18:46 -05:00
Joshua Goins
0334cae4c8 Change the room alias text color to disabled
It's less important than the title, and this should reduce it's visual
prominence.
2024-11-16 16:40:57 +00:00
Joshua Goins
24c405d747 Add a separator between the report and copy message actions 2024-11-16 11:39:18 -05:00
Joshua Goins
a3f5962809 DelegateContextMenu: Add support for separators in the mobile menu too 2024-11-16 11:30:49 -05:00
Joshua Goins
0deb7495f0 Re-arrange the file and message context menus, add separators
Like the room context menu, this is a jumbled list of actions that could
use some organization. Also, the text for "Copy Text" and "Copy Link" is
clearer.
2024-11-16 11:23:39 -05:00
Joshua Goins
d34f89fc4b DelegateContextMenu: Add support for separator actions 2024-11-16 11:22:37 -05:00
Joshua Goins
a909ed498f Hide the category list in the emoji picker when there is none
This is easy to test if you have no stickers. It should no longer have
a weird empty space above the placeholder message.
2024-11-16 16:03:36 +00:00
Joshua Goins
16f4e17e8f Improve how stickers appear in the emoji picker
First, the fill mode for the sticker images shouldn't stretch them.
Also make sure there is enough padding in the category so the image
doesn't appear larger than the button. Finally, set the source size for
the images so Qt can smooth them out better.
2024-11-16 16:03:24 +00:00
Joshua Goins
0e9592a96c Settings: Use symbolic version of the NeoChat icon
To match the rest of the icons in this sidebar, we can reuse our tray
icon.
2024-11-16 16:03:09 +00:00
Joshua Goins
704ee6a53a Add placeholder icon when there's no emojis or stickers 2024-11-16 10:50:49 -05:00
Joshua Goins
5b9afbce9a Settings: Request symbolic versions of the icons
According to the HIG, we should be using symbolic versions of these
icons at this size. Not that we have symbolic versions for these icons
yet, but it's still safe to do as they'll fall back to the old ones.
2024-11-16 09:48:13 -05:00
Thiago Sueto
396cc8e8ef Make top margin consistent across Neochat settings
This standardizes on the same value used for KirigamiAddons pages like AboutKDE and About, namely largeSpacing * 4.

Now, when switching between settings pages you no longer have settings inconsistently changing heights willy nilly, header notwithstanding.

The only page that's missing is the Spellchecking page, as that needs to be fixed in Kirigami Addons' private Sonnet page.
2024-11-16 14:37:01 +00:00
Thiago Sueto
bf776b5c06 Fix inconsistent wording about leaving current space/room
For rooms, we already say "Leave this room".

When viewing a Space page, we have both "Leave the space" and "Leave this room". The "Leave the space" VS "Leave this space" was bothering me, and the Space page should say "Leave this space" instead of "Leave this room".
2024-11-16 14:36:30 +00:00
Joshua Goins
be319f88d3 "Save As" action should have ellipses
Because you have to interact with the save dialog before doing anything
else.
2024-11-16 14:25:47 +00:00
Joshua Goins
af40d555d4 Improve the layout and function of the room context menu
The room context menu is a jumbled mess of actions, so the first idea of
this commit is to organize them. The first item is "Mark as Read"
because let's be honest, you're going to be using that the most. Then
the next "group" of actions are what users can "do" with the room. This
is like "Notification settings", "Favorite" and etc. Then there's room
settings, and leave.

Secondly, the "Favorite" action now uses the same icon we use elsewhere.

Third, "Notification State" is a weird name for this action and renamed
to simply "Notifications".

Finally, the "Mark as Read" action is now disabled when there's nothing
else to read.
2024-11-16 14:25:12 +00:00
Joshua Goins
f802dbe686 Port from deprecated AboutKDE component to AboutKDEPage 2024-11-16 14:24:10 +00:00
Joshua Goins
2379e3d83b Don't scroll up when clicking on the same room over and over
If you try to click on your current room in the list, it scrolls up the
messages a bit. This is because in RoomManager::visitRoom it's being
called with an empty eventId and we will happily emit a goToEvent. This
is despite there being nothing to go to.

Fixes #677.
2024-11-16 14:18:32 +00:00
Joshua Goins
9e90ac0412 Add margins to the room drawer header to match Kirigami
Otherwise it sticks to the left of the drawer and looks kinda ugly.
2024-11-16 14:16:50 +00:00
Joshua Goins
c27948ca3c Change the leave button in the drawer to "Leave this space" if needed 2024-11-16 14:14:32 +00:00
Joshua Goins
c3b9d664df "Room Information" title should be capitalized 2024-11-16 14:13:32 +00:00
Joshua Goins
31ef0a5223 Make it so the filename is filled out by default when saving files
This was never ported from the Qt labs platform FileDialog, because
currentFile doesn't exist anymore. It's now called selectedFile.
2024-11-16 14:12:19 +00:00
Joshua Goins
14c58acea1 Improve the appearance of the welcome page user list
Before it only listed the user id, and nothing else. If you had multiple
accounts, it's a little difficult to tell them apart. Now the user
selection appears like how they are displayed elsewhere in NeoChat, with
the display name and avatar.

| Before | After |
| ------ | ------ |
|   ![Screenshot_20241115_221425](/uploads/3986e4c7bbb7dcdca67ee30bb529767e/Screenshot_20241115_221425.png){width=786 height=822}     |        ![Screenshot_20241115_221149](/uploads/57eb1a7e57ba5ae8c41dd922cbf39c62/Screenshot_20241115_221149.png){width=786 height=822} |
2024-11-16 14:11:55 +00:00
l10n daemon script
5dae20603e GIT_SILENT Sync po/docbooks with svn 2024-11-16 01:34:25 +00:00
Joshua Goins
3f6fa94289 Port from Kirigami Add-ons Banner to Kirigami InlineMessage 2024-11-15 17:29:56 +00:00
l10n daemon script
117615a8b0 GIT_SILENT Sync po/docbooks with svn 2024-11-15 01:32:04 +00:00
l10n daemon script
4a52773c7d GIT_SILENT Sync po/docbooks with svn 2024-11-14 01:31:26 +00:00
l10n daemon script
edfee495c6 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-11-14 01:24:49 +00:00
l10n daemon script
7d112df7c6 GIT_SILENT made messages (after extraction) 2024-11-14 00:40:15 +00:00
124 changed files with 9513 additions and 13458 deletions

View File

@@ -11,7 +11,6 @@
#include <qnamespace.h>
#include "enums/messagecomponenttype.h"
#include "models/customemojimodel.h"
#include "neochatconnection.h"
#include "testutils.h"
@@ -77,7 +76,6 @@ void TextHandlerTest::initTestCase()
QJsonObject{{"body"_ls, "Test custom emoji"_ls},
{"url"_ls, "mxc://example.org/test"_ls},
{"usage"_ls, QJsonArray{"emoticon"_ls}}}}}}});
CustomEmojiModel::instance().setConnection(static_cast<NeoChatConnection *>(connection));
room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-texthandler-sync.json"));
}
@@ -535,7 +533,7 @@ void TextHandlerTest::componentOutput_data()
QVariantMap{{QStringLiteral("class"), QStringLiteral("html")}}}};
QTest::newRow("quote") << QStringLiteral("<p>Text</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>")
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}},
MessageComponent{MessageComponentType::Quote, QStringLiteral("\"blockquote\""), {}}};
MessageComponent{MessageComponentType::Quote, QStringLiteral("blockquote"), {}}};
QTest::newRow("no tag first paragraph") << QStringLiteral("Text\n<p>Text</p>")
<< QList<MessageComponent>{MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}},
MessageComponent{MessageComponentType::Text, QStringLiteral("Text"), {}}};

View File

@@ -59,6 +59,7 @@
<summary xml:lang="eu">Berriketa Matrix-en</summary>
<summary xml:lang="fr">Discuter sur Matrix</summary>
<summary xml:lang="gl">Charlar en Matrix</summary>
<summary xml:lang="hu">Csevegés Matrixon</summary>
<summary xml:lang="ia">Conversation en ditecto sur Matrix</summary>
<summary xml:lang="it">Chat su Matrix</summary>
<summary xml:lang="ka">ისაუბრეთ Matrix-ზე</summary>

View File

@@ -89,16 +89,20 @@ GenericName[zh_CN]=Matrix 客户端
GenericName[zh_TW]=Matrix 用戶端
Comment=Chat on Matrix
Comment[ca]=Xat a Matrix
Comment[ca@valencia]=Xat a Matrix
Comment[en_GB]=Chat on Matrix
Comment[es]=Chat en Matrix
Comment[eu]=Berriketa Matrix-en
Comment[fr]=Clavarder sur Matrix
Comment[gl]=Charle en Matrix
Comment[hu]=Csevegés Matrixon
Comment[ia]=Conversation en ditecto sur Matrix
Comment[it]= su Matrix
Comment[ka]=ჩატი Matrix-ზე
Comment[nl]=Chat op Matrix
Comment[pl]=Rozmawiaj na Matriksie
Comment[sl]=Klepet na Matrixu
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும்
Comment[tr]=Matrix Üzerinde Sohbet Et
Comment[uk]=Спілкування у Matrix
Comment[x-test]=xxChat on Matrixxx

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2024-11-13 00:40+0000\n"
"POT-Creation-Date: 2024-11-19 00:40+0000\n"
"PO-Revision-Date: 2023-12-12 01:02+0100\n"
"Last-Translator: Enol P. <enolp@softastur.org>\n"
"Language-Team: Asturian <alministradores@softastur.org>\n"
@@ -47,33 +47,33 @@ msgstr ""
msgid "Send message"
msgstr ""
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Send an encrypted message…"
msgstr ""
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Set an attachment caption…"
msgstr ""
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Send a message…"
msgstr ""
#: src/chatbar/ChatBar.qml:376
#: src/chatbar/ChatBar.qml:375
#, kde-format
msgctxt "@action:button"
msgid "Cancel reply"
msgstr ""
#: src/chatbar/EmojiGrid.qml:87
#: src/chatbar/EmojiGrid.qml:88
#, kde-format
msgid "No stickers"
msgstr ""
#: src/chatbar/EmojiGrid.qml:87
#: src/chatbar/EmojiGrid.qml:88
#, kde-format
msgid "No emojis"
msgstr ""
@@ -910,7 +910,7 @@ msgstr ""
msgid "Loading"
msgstr ""
#: src/login/Loading.qml:16
#: src/login/Loading.qml:17
#, kde-format
msgid ""
"Please wait while your messages are loaded from the server. This might take "
@@ -934,7 +934,7 @@ msgstr ""
msgid "Loading…"
msgstr ""
#: src/login/Login.qml:38 src/login/WelcomePage.qml:232
#: src/login/Login.qml:38 src/login/WelcomePage.qml:249
#: src/settings/ThreePIdCard.qml:183
#, kde-format
msgctxt "@action:button"
@@ -976,7 +976,7 @@ msgstr ""
msgid "Password:"
msgstr ""
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:152
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:154
#: src/settings/NetworkProxyPage.qml:122
#, kde-format
msgid "Password"
@@ -1030,47 +1030,47 @@ msgstr ""
msgid "Username unavailable"
msgstr ""
#: src/login/WelcomePage.qml:25
#: src/login/WelcomePage.qml:26
#, kde-format
msgid "Welcome"
msgstr ""
#: src/login/WelcomePage.qml:73 src/main.cpp:141
#: src/login/WelcomePage.qml:74 src/main.cpp:141
#, kde-format
msgid "NeoChat"
msgstr ""
#: src/login/WelcomePage.qml:81
#: src/login/WelcomePage.qml:82
#, kde-format
msgctxt "@title"
msgid "Continue with an existing account"
msgstr ""
#: src/login/WelcomePage.qml:115
#: src/login/WelcomePage.qml:132
#, kde-format
msgctxt "As in 'this account is still loading'"
msgid "%1 (loading)"
msgstr ""
#: src/login/WelcomePage.qml:124
#: src/login/WelcomePage.qml:141
#, kde-format
msgctxt "@action:button"
msgid "Log out of this account"
msgstr ""
#: src/login/WelcomePage.qml:153
#: src/login/WelcomePage.qml:170
#, kde-format
msgctxt "@title"
msgid "Log in or Create a New Account"
msgstr ""
#: src/login/WelcomePage.qml:240
#: src/login/WelcomePage.qml:257
#, kde-format
msgctxt "@action:button"
msgid "Go back"
msgstr ""
#: src/login/WelcomePage.qml:252
#: src/login/WelcomePage.qml:269
#, kde-format
msgctxt "@action:button"
msgid "Settings"
@@ -1850,7 +1850,7 @@ msgstr ""
msgid "Open NeoChat in this room"
msgstr ""
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:110
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:111
#: src/qml/HoverActions.qml:123
#, kde-format
msgid "Reply"
@@ -1905,58 +1905,58 @@ msgctxt "@action:button"
msgid "Show QR code"
msgstr ""
#: src/qml/AccountMenu.qml:39 src/qml/UserInfo.qml:46
#: src/qml/AccountMenu.qml:40 src/qml/UserInfo.qml:46
#, kde-format
msgid "Edit this account"
msgstr ""
#: src/qml/AccountMenu.qml:44 src/settings/AccountsPage.qml:33
#: src/qml/AccountMenu.qml:45 src/settings/AccountsPage.qml:33
#: src/settings/AccountsPage.qml:50
#, kde-format
msgid "Account editor"
msgstr ""
#: src/qml/AccountMenu.qml:48
#: src/qml/AccountMenu.qml:49
#, kde-format
msgid "Notification settings"
msgstr ""
#: src/qml/AccountMenu.qml:55 src/settings/DevicesPage.qml:17
#: src/qml/AccountMenu.qml:56 src/settings/DevicesPage.qml:17
#: src/settings/NeoChatSettingsView.qml:89
#, kde-format
msgid "Devices"
msgstr ""
#: src/qml/AccountMenu.qml:62 src/settings/NeoChatGeneralPage.qml:269
#: src/qml/AccountMenu.qml:63 src/settings/NeoChatGeneralPage.qml:269
#, kde-format
msgid "Open developer tools"
msgstr ""
#: src/qml/AccountMenu.qml:68
#: src/qml/AccountMenu.qml:69
#, kde-format
msgctxt "@title:window"
msgid "Developer Tools"
msgstr ""
#: src/qml/AccountMenu.qml:74
#: src/qml/AccountMenu.qml:75
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Secret Backup"
msgstr ""
#: src/qml/AccountMenu.qml:78
#: src/qml/AccountMenu.qml:79
#, kde-format
msgctxt "@title:window"
msgid "Open Key Backup"
msgstr ""
#: src/qml/AccountMenu.qml:82
#: src/qml/AccountMenu.qml:83
#, kde-format
msgctxt "@action:inmenu"
msgid "Verify this Device"
msgstr ""
#: src/qml/AccountMenu.qml:88 src/settings/AccountsPage.qml:87
#: src/qml/AccountMenu.qml:89 src/settings/AccountsPage.qml:88
#, kde-format
msgid "Logout"
msgstr ""
@@ -2007,7 +2007,7 @@ msgid "Attachment:"
msgstr ""
#: src/qml/AttachmentPane.qml:38 src/qml/HoverActions.qml:106
#: src/qml/ImageEditorPage.qml:21 src/qml/MessageDelegateContextMenu.qml:37
#: src/qml/ImageEditorPage.qml:20 src/qml/MessageDelegateContextMenu.qml:37
#, kde-format
msgid "Edit"
msgstr ""
@@ -2139,61 +2139,29 @@ msgctxt "@action:button"
msgid "Open"
msgstr ""
#: src/qml/ContextMenu.qml:31
#, kde-format
msgid "Remove from Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:31
#, kde-format
msgid "Add to Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:37 src/qml/ContextMenu.qml:197
#, kde-format
msgid "Reprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:37 src/qml/ContextMenu.qml:197
#, kde-format
msgid "Deprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:43 src/qml/ContextMenu.qml:204
#: src/qml/ContextMenu.qml:31 src/qml/ContextMenu.qml:209
#, kde-format
msgid "Mark as Read"
msgstr ""
#: src/qml/ContextMenu.qml:49
#: src/qml/ContextMenu.qml:40
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy user's Matrix ID to Clipboard"
msgid "Notifications"
msgstr ""
#: src/qml/ContextMenu.qml:49 src/qml/SpaceListContextMenu.qml:38
#: src/qml/SpaceListContextMenu.qml:120
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Address to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:61
#, kde-format
msgid "Notification State"
msgstr ""
#: src/qml/ContextMenu.qml:65
#: src/qml/ContextMenu.qml:44
#, kde-format
msgid "Follow Global Setting"
msgstr ""
#: src/qml/ContextMenu.qml:76 src/settings/PushNotification.qml:39
#: src/qml/ContextMenu.qml:55 src/settings/PushNotification.qml:39
#, kde-format
msgctxt "As in 'notify for all messages'"
msgid "All"
msgstr ""
#: src/qml/ContextMenu.qml:87 src/settings/PushNotification.qml:47
#: src/qml/ContextMenu.qml:66 src/settings/PushNotification.qml:47
#, kde-format
msgctxt ""
"As in 'notify when the user is mentioned or the message contains a set "
@@ -2201,34 +2169,67 @@ msgctxt ""
msgid "@Mentions and Keywords"
msgstr ""
#: src/qml/ContextMenu.qml:98 src/settings/PushNotification.qml:55
#: src/qml/ContextMenu.qml:77 src/settings/PushNotification.qml:55
#, kde-format
msgctxt "As in 'do not notify for any messages'"
msgid "Off"
msgstr ""
#: src/qml/ContextMenu.qml:111
#: src/qml/ContextMenu.qml:90
#, kde-format
msgid "Remove from Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:90
#, kde-format
msgid "Add to Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:96 src/qml/ContextMenu.qml:202
#, kde-format
msgid "Reprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:96 src/qml/ContextMenu.qml:202
#, kde-format
msgid "Deprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:104
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy user's Matrix ID to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:104 src/qml/SpaceListContextMenu.qml:38
#: src/qml/SpaceListContextMenu.qml:120
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Address to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:116
#, kde-format
msgctxt "@action:inmenu"
msgid "Room Settings"
msgstr ""
#: src/qml/ContextMenu.qml:121 src/qml/ContextMenu.qml:211
#: src/qml/ContextMenu.qml:126 src/qml/ContextMenu.qml:216
#, kde-format
msgid "Leave Room"
msgstr ""
#: src/qml/ContextMenu.qml:182
#: src/qml/ContextMenu.qml:187
#, kde-format
msgid "Remove from Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:182
#: src/qml/ContextMenu.qml:187
#, kde-format
msgid "Add to Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:192
#, kde-format
msgctxt "@action:button"
msgid "Room Settings"
@@ -2351,74 +2352,74 @@ msgctxt "@action:button"
msgid "Ok"
msgstr ""
#: src/qml/DelegateContextMenu.qml:83
#: src/qml/DelegateContextMenu.qml:84
#, kde-format
msgid "View Source"
msgstr ""
#: src/qml/DelegateContextMenu.qml:90 src/settings/ThreePIdCard.qml:66
#: src/qml/DelegateContextMenu.qml:91 src/settings/ThreePIdCard.qml:66
#, kde-format
msgctxt "@action:button"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:95 src/qml/DelegateContextMenu.qml:100
#: src/qml/FileDelegateContextMenu.qml:76
#: src/qml/FileDelegateContextMenu.qml:81
#: src/qml/DelegateContextMenu.qml:96 src/qml/DelegateContextMenu.qml:101
#: src/qml/FileDelegateContextMenu.qml:82
#: src/qml/FileDelegateContextMenu.qml:87
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:96 src/qml/FileDelegateContextMenu.qml:77
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:83
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:78
#: src/qml/DelegateContextMenu.qml:98 src/qml/FileDelegateContextMenu.qml:84
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove this message'"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:120 src/qml/DelegateContextMenu.qml:128
#: src/qml/DelegateContextMenu.qml:121 src/qml/DelegateContextMenu.qml:129
#, kde-format
msgctxt ""
"@action:button 'Report' as in 'Report this event to the administrators'"
msgid "Report"
msgstr ""
#: src/qml/DelegateContextMenu.qml:125
#: src/qml/DelegateContextMenu.qml:126
#, kde-format
msgctxt "@title:dialog"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:126
#: src/qml/DelegateContextMenu.qml:127
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for reporting this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:130
#: src/qml/DelegateContextMenu.qml:131
#, kde-format
msgctxt "@title"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:140
#: src/qml/DelegateContextMenu.qml:141
#, kde-format
msgctxt "@action:inmenu"
msgid "Show User"
msgstr ""
#: src/qml/DelegateContextMenu.qml:188
#: src/qml/DelegateContextMenu.qml:204
#, kde-format
msgid "Search for '%1'"
msgstr ""
#: src/qml/DelegateContextMenu.qml:210
#: src/qml/DelegateContextMenu.qml:226
#, kde-format
msgid "Configure Web Shortcuts..."
msgstr ""
@@ -2613,23 +2614,25 @@ msgctxt "@info:label"
msgid "No public rooms found"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:46
#: src/qml/FileDelegateContextMenu.qml:50
#, kde-format
msgid "Open Externally"
msgctxt "@action:inmenu"
msgid "Open Image"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:53
#: src/qml/FileDelegateContextMenu.qml:57
#, kde-format
msgid "Save As"
msgctxt "@action:inmenu"
msgid "Save Image…"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:63
#: src/qml/MessageDelegateContextMenu.qml:64
#: src/qml/FileDelegateContextMenu.qml:66
#, kde-format
msgid "Copy"
msgctxt "@action:inmenu"
msgid "Copy Image"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:71
#: src/qml/FileDelegateContextMenu.qml:77
#, kde-format
msgid "Remove"
msgstr ""
@@ -2779,55 +2782,55 @@ msgctxt "@info screenreader"
msgid "The currently selected link"
msgstr ""
#: src/qml/ImageEditorPage.qml:37
#: src/qml/ImageEditorPage.qml:36
#, kde-format
msgctxt "@action:button Undo modification"
msgid "Undo"
msgstr ""
#: src/qml/ImageEditorPage.qml:44
#: src/qml/ImageEditorPage.qml:43
#, kde-format
msgctxt "@action:button Accept image modification"
msgid "Accept"
msgstr ""
#: src/qml/ImageEditorPage.qml:52
#: src/qml/ImageEditorPage.qml:51
#, kde-format
msgid ""
"Unable to save file. Check if you have the correct permission to edit the "
"cache directory."
msgstr ""
#: src/qml/ImageEditorPage.qml:124
#: src/qml/ImageEditorPage.qml:123
#, kde-format
msgid "Cancel"
msgstr ""
#: src/qml/ImageEditorPage.qml:124 src/qml/ImageEditorPage.qml:140
#: src/qml/ImageEditorPage.qml:123 src/qml/ImageEditorPage.qml:139
#, kde-format
msgctxt "@action:button Crop an image"
msgid "Crop"
msgstr ""
#: src/qml/ImageEditorPage.qml:145
#: src/qml/ImageEditorPage.qml:144
#, kde-format
msgctxt "@action:button Rotate an image to the left"
msgid "Rotate left"
msgstr ""
#: src/qml/ImageEditorPage.qml:151
#: src/qml/ImageEditorPage.qml:150
#, kde-format
msgctxt "@action:button Rotate an image to the right"
msgid "Rotate right"
msgstr ""
#: src/qml/ImageEditorPage.qml:157
#: src/qml/ImageEditorPage.qml:156
#, kde-format
msgctxt "@action:button Mirror an image vertically"
msgid "Flip"
msgstr ""
#: src/qml/ImageEditorPage.qml:163
#: src/qml/ImageEditorPage.qml:162
#, kde-format
msgctxt "@action:button Mirror an image horizontally"
msgid "Mirror"
@@ -3055,7 +3058,7 @@ msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:47
#, kde-format
msgctxt "@action:inmenu As in 'Forward this message'"
msgid "Forward"
msgid "Forward"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:53
@@ -3064,9 +3067,16 @@ msgctxt "@title"
msgid "Forward Message"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:67
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Text"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:72
#, kde-format
msgid "Copy Link"
msgctxt "@action:inmenu"
msgid "Copy Message Link"
msgstr ""
#: src/qml/MessageSourceSheet.qml:46
@@ -3161,7 +3171,7 @@ msgctxt "@action:button"
msgid "Join"
msgstr ""
#: src/qml/RecommendedSpaceDialog.qml:61
#: src/qml/RecommendedSpaceDialog.qml:63
#, kde-format
msgctxt "@action:button"
msgid "Ignore"
@@ -3195,18 +3205,18 @@ msgstr ""
msgid "Configure room"
msgstr ""
#: src/qml/RoomDrawer.qml:111 src/qml/RoomDrawerPage.qml:45
#: src/qml/RoomDrawer.qml:114 src/qml/RoomDrawerPage.qml:45
#, kde-format
msgctxt "@action:button"
msgid "Room settings"
msgstr ""
#: src/qml/RoomDrawer.qml:160 src/qml/RoomDrawerPage.qml:85
#: src/qml/RoomDrawer.qml:163 src/qml/RoomDrawerPage.qml:85
#, kde-format
msgid "Information"
msgstr ""
#: src/qml/RoomDrawer.qml:165 src/qml/RoomDrawerPage.qml:90
#: src/qml/RoomDrawer.qml:168 src/qml/RoomDrawerPage.qml:90
#, kde-format
msgid "Media"
msgstr ""
@@ -3220,7 +3230,7 @@ msgstr ""
#: src/qml/RoomInformation.qml:42
#, kde-format
msgctxt "@action:title"
msgid "Room information"
msgid "Room Information"
msgstr ""
#: src/qml/RoomInformation.qml:70
@@ -3261,6 +3271,12 @@ msgstr ""
msgid "Show locations for this room"
msgstr ""
#: src/qml/RoomInformation.qml:136 src/qml/SpaceHomePage.qml:65
#, kde-format
msgctxt "@action:button"
msgid "Leave this space"
msgstr ""
#: src/qml/RoomInformation.qml:136
#, kde-format
msgctxt "@action:button"
@@ -3332,7 +3348,7 @@ msgctxt "@action:title"
msgid "Room Media"
msgstr ""
#: src/qml/RoomPage.qml:93
#: src/qml/RoomPage.qml:92
#, kde-format
msgid "NeoChat is offline. Please check your network connection."
msgstr ""
@@ -3570,12 +3586,6 @@ msgctxt "@button"
msgid "Invite user to space"
msgstr ""
#: src/qml/SpaceHomePage.qml:65
#, kde-format
msgctxt "@button"
msgid "Leave the space"
msgstr ""
#: src/qml/SpaceHomePage.qml:76 src/qml/SpaceListContextMenu.qml:48
#: src/qml/SpaceListContextMenu.qml:130
#, kde-format
@@ -3629,7 +3639,7 @@ msgid_plural "%2 are typing"
msgstr[0] ""
msgstr[1] ""
#: src/qml/UnlockSSSSDialog.qml:17
#: src/qml/UnlockSSSSDialog.qml:16
#, kde-format
msgctxt "@title:window"
msgid "Load your encrypted messages"
@@ -3717,129 +3727,129 @@ msgctxt "@title:menu Account details dialog"
msgid "Account Details"
msgstr ""
#: src/qml/UserDetailDialog.qml:109
#: src/qml/UserDetailDialog.qml:111
#, kde-format
msgid "Unignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:109
#: src/qml/UserDetailDialog.qml:111
#, kde-format
msgid "Ignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:122
#: src/qml/UserDetailDialog.qml:124
#, kde-format
msgid "Kick this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:126 src/qml/UserDetailDialog.qml:131
#: src/qml/UserDetailDialog.qml:128 src/qml/UserDetailDialog.qml:133
#, kde-format
msgctxt "@title:dialog"
msgid "Kick User"
msgstr ""
#: src/qml/UserDetailDialog.qml:127
#: src/qml/UserDetailDialog.qml:129
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for kicking this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:128
#: src/qml/UserDetailDialog.qml:130
#, kde-format
msgctxt "@action:button 'Kick' as in 'Kick this user from the room'"
msgid "Kick"
msgstr ""
#: src/qml/UserDetailDialog.qml:147
#: src/qml/UserDetailDialog.qml:149
#, kde-format
msgid "Invite this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:160
#: src/qml/UserDetailDialog.qml:162
#, kde-format
msgid "Ban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:165 src/qml/UserDetailDialog.qml:170
#: src/qml/UserDetailDialog.qml:167 src/qml/UserDetailDialog.qml:172
#, kde-format
msgctxt "@title:dialog"
msgid "Ban User"
msgstr ""
#: src/qml/UserDetailDialog.qml:166
#: src/qml/UserDetailDialog.qml:168
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for banning this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:167
#: src/qml/UserDetailDialog.qml:169
#, kde-format
msgctxt "@action:button 'Ban' as in 'Ban this user'"
msgid "Ban"
msgstr ""
#: src/qml/UserDetailDialog.qml:185
#: src/qml/UserDetailDialog.qml:187
#, kde-format
msgid "Unban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:198
#: src/qml/UserDetailDialog.qml:200
#, kde-format
msgid "Set user power level"
msgstr ""
#: src/qml/UserDetailDialog.qml:223
#: src/qml/UserDetailDialog.qml:225
#, kde-format
msgctxt "@action:button"
msgid "Remove recent messages by this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:228
#: src/qml/UserDetailDialog.qml:230
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:229
#: src/qml/UserDetailDialog.qml:231
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this user's recent messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:230
#: src/qml/UserDetailDialog.qml:232
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove these messages'"
msgid "Remove"
msgstr ""
#: src/qml/UserDetailDialog.qml:233
#: src/qml/UserDetailDialog.qml:235
#, kde-format
msgctxt "@title"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:247
#: src/qml/UserDetailDialog.qml:249
#, kde-format
msgctxt "%1 is the name of the user."
msgid "Chat with %1"
msgstr ""
#: src/qml/UserDetailDialog.qml:247
#: src/qml/UserDetailDialog.qml:249
#, kde-format
msgid "Invite to private chat"
msgstr ""
#: src/qml/UserDetailDialog.qml:258
#: src/qml/UserDetailDialog.qml:260
#, kde-format
msgid "Copy link"
msgstr ""
#: src/qml/UserInfo.qml:91
#: src/qml/UserInfo.qml:92
#, kde-format
msgid "Switch User"
msgstr ""
#: src/qml/UserInfo.qml:100
#: src/qml/UserInfo.qml:101
#, kde-format
msgid "Open Settings"
msgstr ""
@@ -4057,7 +4067,7 @@ msgstr ""
msgid "Working"
msgstr ""
#: src/roommanager.cpp:146
#: src/roommanager.cpp:145
#, kde-format
msgid "Malformed or empty Matrix id<br />%1 is not a correct Matrix identifier"
msgstr ""
@@ -4082,126 +4092,126 @@ msgstr ""
msgid "Edit Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:61
#: src/settings/AccountEditorPage.qml:62
#, kde-format
msgid "Upload new avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:78
#: src/settings/AccountEditorPage.qml:79
#, kde-format
msgid "Remove current avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:101
#: src/settings/AccountEditorPage.qml:102
#, kde-format
msgid "User Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:106
#: src/settings/AccountEditorPage.qml:107
#, kde-format
msgid "Display Name:"
msgstr ""
#: src/settings/AccountEditorPage.qml:112
#: src/settings/AccountEditorPage.qml:113
#, kde-format
msgid "Label:"
msgstr ""
#: src/settings/AccountEditorPage.qml:113
#: src/settings/AccountEditorPage.qml:114
#, kde-format
msgid "Work"
msgstr ""
#: src/settings/AccountEditorPage.qml:118
#: src/settings/AccountEditorPage.qml:119
#, kde-format
msgctxt "@action:button"
msgid "Show QR Code"
msgstr ""
#: src/settings/AccountEditorPage.qml:135
#: src/settings/AccountEditorPage.qml:191
#: src/settings/AccountEditorPage.qml:137
#: src/settings/AccountEditorPage.qml:193
#: src/settings/EmoticonEditorPage.qml:108 src/settings/RoomGeneralPage.qml:98
#, kde-format
msgid "Save"
msgstr ""
#: src/settings/AccountEditorPage.qml:157
#: src/settings/AccountEditorPage.qml:159
#, kde-format
msgid "Your server doesn't support changing your password"
msgstr ""
#: src/settings/AccountEditorPage.qml:164
#: src/settings/AccountEditorPage.qml:166
#, kde-format
msgid "Current Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:171
#: src/settings/AccountEditorPage.qml:173
#, kde-format
msgid "New Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:178
#: src/settings/AccountEditorPage.qml:180
#, kde-format
msgid "Confirm new Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:183
#: src/settings/AccountEditorPage.qml:185
#, kde-format
msgid "Passwords don't match"
msgstr ""
#: src/settings/AccountEditorPage.qml:198
#: src/settings/AccountEditorPage.qml:200
#, kde-format
msgid "Passwords do not match"
msgstr ""
#: src/settings/AccountEditorPage.qml:205
#: src/settings/AccountEditorPage.qml:207
#, kde-format
msgid "Email Addresses"
msgstr ""
#: src/settings/AccountEditorPage.qml:211
#: src/settings/AccountEditorPage.qml:213
#, kde-format
msgid "Phone Numbers"
msgstr ""
#: src/settings/AccountEditorPage.qml:216
#: src/settings/AccountEditorPage.qml:218
#, kde-format
msgid "Identity Server"
msgstr ""
#: src/settings/AccountEditorPage.qml:225
#: src/settings/AccountEditorPage.qml:227
#, kde-format
msgid "Server Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:229
#: src/settings/AccountEditorPage.qml:231
#, kde-format
msgid "Homeserver url"
msgstr ""
#: src/settings/AccountEditorPage.qml:250
#: src/settings/AccountEditorPage.qml:252
#, kde-format
msgctxt "@title"
msgid "Account Management"
msgstr ""
#: src/settings/AccountEditorPage.qml:255
#: src/settings/AccountEditorPage.qml:257
#, kde-format
msgid "Deactivate Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:271
#: src/settings/AccountEditorPage.qml:273
#, kde-format
msgid "Password changed successfully"
msgstr ""
#: src/settings/AccountEditorPage.qml:273
#: src/settings/AccountEditorPage.qml:275
#, kde-format
msgid "Wrong password entered"
msgstr ""
#: src/settings/AccountEditorPage.qml:275
#: src/settings/AccountEditorPage.qml:277
#, kde-format
msgid "Unknown problem while trying to change password"
msgstr ""
@@ -4212,7 +4222,7 @@ msgstr ""
msgid "Accounts"
msgstr ""
#: src/settings/AccountsPage.qml:117
#: src/settings/AccountsPage.qml:118
#, kde-format
msgid "Add Account"
msgstr ""
@@ -4442,7 +4452,7 @@ msgctxt "@title"
msgid "Stickers & Emojis"
msgstr ""
#: src/settings/ExportKeysDialog.qml:18
#: src/settings/ExportKeysDialog.qml:17
#: src/settings/NeoChatSecurityPage.qml:107
#, kde-format
msgctxt "@title"
@@ -4591,7 +4601,7 @@ msgctxt "@action:button"
msgid "Unignore this user"
msgstr ""
#: src/settings/ImportKeysDialog.qml:22 src/settings/NeoChatSecurityPage.qml:84
#: src/settings/ImportKeysDialog.qml:21 src/settings/NeoChatSecurityPage.qml:84
#, kde-format
msgctxt "@title"
msgid "Import Keys"
@@ -4755,7 +4765,7 @@ msgctxt "@action:button"
msgid "Reset all configuration values to their default"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:19
#: src/settings/NeoChatSecurityPage.qml:18
#: src/settings/NeoChatSettingsView.qml:51
#, kde-format
msgctxt "@title"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2024-11-13 00:40+0000\n"
"POT-Creation-Date: 2024-11-19 00:40+0000\n"
"PO-Revision-Date: 2020-11-05 23:50-0800\n"
"Last-Translator: Japanese KDE translation team <kde-jp@kde.org>\n"
"Language-Team: Japanese <kde-jp@kde.org>\n"
@@ -44,33 +44,33 @@ msgstr ""
msgid "Send message"
msgstr ""
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Send an encrypted message…"
msgstr ""
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Set an attachment caption…"
msgstr ""
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Send a message…"
msgstr ""
#: src/chatbar/ChatBar.qml:376
#: src/chatbar/ChatBar.qml:375
#, kde-format
msgctxt "@action:button"
msgid "Cancel reply"
msgstr ""
#: src/chatbar/EmojiGrid.qml:87
#: src/chatbar/EmojiGrid.qml:88
#, kde-format
msgid "No stickers"
msgstr ""
#: src/chatbar/EmojiGrid.qml:87
#: src/chatbar/EmojiGrid.qml:88
#, kde-format
msgid "No emojis"
msgstr ""
@@ -906,7 +906,7 @@ msgstr ""
msgid "Loading"
msgstr ""
#: src/login/Loading.qml:16
#: src/login/Loading.qml:17
#, kde-format
msgid ""
"Please wait while your messages are loaded from the server. This might take "
@@ -930,7 +930,7 @@ msgstr ""
msgid "Loading…"
msgstr ""
#: src/login/Login.qml:38 src/login/WelcomePage.qml:232
#: src/login/Login.qml:38 src/login/WelcomePage.qml:249
#: src/settings/ThreePIdCard.qml:183
#, kde-format
msgctxt "@action:button"
@@ -972,7 +972,7 @@ msgstr ""
msgid "Password:"
msgstr ""
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:152
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:154
#: src/settings/NetworkProxyPage.qml:122
#, kde-format
msgid "Password"
@@ -1026,47 +1026,47 @@ msgstr ""
msgid "Username unavailable"
msgstr ""
#: src/login/WelcomePage.qml:25
#: src/login/WelcomePage.qml:26
#, kde-format
msgid "Welcome"
msgstr ""
#: src/login/WelcomePage.qml:73 src/main.cpp:141
#: src/login/WelcomePage.qml:74 src/main.cpp:141
#, kde-format
msgid "NeoChat"
msgstr ""
#: src/login/WelcomePage.qml:81
#: src/login/WelcomePage.qml:82
#, kde-format
msgctxt "@title"
msgid "Continue with an existing account"
msgstr ""
#: src/login/WelcomePage.qml:115
#: src/login/WelcomePage.qml:132
#, kde-format
msgctxt "As in 'this account is still loading'"
msgid "%1 (loading)"
msgstr ""
#: src/login/WelcomePage.qml:124
#: src/login/WelcomePage.qml:141
#, kde-format
msgctxt "@action:button"
msgid "Log out of this account"
msgstr ""
#: src/login/WelcomePage.qml:153
#: src/login/WelcomePage.qml:170
#, kde-format
msgctxt "@title"
msgid "Log in or Create a New Account"
msgstr ""
#: src/login/WelcomePage.qml:240
#: src/login/WelcomePage.qml:257
#, kde-format
msgctxt "@action:button"
msgid "Go back"
msgstr ""
#: src/login/WelcomePage.qml:252
#: src/login/WelcomePage.qml:269
#, kde-format
msgctxt "@action:button"
msgid "Settings"
@@ -1843,7 +1843,7 @@ msgstr ""
msgid "Open NeoChat in this room"
msgstr ""
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:110
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:111
#: src/qml/HoverActions.qml:123
#, kde-format
msgid "Reply"
@@ -1898,58 +1898,58 @@ msgctxt "@action:button"
msgid "Show QR code"
msgstr ""
#: src/qml/AccountMenu.qml:39 src/qml/UserInfo.qml:46
#: src/qml/AccountMenu.qml:40 src/qml/UserInfo.qml:46
#, kde-format
msgid "Edit this account"
msgstr ""
#: src/qml/AccountMenu.qml:44 src/settings/AccountsPage.qml:33
#: src/qml/AccountMenu.qml:45 src/settings/AccountsPage.qml:33
#: src/settings/AccountsPage.qml:50
#, kde-format
msgid "Account editor"
msgstr ""
#: src/qml/AccountMenu.qml:48
#: src/qml/AccountMenu.qml:49
#, kde-format
msgid "Notification settings"
msgstr ""
#: src/qml/AccountMenu.qml:55 src/settings/DevicesPage.qml:17
#: src/qml/AccountMenu.qml:56 src/settings/DevicesPage.qml:17
#: src/settings/NeoChatSettingsView.qml:89
#, kde-format
msgid "Devices"
msgstr ""
#: src/qml/AccountMenu.qml:62 src/settings/NeoChatGeneralPage.qml:269
#: src/qml/AccountMenu.qml:63 src/settings/NeoChatGeneralPage.qml:269
#, kde-format
msgid "Open developer tools"
msgstr ""
#: src/qml/AccountMenu.qml:68
#: src/qml/AccountMenu.qml:69
#, kde-format
msgctxt "@title:window"
msgid "Developer Tools"
msgstr ""
#: src/qml/AccountMenu.qml:74
#: src/qml/AccountMenu.qml:75
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Secret Backup"
msgstr ""
#: src/qml/AccountMenu.qml:78
#: src/qml/AccountMenu.qml:79
#, kde-format
msgctxt "@title:window"
msgid "Open Key Backup"
msgstr ""
#: src/qml/AccountMenu.qml:82
#: src/qml/AccountMenu.qml:83
#, kde-format
msgctxt "@action:inmenu"
msgid "Verify this Device"
msgstr ""
#: src/qml/AccountMenu.qml:88 src/settings/AccountsPage.qml:87
#: src/qml/AccountMenu.qml:89 src/settings/AccountsPage.qml:88
#, kde-format
msgid "Logout"
msgstr ""
@@ -2000,7 +2000,7 @@ msgid "Attachment:"
msgstr ""
#: src/qml/AttachmentPane.qml:38 src/qml/HoverActions.qml:106
#: src/qml/ImageEditorPage.qml:21 src/qml/MessageDelegateContextMenu.qml:37
#: src/qml/ImageEditorPage.qml:20 src/qml/MessageDelegateContextMenu.qml:37
#, kde-format
msgid "Edit"
msgstr ""
@@ -2132,61 +2132,29 @@ msgctxt "@action:button"
msgid "Open"
msgstr ""
#: src/qml/ContextMenu.qml:31
#, kde-format
msgid "Remove from Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:31
#, kde-format
msgid "Add to Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:37 src/qml/ContextMenu.qml:197
#, kde-format
msgid "Reprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:37 src/qml/ContextMenu.qml:197
#, kde-format
msgid "Deprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:43 src/qml/ContextMenu.qml:204
#: src/qml/ContextMenu.qml:31 src/qml/ContextMenu.qml:209
#, kde-format
msgid "Mark as Read"
msgstr ""
#: src/qml/ContextMenu.qml:49
#: src/qml/ContextMenu.qml:40
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy user's Matrix ID to Clipboard"
msgid "Notifications"
msgstr ""
#: src/qml/ContextMenu.qml:49 src/qml/SpaceListContextMenu.qml:38
#: src/qml/SpaceListContextMenu.qml:120
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Address to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:61
#, kde-format
msgid "Notification State"
msgstr ""
#: src/qml/ContextMenu.qml:65
#: src/qml/ContextMenu.qml:44
#, kde-format
msgid "Follow Global Setting"
msgstr ""
#: src/qml/ContextMenu.qml:76 src/settings/PushNotification.qml:39
#: src/qml/ContextMenu.qml:55 src/settings/PushNotification.qml:39
#, kde-format
msgctxt "As in 'notify for all messages'"
msgid "All"
msgstr ""
#: src/qml/ContextMenu.qml:87 src/settings/PushNotification.qml:47
#: src/qml/ContextMenu.qml:66 src/settings/PushNotification.qml:47
#, kde-format
msgctxt ""
"As in 'notify when the user is mentioned or the message contains a set "
@@ -2194,34 +2162,67 @@ msgctxt ""
msgid "@Mentions and Keywords"
msgstr ""
#: src/qml/ContextMenu.qml:98 src/settings/PushNotification.qml:55
#: src/qml/ContextMenu.qml:77 src/settings/PushNotification.qml:55
#, kde-format
msgctxt "As in 'do not notify for any messages'"
msgid "Off"
msgstr ""
#: src/qml/ContextMenu.qml:111
#: src/qml/ContextMenu.qml:90
#, kde-format
msgid "Remove from Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:90
#, kde-format
msgid "Add to Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:96 src/qml/ContextMenu.qml:202
#, kde-format
msgid "Reprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:96 src/qml/ContextMenu.qml:202
#, kde-format
msgid "Deprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:104
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy user's Matrix ID to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:104 src/qml/SpaceListContextMenu.qml:38
#: src/qml/SpaceListContextMenu.qml:120
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Address to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:116
#, kde-format
msgctxt "@action:inmenu"
msgid "Room Settings"
msgstr ""
#: src/qml/ContextMenu.qml:121 src/qml/ContextMenu.qml:211
#: src/qml/ContextMenu.qml:126 src/qml/ContextMenu.qml:216
#, kde-format
msgid "Leave Room"
msgstr ""
#: src/qml/ContextMenu.qml:182
#: src/qml/ContextMenu.qml:187
#, kde-format
msgid "Remove from Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:182
#: src/qml/ContextMenu.qml:187
#, kde-format
msgid "Add to Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:192
#, kde-format
msgctxt "@action:button"
msgid "Room Settings"
@@ -2344,74 +2345,74 @@ msgctxt "@action:button"
msgid "Ok"
msgstr ""
#: src/qml/DelegateContextMenu.qml:83
#: src/qml/DelegateContextMenu.qml:84
#, kde-format
msgid "View Source"
msgstr ""
#: src/qml/DelegateContextMenu.qml:90 src/settings/ThreePIdCard.qml:66
#: src/qml/DelegateContextMenu.qml:91 src/settings/ThreePIdCard.qml:66
#, kde-format
msgctxt "@action:button"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:95 src/qml/DelegateContextMenu.qml:100
#: src/qml/FileDelegateContextMenu.qml:76
#: src/qml/FileDelegateContextMenu.qml:81
#: src/qml/DelegateContextMenu.qml:96 src/qml/DelegateContextMenu.qml:101
#: src/qml/FileDelegateContextMenu.qml:82
#: src/qml/FileDelegateContextMenu.qml:87
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:96 src/qml/FileDelegateContextMenu.qml:77
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:83
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:78
#: src/qml/DelegateContextMenu.qml:98 src/qml/FileDelegateContextMenu.qml:84
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove this message'"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:120 src/qml/DelegateContextMenu.qml:128
#: src/qml/DelegateContextMenu.qml:121 src/qml/DelegateContextMenu.qml:129
#, kde-format
msgctxt ""
"@action:button 'Report' as in 'Report this event to the administrators'"
msgid "Report"
msgstr ""
#: src/qml/DelegateContextMenu.qml:125
#: src/qml/DelegateContextMenu.qml:126
#, kde-format
msgctxt "@title:dialog"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:126
#: src/qml/DelegateContextMenu.qml:127
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for reporting this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:130
#: src/qml/DelegateContextMenu.qml:131
#, kde-format
msgctxt "@title"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:140
#: src/qml/DelegateContextMenu.qml:141
#, kde-format
msgctxt "@action:inmenu"
msgid "Show User"
msgstr ""
#: src/qml/DelegateContextMenu.qml:188
#: src/qml/DelegateContextMenu.qml:204
#, kde-format
msgid "Search for '%1'"
msgstr ""
#: src/qml/DelegateContextMenu.qml:210
#: src/qml/DelegateContextMenu.qml:226
#, kde-format
msgid "Configure Web Shortcuts..."
msgstr ""
@@ -2606,23 +2607,25 @@ msgctxt "@info:label"
msgid "No public rooms found"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:46
#: src/qml/FileDelegateContextMenu.qml:50
#, kde-format
msgid "Open Externally"
msgctxt "@action:inmenu"
msgid "Open Image"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:53
#: src/qml/FileDelegateContextMenu.qml:57
#, kde-format
msgid "Save As"
msgctxt "@action:inmenu"
msgid "Save Image…"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:63
#: src/qml/MessageDelegateContextMenu.qml:64
#: src/qml/FileDelegateContextMenu.qml:66
#, kde-format
msgid "Copy"
msgctxt "@action:inmenu"
msgid "Copy Image"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:71
#: src/qml/FileDelegateContextMenu.qml:77
#, kde-format
msgid "Remove"
msgstr ""
@@ -2772,55 +2775,55 @@ msgctxt "@info screenreader"
msgid "The currently selected link"
msgstr ""
#: src/qml/ImageEditorPage.qml:37
#: src/qml/ImageEditorPage.qml:36
#, kde-format
msgctxt "@action:button Undo modification"
msgid "Undo"
msgstr ""
#: src/qml/ImageEditorPage.qml:44
#: src/qml/ImageEditorPage.qml:43
#, kde-format
msgctxt "@action:button Accept image modification"
msgid "Accept"
msgstr ""
#: src/qml/ImageEditorPage.qml:52
#: src/qml/ImageEditorPage.qml:51
#, kde-format
msgid ""
"Unable to save file. Check if you have the correct permission to edit the "
"cache directory."
msgstr ""
#: src/qml/ImageEditorPage.qml:124
#: src/qml/ImageEditorPage.qml:123
#, kde-format
msgid "Cancel"
msgstr ""
#: src/qml/ImageEditorPage.qml:124 src/qml/ImageEditorPage.qml:140
#: src/qml/ImageEditorPage.qml:123 src/qml/ImageEditorPage.qml:139
#, kde-format
msgctxt "@action:button Crop an image"
msgid "Crop"
msgstr ""
#: src/qml/ImageEditorPage.qml:145
#: src/qml/ImageEditorPage.qml:144
#, kde-format
msgctxt "@action:button Rotate an image to the left"
msgid "Rotate left"
msgstr ""
#: src/qml/ImageEditorPage.qml:151
#: src/qml/ImageEditorPage.qml:150
#, kde-format
msgctxt "@action:button Rotate an image to the right"
msgid "Rotate right"
msgstr ""
#: src/qml/ImageEditorPage.qml:157
#: src/qml/ImageEditorPage.qml:156
#, kde-format
msgctxt "@action:button Mirror an image vertically"
msgid "Flip"
msgstr ""
#: src/qml/ImageEditorPage.qml:163
#: src/qml/ImageEditorPage.qml:162
#, kde-format
msgctxt "@action:button Mirror an image horizontally"
msgid "Mirror"
@@ -3048,7 +3051,7 @@ msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:47
#, kde-format
msgctxt "@action:inmenu As in 'Forward this message'"
msgid "Forward"
msgid "Forward"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:53
@@ -3057,9 +3060,16 @@ msgctxt "@title"
msgid "Forward Message"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:67
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Text"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:72
#, kde-format
msgid "Copy Link"
msgctxt "@action:inmenu"
msgid "Copy Message Link"
msgstr ""
#: src/qml/MessageSourceSheet.qml:46
@@ -3154,7 +3164,7 @@ msgctxt "@action:button"
msgid "Join"
msgstr ""
#: src/qml/RecommendedSpaceDialog.qml:61
#: src/qml/RecommendedSpaceDialog.qml:63
#, kde-format
msgctxt "@action:button"
msgid "Ignore"
@@ -3188,18 +3198,18 @@ msgstr ""
msgid "Configure room"
msgstr ""
#: src/qml/RoomDrawer.qml:111 src/qml/RoomDrawerPage.qml:45
#: src/qml/RoomDrawer.qml:114 src/qml/RoomDrawerPage.qml:45
#, kde-format
msgctxt "@action:button"
msgid "Room settings"
msgstr ""
#: src/qml/RoomDrawer.qml:160 src/qml/RoomDrawerPage.qml:85
#: src/qml/RoomDrawer.qml:163 src/qml/RoomDrawerPage.qml:85
#, kde-format
msgid "Information"
msgstr ""
#: src/qml/RoomDrawer.qml:165 src/qml/RoomDrawerPage.qml:90
#: src/qml/RoomDrawer.qml:168 src/qml/RoomDrawerPage.qml:90
#, kde-format
msgid "Media"
msgstr ""
@@ -3213,7 +3223,7 @@ msgstr ""
#: src/qml/RoomInformation.qml:42
#, kde-format
msgctxt "@action:title"
msgid "Room information"
msgid "Room Information"
msgstr ""
#: src/qml/RoomInformation.qml:70
@@ -3254,6 +3264,12 @@ msgstr ""
msgid "Show locations for this room"
msgstr ""
#: src/qml/RoomInformation.qml:136 src/qml/SpaceHomePage.qml:65
#, kde-format
msgctxt "@action:button"
msgid "Leave this space"
msgstr ""
#: src/qml/RoomInformation.qml:136
#, kde-format
msgctxt "@action:button"
@@ -3324,7 +3340,7 @@ msgctxt "@action:title"
msgid "Room Media"
msgstr ""
#: src/qml/RoomPage.qml:93
#: src/qml/RoomPage.qml:92
#, kde-format
msgid "NeoChat is offline. Please check your network connection."
msgstr ""
@@ -3560,12 +3576,6 @@ msgctxt "@button"
msgid "Invite user to space"
msgstr ""
#: src/qml/SpaceHomePage.qml:65
#, kde-format
msgctxt "@button"
msgid "Leave the space"
msgstr ""
#: src/qml/SpaceHomePage.qml:76 src/qml/SpaceListContextMenu.qml:48
#: src/qml/SpaceListContextMenu.qml:130
#, kde-format
@@ -3618,7 +3628,7 @@ msgid "%2 is typing"
msgid_plural "%2 are typing"
msgstr[0] ""
#: src/qml/UnlockSSSSDialog.qml:17
#: src/qml/UnlockSSSSDialog.qml:16
#, kde-format
msgctxt "@title:window"
msgid "Load your encrypted messages"
@@ -3706,129 +3716,129 @@ msgctxt "@title:menu Account details dialog"
msgid "Account Details"
msgstr ""
#: src/qml/UserDetailDialog.qml:109
#: src/qml/UserDetailDialog.qml:111
#, kde-format
msgid "Unignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:109
#: src/qml/UserDetailDialog.qml:111
#, kde-format
msgid "Ignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:122
#: src/qml/UserDetailDialog.qml:124
#, kde-format
msgid "Kick this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:126 src/qml/UserDetailDialog.qml:131
#: src/qml/UserDetailDialog.qml:128 src/qml/UserDetailDialog.qml:133
#, kde-format
msgctxt "@title:dialog"
msgid "Kick User"
msgstr ""
#: src/qml/UserDetailDialog.qml:127
#: src/qml/UserDetailDialog.qml:129
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for kicking this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:128
#: src/qml/UserDetailDialog.qml:130
#, kde-format
msgctxt "@action:button 'Kick' as in 'Kick this user from the room'"
msgid "Kick"
msgstr ""
#: src/qml/UserDetailDialog.qml:147
#: src/qml/UserDetailDialog.qml:149
#, kde-format
msgid "Invite this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:160
#: src/qml/UserDetailDialog.qml:162
#, kde-format
msgid "Ban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:165 src/qml/UserDetailDialog.qml:170
#: src/qml/UserDetailDialog.qml:167 src/qml/UserDetailDialog.qml:172
#, kde-format
msgctxt "@title:dialog"
msgid "Ban User"
msgstr ""
#: src/qml/UserDetailDialog.qml:166
#: src/qml/UserDetailDialog.qml:168
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for banning this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:167
#: src/qml/UserDetailDialog.qml:169
#, kde-format
msgctxt "@action:button 'Ban' as in 'Ban this user'"
msgid "Ban"
msgstr ""
#: src/qml/UserDetailDialog.qml:185
#: src/qml/UserDetailDialog.qml:187
#, kde-format
msgid "Unban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:198
#: src/qml/UserDetailDialog.qml:200
#, kde-format
msgid "Set user power level"
msgstr ""
#: src/qml/UserDetailDialog.qml:223
#: src/qml/UserDetailDialog.qml:225
#, kde-format
msgctxt "@action:button"
msgid "Remove recent messages by this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:228
#: src/qml/UserDetailDialog.qml:230
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:229
#: src/qml/UserDetailDialog.qml:231
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this user's recent messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:230
#: src/qml/UserDetailDialog.qml:232
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove these messages'"
msgid "Remove"
msgstr ""
#: src/qml/UserDetailDialog.qml:233
#: src/qml/UserDetailDialog.qml:235
#, kde-format
msgctxt "@title"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:247
#: src/qml/UserDetailDialog.qml:249
#, kde-format
msgctxt "%1 is the name of the user."
msgid "Chat with %1"
msgstr ""
#: src/qml/UserDetailDialog.qml:247
#: src/qml/UserDetailDialog.qml:249
#, kde-format
msgid "Invite to private chat"
msgstr ""
#: src/qml/UserDetailDialog.qml:258
#: src/qml/UserDetailDialog.qml:260
#, kde-format
msgid "Copy link"
msgstr ""
#: src/qml/UserInfo.qml:91
#: src/qml/UserInfo.qml:92
#, kde-format
msgid "Switch User"
msgstr ""
#: src/qml/UserInfo.qml:100
#: src/qml/UserInfo.qml:101
#, kde-format
msgid "Open Settings"
msgstr ""
@@ -4046,7 +4056,7 @@ msgstr ""
msgid "Working"
msgstr ""
#: src/roommanager.cpp:146
#: src/roommanager.cpp:145
#, kde-format
msgid "Malformed or empty Matrix id<br />%1 is not a correct Matrix identifier"
msgstr ""
@@ -4071,126 +4081,126 @@ msgstr ""
msgid "Edit Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:61
#: src/settings/AccountEditorPage.qml:62
#, kde-format
msgid "Upload new avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:78
#: src/settings/AccountEditorPage.qml:79
#, kde-format
msgid "Remove current avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:101
#: src/settings/AccountEditorPage.qml:102
#, kde-format
msgid "User Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:106
#: src/settings/AccountEditorPage.qml:107
#, kde-format
msgid "Display Name:"
msgstr ""
#: src/settings/AccountEditorPage.qml:112
#: src/settings/AccountEditorPage.qml:113
#, kde-format
msgid "Label:"
msgstr ""
#: src/settings/AccountEditorPage.qml:113
#: src/settings/AccountEditorPage.qml:114
#, kde-format
msgid "Work"
msgstr ""
#: src/settings/AccountEditorPage.qml:118
#: src/settings/AccountEditorPage.qml:119
#, kde-format
msgctxt "@action:button"
msgid "Show QR Code"
msgstr ""
#: src/settings/AccountEditorPage.qml:135
#: src/settings/AccountEditorPage.qml:191
#: src/settings/AccountEditorPage.qml:137
#: src/settings/AccountEditorPage.qml:193
#: src/settings/EmoticonEditorPage.qml:108 src/settings/RoomGeneralPage.qml:98
#, kde-format
msgid "Save"
msgstr ""
#: src/settings/AccountEditorPage.qml:157
#: src/settings/AccountEditorPage.qml:159
#, kde-format
msgid "Your server doesn't support changing your password"
msgstr ""
#: src/settings/AccountEditorPage.qml:164
#: src/settings/AccountEditorPage.qml:166
#, kde-format
msgid "Current Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:171
#: src/settings/AccountEditorPage.qml:173
#, kde-format
msgid "New Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:178
#: src/settings/AccountEditorPage.qml:180
#, kde-format
msgid "Confirm new Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:183
#: src/settings/AccountEditorPage.qml:185
#, kde-format
msgid "Passwords don't match"
msgstr ""
#: src/settings/AccountEditorPage.qml:198
#: src/settings/AccountEditorPage.qml:200
#, kde-format
msgid "Passwords do not match"
msgstr ""
#: src/settings/AccountEditorPage.qml:205
#: src/settings/AccountEditorPage.qml:207
#, kde-format
msgid "Email Addresses"
msgstr ""
#: src/settings/AccountEditorPage.qml:211
#: src/settings/AccountEditorPage.qml:213
#, kde-format
msgid "Phone Numbers"
msgstr ""
#: src/settings/AccountEditorPage.qml:216
#: src/settings/AccountEditorPage.qml:218
#, kde-format
msgid "Identity Server"
msgstr ""
#: src/settings/AccountEditorPage.qml:225
#: src/settings/AccountEditorPage.qml:227
#, kde-format
msgid "Server Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:229
#: src/settings/AccountEditorPage.qml:231
#, kde-format
msgid "Homeserver url"
msgstr ""
#: src/settings/AccountEditorPage.qml:250
#: src/settings/AccountEditorPage.qml:252
#, kde-format
msgctxt "@title"
msgid "Account Management"
msgstr ""
#: src/settings/AccountEditorPage.qml:255
#: src/settings/AccountEditorPage.qml:257
#, kde-format
msgid "Deactivate Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:271
#: src/settings/AccountEditorPage.qml:273
#, kde-format
msgid "Password changed successfully"
msgstr ""
#: src/settings/AccountEditorPage.qml:273
#: src/settings/AccountEditorPage.qml:275
#, kde-format
msgid "Wrong password entered"
msgstr ""
#: src/settings/AccountEditorPage.qml:275
#: src/settings/AccountEditorPage.qml:277
#, kde-format
msgid "Unknown problem while trying to change password"
msgstr ""
@@ -4201,7 +4211,7 @@ msgstr ""
msgid "Accounts"
msgstr ""
#: src/settings/AccountsPage.qml:117
#: src/settings/AccountsPage.qml:118
#, kde-format
msgid "Add Account"
msgstr ""
@@ -4431,7 +4441,7 @@ msgctxt "@title"
msgid "Stickers & Emojis"
msgstr ""
#: src/settings/ExportKeysDialog.qml:18
#: src/settings/ExportKeysDialog.qml:17
#: src/settings/NeoChatSecurityPage.qml:107
#, kde-format
msgctxt "@title"
@@ -4580,7 +4590,7 @@ msgctxt "@action:button"
msgid "Unignore this user"
msgstr ""
#: src/settings/ImportKeysDialog.qml:22 src/settings/NeoChatSecurityPage.qml:84
#: src/settings/ImportKeysDialog.qml:21 src/settings/NeoChatSecurityPage.qml:84
#, kde-format
msgctxt "@title"
msgid "Import Keys"
@@ -4744,7 +4754,7 @@ msgctxt "@action:button"
msgid "Reset all configuration values to their default"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:19
#: src/settings/NeoChatSecurityPage.qml:18
#: src/settings/NeoChatSettingsView.qml:51
#, kde-format
msgctxt "@title"

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 ""
"Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2024-11-13 00:40+0000\n"
"POT-Creation-Date: 2024-11-19 00:40+0000\n"
"PO-Revision-Date: 2023-02-25 01:00+0000\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -48,33 +48,33 @@ msgstr ""
msgid "Send message"
msgstr ""
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Send an encrypted message…"
msgstr ""
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Set an attachment caption…"
msgstr ""
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Send a message…"
msgstr ""
#: src/chatbar/ChatBar.qml:376
#: src/chatbar/ChatBar.qml:375
#, kde-format
msgctxt "@action:button"
msgid "Cancel reply"
msgstr ""
#: src/chatbar/EmojiGrid.qml:87
#: src/chatbar/EmojiGrid.qml:88
#, kde-format
msgid "No stickers"
msgstr ""
#: src/chatbar/EmojiGrid.qml:87
#: src/chatbar/EmojiGrid.qml:88
#, kde-format
msgid "No emojis"
msgstr ""
@@ -913,7 +913,7 @@ msgstr ""
msgid "Loading"
msgstr ""
#: src/login/Loading.qml:16
#: src/login/Loading.qml:17
#, kde-format
msgid ""
"Please wait while your messages are loaded from the server. This might take "
@@ -937,7 +937,7 @@ msgstr ""
msgid "Loading…"
msgstr ""
#: src/login/Login.qml:38 src/login/WelcomePage.qml:232
#: src/login/Login.qml:38 src/login/WelcomePage.qml:249
#: src/settings/ThreePIdCard.qml:183
#, kde-format
msgctxt "@action:button"
@@ -979,7 +979,7 @@ msgstr ""
msgid "Password:"
msgstr ""
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:152
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:154
#: src/settings/NetworkProxyPage.qml:122
#, kde-format
msgid "Password"
@@ -1033,47 +1033,47 @@ msgstr ""
msgid "Username unavailable"
msgstr ""
#: src/login/WelcomePage.qml:25
#: src/login/WelcomePage.qml:26
#, kde-format
msgid "Welcome"
msgstr ""
#: src/login/WelcomePage.qml:73 src/main.cpp:141
#: src/login/WelcomePage.qml:74 src/main.cpp:141
#, kde-format
msgid "NeoChat"
msgstr ""
#: src/login/WelcomePage.qml:81
#: src/login/WelcomePage.qml:82
#, kde-format
msgctxt "@title"
msgid "Continue with an existing account"
msgstr ""
#: src/login/WelcomePage.qml:115
#: src/login/WelcomePage.qml:132
#, kde-format
msgctxt "As in 'this account is still loading'"
msgid "%1 (loading)"
msgstr ""
#: src/login/WelcomePage.qml:124
#: src/login/WelcomePage.qml:141
#, kde-format
msgctxt "@action:button"
msgid "Log out of this account"
msgstr ""
#: src/login/WelcomePage.qml:153
#: src/login/WelcomePage.qml:170
#, kde-format
msgctxt "@title"
msgid "Log in or Create a New Account"
msgstr ""
#: src/login/WelcomePage.qml:240
#: src/login/WelcomePage.qml:257
#, kde-format
msgctxt "@action:button"
msgid "Go back"
msgstr ""
#: src/login/WelcomePage.qml:252
#: src/login/WelcomePage.qml:269
#, kde-format
msgctxt "@action:button"
msgid "Settings"
@@ -1857,7 +1857,7 @@ msgstr ""
msgid "Open NeoChat in this room"
msgstr ""
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:110
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:111
#: src/qml/HoverActions.qml:123
#, kde-format
msgid "Reply"
@@ -1912,58 +1912,58 @@ msgctxt "@action:button"
msgid "Show QR code"
msgstr ""
#: src/qml/AccountMenu.qml:39 src/qml/UserInfo.qml:46
#: src/qml/AccountMenu.qml:40 src/qml/UserInfo.qml:46
#, kde-format
msgid "Edit this account"
msgstr ""
#: src/qml/AccountMenu.qml:44 src/settings/AccountsPage.qml:33
#: src/qml/AccountMenu.qml:45 src/settings/AccountsPage.qml:33
#: src/settings/AccountsPage.qml:50
#, kde-format
msgid "Account editor"
msgstr ""
#: src/qml/AccountMenu.qml:48
#: src/qml/AccountMenu.qml:49
#, kde-format
msgid "Notification settings"
msgstr ""
#: src/qml/AccountMenu.qml:55 src/settings/DevicesPage.qml:17
#: src/qml/AccountMenu.qml:56 src/settings/DevicesPage.qml:17
#: src/settings/NeoChatSettingsView.qml:89
#, kde-format
msgid "Devices"
msgstr ""
#: src/qml/AccountMenu.qml:62 src/settings/NeoChatGeneralPage.qml:269
#: src/qml/AccountMenu.qml:63 src/settings/NeoChatGeneralPage.qml:269
#, kde-format
msgid "Open developer tools"
msgstr ""
#: src/qml/AccountMenu.qml:68
#: src/qml/AccountMenu.qml:69
#, kde-format
msgctxt "@title:window"
msgid "Developer Tools"
msgstr ""
#: src/qml/AccountMenu.qml:74
#: src/qml/AccountMenu.qml:75
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Secret Backup"
msgstr ""
#: src/qml/AccountMenu.qml:78
#: src/qml/AccountMenu.qml:79
#, kde-format
msgctxt "@title:window"
msgid "Open Key Backup"
msgstr ""
#: src/qml/AccountMenu.qml:82
#: src/qml/AccountMenu.qml:83
#, kde-format
msgctxt "@action:inmenu"
msgid "Verify this Device"
msgstr ""
#: src/qml/AccountMenu.qml:88 src/settings/AccountsPage.qml:87
#: src/qml/AccountMenu.qml:89 src/settings/AccountsPage.qml:88
#, kde-format
msgid "Logout"
msgstr ""
@@ -2014,7 +2014,7 @@ msgid "Attachment:"
msgstr ""
#: src/qml/AttachmentPane.qml:38 src/qml/HoverActions.qml:106
#: src/qml/ImageEditorPage.qml:21 src/qml/MessageDelegateContextMenu.qml:37
#: src/qml/ImageEditorPage.qml:20 src/qml/MessageDelegateContextMenu.qml:37
#, kde-format
msgid "Edit"
msgstr ""
@@ -2146,61 +2146,29 @@ msgctxt "@action:button"
msgid "Open"
msgstr ""
#: src/qml/ContextMenu.qml:31
#, kde-format
msgid "Remove from Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:31
#, kde-format
msgid "Add to Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:37 src/qml/ContextMenu.qml:197
#, kde-format
msgid "Reprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:37 src/qml/ContextMenu.qml:197
#, kde-format
msgid "Deprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:43 src/qml/ContextMenu.qml:204
#: src/qml/ContextMenu.qml:31 src/qml/ContextMenu.qml:209
#, kde-format
msgid "Mark as Read"
msgstr ""
#: src/qml/ContextMenu.qml:49
#: src/qml/ContextMenu.qml:40
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy user's Matrix ID to Clipboard"
msgid "Notifications"
msgstr ""
#: src/qml/ContextMenu.qml:49 src/qml/SpaceListContextMenu.qml:38
#: src/qml/SpaceListContextMenu.qml:120
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Address to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:61
#, kde-format
msgid "Notification State"
msgstr ""
#: src/qml/ContextMenu.qml:65
#: src/qml/ContextMenu.qml:44
#, kde-format
msgid "Follow Global Setting"
msgstr ""
#: src/qml/ContextMenu.qml:76 src/settings/PushNotification.qml:39
#: src/qml/ContextMenu.qml:55 src/settings/PushNotification.qml:39
#, kde-format
msgctxt "As in 'notify for all messages'"
msgid "All"
msgstr ""
#: src/qml/ContextMenu.qml:87 src/settings/PushNotification.qml:47
#: src/qml/ContextMenu.qml:66 src/settings/PushNotification.qml:47
#, kde-format
msgctxt ""
"As in 'notify when the user is mentioned or the message contains a set "
@@ -2208,34 +2176,67 @@ msgctxt ""
msgid "@Mentions and Keywords"
msgstr ""
#: src/qml/ContextMenu.qml:98 src/settings/PushNotification.qml:55
#: src/qml/ContextMenu.qml:77 src/settings/PushNotification.qml:55
#, kde-format
msgctxt "As in 'do not notify for any messages'"
msgid "Off"
msgstr ""
#: src/qml/ContextMenu.qml:111
#: src/qml/ContextMenu.qml:90
#, kde-format
msgid "Remove from Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:90
#, kde-format
msgid "Add to Favorites"
msgstr ""
#: src/qml/ContextMenu.qml:96 src/qml/ContextMenu.qml:202
#, kde-format
msgid "Reprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:96 src/qml/ContextMenu.qml:202
#, kde-format
msgid "Deprioritize"
msgstr ""
#: src/qml/ContextMenu.qml:104
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy user's Matrix ID to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:104 src/qml/SpaceListContextMenu.qml:38
#: src/qml/SpaceListContextMenu.qml:120
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Address to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:116
#, kde-format
msgctxt "@action:inmenu"
msgid "Room Settings"
msgstr ""
#: src/qml/ContextMenu.qml:121 src/qml/ContextMenu.qml:211
#: src/qml/ContextMenu.qml:126 src/qml/ContextMenu.qml:216
#, kde-format
msgid "Leave Room"
msgstr ""
#: src/qml/ContextMenu.qml:182
#: src/qml/ContextMenu.qml:187
#, kde-format
msgid "Remove from Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:182
#: src/qml/ContextMenu.qml:187
#, kde-format
msgid "Add to Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:192
#, kde-format
msgctxt "@action:button"
msgid "Room Settings"
@@ -2358,74 +2359,74 @@ msgctxt "@action:button"
msgid "Ok"
msgstr ""
#: src/qml/DelegateContextMenu.qml:83
#: src/qml/DelegateContextMenu.qml:84
#, kde-format
msgid "View Source"
msgstr ""
#: src/qml/DelegateContextMenu.qml:90 src/settings/ThreePIdCard.qml:66
#: src/qml/DelegateContextMenu.qml:91 src/settings/ThreePIdCard.qml:66
#, kde-format
msgctxt "@action:button"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:95 src/qml/DelegateContextMenu.qml:100
#: src/qml/FileDelegateContextMenu.qml:76
#: src/qml/FileDelegateContextMenu.qml:81
#: src/qml/DelegateContextMenu.qml:96 src/qml/DelegateContextMenu.qml:101
#: src/qml/FileDelegateContextMenu.qml:82
#: src/qml/FileDelegateContextMenu.qml:87
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:96 src/qml/FileDelegateContextMenu.qml:77
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:83
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:78
#: src/qml/DelegateContextMenu.qml:98 src/qml/FileDelegateContextMenu.qml:84
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove this message'"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:120 src/qml/DelegateContextMenu.qml:128
#: src/qml/DelegateContextMenu.qml:121 src/qml/DelegateContextMenu.qml:129
#, kde-format
msgctxt ""
"@action:button 'Report' as in 'Report this event to the administrators'"
msgid "Report"
msgstr ""
#: src/qml/DelegateContextMenu.qml:125
#: src/qml/DelegateContextMenu.qml:126
#, kde-format
msgctxt "@title:dialog"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:126
#: src/qml/DelegateContextMenu.qml:127
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for reporting this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:130
#: src/qml/DelegateContextMenu.qml:131
#, kde-format
msgctxt "@title"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:140
#: src/qml/DelegateContextMenu.qml:141
#, kde-format
msgctxt "@action:inmenu"
msgid "Show User"
msgstr ""
#: src/qml/DelegateContextMenu.qml:188
#: src/qml/DelegateContextMenu.qml:204
#, kde-format
msgid "Search for '%1'"
msgstr ""
#: src/qml/DelegateContextMenu.qml:210
#: src/qml/DelegateContextMenu.qml:226
#, kde-format
msgid "Configure Web Shortcuts..."
msgstr ""
@@ -2620,23 +2621,25 @@ msgctxt "@info:label"
msgid "No public rooms found"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:46
#: src/qml/FileDelegateContextMenu.qml:50
#, kde-format
msgid "Open Externally"
msgctxt "@action:inmenu"
msgid "Open Image"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:53
#: src/qml/FileDelegateContextMenu.qml:57
#, kde-format
msgid "Save As"
msgctxt "@action:inmenu"
msgid "Save Image…"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:63
#: src/qml/MessageDelegateContextMenu.qml:64
#: src/qml/FileDelegateContextMenu.qml:66
#, kde-format
msgid "Copy"
msgctxt "@action:inmenu"
msgid "Copy Image"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:71
#: src/qml/FileDelegateContextMenu.qml:77
#, kde-format
msgid "Remove"
msgstr ""
@@ -2786,55 +2789,55 @@ msgctxt "@info screenreader"
msgid "The currently selected link"
msgstr ""
#: src/qml/ImageEditorPage.qml:37
#: src/qml/ImageEditorPage.qml:36
#, kde-format
msgctxt "@action:button Undo modification"
msgid "Undo"
msgstr ""
#: src/qml/ImageEditorPage.qml:44
#: src/qml/ImageEditorPage.qml:43
#, kde-format
msgctxt "@action:button Accept image modification"
msgid "Accept"
msgstr ""
#: src/qml/ImageEditorPage.qml:52
#: src/qml/ImageEditorPage.qml:51
#, kde-format
msgid ""
"Unable to save file. Check if you have the correct permission to edit the "
"cache directory."
msgstr ""
#: src/qml/ImageEditorPage.qml:124
#: src/qml/ImageEditorPage.qml:123
#, kde-format
msgid "Cancel"
msgstr ""
#: src/qml/ImageEditorPage.qml:124 src/qml/ImageEditorPage.qml:140
#: src/qml/ImageEditorPage.qml:123 src/qml/ImageEditorPage.qml:139
#, kde-format
msgctxt "@action:button Crop an image"
msgid "Crop"
msgstr ""
#: src/qml/ImageEditorPage.qml:145
#: src/qml/ImageEditorPage.qml:144
#, kde-format
msgctxt "@action:button Rotate an image to the left"
msgid "Rotate left"
msgstr ""
#: src/qml/ImageEditorPage.qml:151
#: src/qml/ImageEditorPage.qml:150
#, kde-format
msgctxt "@action:button Rotate an image to the right"
msgid "Rotate right"
msgstr ""
#: src/qml/ImageEditorPage.qml:157
#: src/qml/ImageEditorPage.qml:156
#, kde-format
msgctxt "@action:button Mirror an image vertically"
msgid "Flip"
msgstr ""
#: src/qml/ImageEditorPage.qml:163
#: src/qml/ImageEditorPage.qml:162
#, kde-format
msgctxt "@action:button Mirror an image horizontally"
msgid "Mirror"
@@ -3062,7 +3065,7 @@ msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:47
#, kde-format
msgctxt "@action:inmenu As in 'Forward this message'"
msgid "Forward"
msgid "Forward"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:53
@@ -3071,9 +3074,16 @@ msgctxt "@title"
msgid "Forward Message"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:67
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Text"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:72
#, kde-format
msgid "Copy Link"
msgctxt "@action:inmenu"
msgid "Copy Message Link"
msgstr ""
#: src/qml/MessageSourceSheet.qml:46
@@ -3168,7 +3178,7 @@ msgctxt "@action:button"
msgid "Join"
msgstr ""
#: src/qml/RecommendedSpaceDialog.qml:61
#: src/qml/RecommendedSpaceDialog.qml:63
#, kde-format
msgctxt "@action:button"
msgid "Ignore"
@@ -3202,18 +3212,18 @@ msgstr ""
msgid "Configure room"
msgstr ""
#: src/qml/RoomDrawer.qml:111 src/qml/RoomDrawerPage.qml:45
#: src/qml/RoomDrawer.qml:114 src/qml/RoomDrawerPage.qml:45
#, kde-format
msgctxt "@action:button"
msgid "Room settings"
msgstr ""
#: src/qml/RoomDrawer.qml:160 src/qml/RoomDrawerPage.qml:85
#: src/qml/RoomDrawer.qml:163 src/qml/RoomDrawerPage.qml:85
#, kde-format
msgid "Information"
msgstr ""
#: src/qml/RoomDrawer.qml:165 src/qml/RoomDrawerPage.qml:90
#: src/qml/RoomDrawer.qml:168 src/qml/RoomDrawerPage.qml:90
#, kde-format
msgid "Media"
msgstr ""
@@ -3227,7 +3237,7 @@ msgstr ""
#: src/qml/RoomInformation.qml:42
#, kde-format
msgctxt "@action:title"
msgid "Room information"
msgid "Room Information"
msgstr ""
#: src/qml/RoomInformation.qml:70
@@ -3268,6 +3278,12 @@ msgstr ""
msgid "Show locations for this room"
msgstr ""
#: src/qml/RoomInformation.qml:136 src/qml/SpaceHomePage.qml:65
#, kde-format
msgctxt "@action:button"
msgid "Leave this space"
msgstr ""
#: src/qml/RoomInformation.qml:136
#, kde-format
msgctxt "@action:button"
@@ -3341,7 +3357,7 @@ msgctxt "@action:title"
msgid "Room Media"
msgstr ""
#: src/qml/RoomPage.qml:93
#: src/qml/RoomPage.qml:92
#, kde-format
msgid "NeoChat is offline. Please check your network connection."
msgstr ""
@@ -3583,12 +3599,6 @@ msgctxt "@button"
msgid "Invite user to space"
msgstr ""
#: src/qml/SpaceHomePage.qml:65
#, kde-format
msgctxt "@button"
msgid "Leave the space"
msgstr ""
#: src/qml/SpaceHomePage.qml:76 src/qml/SpaceListContextMenu.qml:48
#: src/qml/SpaceListContextMenu.qml:130
#, kde-format
@@ -3643,7 +3653,7 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
#: src/qml/UnlockSSSSDialog.qml:17
#: src/qml/UnlockSSSSDialog.qml:16
#, kde-format
msgctxt "@title:window"
msgid "Load your encrypted messages"
@@ -3731,129 +3741,129 @@ msgctxt "@title:menu Account details dialog"
msgid "Account Details"
msgstr ""
#: src/qml/UserDetailDialog.qml:109
#: src/qml/UserDetailDialog.qml:111
#, kde-format
msgid "Unignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:109
#: src/qml/UserDetailDialog.qml:111
#, kde-format
msgid "Ignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:122
#: src/qml/UserDetailDialog.qml:124
#, kde-format
msgid "Kick this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:126 src/qml/UserDetailDialog.qml:131
#: src/qml/UserDetailDialog.qml:128 src/qml/UserDetailDialog.qml:133
#, kde-format
msgctxt "@title:dialog"
msgid "Kick User"
msgstr ""
#: src/qml/UserDetailDialog.qml:127
#: src/qml/UserDetailDialog.qml:129
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for kicking this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:128
#: src/qml/UserDetailDialog.qml:130
#, kde-format
msgctxt "@action:button 'Kick' as in 'Kick this user from the room'"
msgid "Kick"
msgstr ""
#: src/qml/UserDetailDialog.qml:147
#: src/qml/UserDetailDialog.qml:149
#, kde-format
msgid "Invite this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:160
#: src/qml/UserDetailDialog.qml:162
#, kde-format
msgid "Ban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:165 src/qml/UserDetailDialog.qml:170
#: src/qml/UserDetailDialog.qml:167 src/qml/UserDetailDialog.qml:172
#, kde-format
msgctxt "@title:dialog"
msgid "Ban User"
msgstr ""
#: src/qml/UserDetailDialog.qml:166
#: src/qml/UserDetailDialog.qml:168
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for banning this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:167
#: src/qml/UserDetailDialog.qml:169
#, kde-format
msgctxt "@action:button 'Ban' as in 'Ban this user'"
msgid "Ban"
msgstr ""
#: src/qml/UserDetailDialog.qml:185
#: src/qml/UserDetailDialog.qml:187
#, kde-format
msgid "Unban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:198
#: src/qml/UserDetailDialog.qml:200
#, kde-format
msgid "Set user power level"
msgstr ""
#: src/qml/UserDetailDialog.qml:223
#: src/qml/UserDetailDialog.qml:225
#, kde-format
msgctxt "@action:button"
msgid "Remove recent messages by this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:228
#: src/qml/UserDetailDialog.qml:230
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:229
#: src/qml/UserDetailDialog.qml:231
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this user's recent messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:230
#: src/qml/UserDetailDialog.qml:232
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove these messages'"
msgid "Remove"
msgstr ""
#: src/qml/UserDetailDialog.qml:233
#: src/qml/UserDetailDialog.qml:235
#, kde-format
msgctxt "@title"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:247
#: src/qml/UserDetailDialog.qml:249
#, kde-format
msgctxt "%1 is the name of the user."
msgid "Chat with %1"
msgstr ""
#: src/qml/UserDetailDialog.qml:247
#: src/qml/UserDetailDialog.qml:249
#, kde-format
msgid "Invite to private chat"
msgstr ""
#: src/qml/UserDetailDialog.qml:258
#: src/qml/UserDetailDialog.qml:260
#, kde-format
msgid "Copy link"
msgstr ""
#: src/qml/UserInfo.qml:91
#: src/qml/UserInfo.qml:92
#, kde-format
msgid "Switch User"
msgstr ""
#: src/qml/UserInfo.qml:100
#: src/qml/UserInfo.qml:101
#, kde-format
msgid "Open Settings"
msgstr ""
@@ -4071,7 +4081,7 @@ msgstr ""
msgid "Working"
msgstr ""
#: src/roommanager.cpp:146
#: src/roommanager.cpp:145
#, kde-format
msgid "Malformed or empty Matrix id<br />%1 is not a correct Matrix identifier"
msgstr ""
@@ -4096,126 +4106,126 @@ msgstr ""
msgid "Edit Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:61
#: src/settings/AccountEditorPage.qml:62
#, kde-format
msgid "Upload new avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:78
#: src/settings/AccountEditorPage.qml:79
#, kde-format
msgid "Remove current avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:101
#: src/settings/AccountEditorPage.qml:102
#, kde-format
msgid "User Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:106
#: src/settings/AccountEditorPage.qml:107
#, kde-format
msgid "Display Name:"
msgstr ""
#: src/settings/AccountEditorPage.qml:112
#: src/settings/AccountEditorPage.qml:113
#, kde-format
msgid "Label:"
msgstr ""
#: src/settings/AccountEditorPage.qml:113
#: src/settings/AccountEditorPage.qml:114
#, kde-format
msgid "Work"
msgstr ""
#: src/settings/AccountEditorPage.qml:118
#: src/settings/AccountEditorPage.qml:119
#, kde-format
msgctxt "@action:button"
msgid "Show QR Code"
msgstr ""
#: src/settings/AccountEditorPage.qml:135
#: src/settings/AccountEditorPage.qml:191
#: src/settings/AccountEditorPage.qml:137
#: src/settings/AccountEditorPage.qml:193
#: src/settings/EmoticonEditorPage.qml:108 src/settings/RoomGeneralPage.qml:98
#, kde-format
msgid "Save"
msgstr ""
#: src/settings/AccountEditorPage.qml:157
#: src/settings/AccountEditorPage.qml:159
#, kde-format
msgid "Your server doesn't support changing your password"
msgstr ""
#: src/settings/AccountEditorPage.qml:164
#: src/settings/AccountEditorPage.qml:166
#, kde-format
msgid "Current Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:171
#: src/settings/AccountEditorPage.qml:173
#, kde-format
msgid "New Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:178
#: src/settings/AccountEditorPage.qml:180
#, kde-format
msgid "Confirm new Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:183
#: src/settings/AccountEditorPage.qml:185
#, kde-format
msgid "Passwords don't match"
msgstr ""
#: src/settings/AccountEditorPage.qml:198
#: src/settings/AccountEditorPage.qml:200
#, kde-format
msgid "Passwords do not match"
msgstr ""
#: src/settings/AccountEditorPage.qml:205
#: src/settings/AccountEditorPage.qml:207
#, kde-format
msgid "Email Addresses"
msgstr ""
#: src/settings/AccountEditorPage.qml:211
#: src/settings/AccountEditorPage.qml:213
#, kde-format
msgid "Phone Numbers"
msgstr ""
#: src/settings/AccountEditorPage.qml:216
#: src/settings/AccountEditorPage.qml:218
#, kde-format
msgid "Identity Server"
msgstr ""
#: src/settings/AccountEditorPage.qml:225
#: src/settings/AccountEditorPage.qml:227
#, kde-format
msgid "Server Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:229
#: src/settings/AccountEditorPage.qml:231
#, kde-format
msgid "Homeserver url"
msgstr ""
#: src/settings/AccountEditorPage.qml:250
#: src/settings/AccountEditorPage.qml:252
#, kde-format
msgctxt "@title"
msgid "Account Management"
msgstr ""
#: src/settings/AccountEditorPage.qml:255
#: src/settings/AccountEditorPage.qml:257
#, kde-format
msgid "Deactivate Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:271
#: src/settings/AccountEditorPage.qml:273
#, kde-format
msgid "Password changed successfully"
msgstr ""
#: src/settings/AccountEditorPage.qml:273
#: src/settings/AccountEditorPage.qml:275
#, kde-format
msgid "Wrong password entered"
msgstr ""
#: src/settings/AccountEditorPage.qml:275
#: src/settings/AccountEditorPage.qml:277
#, kde-format
msgid "Unknown problem while trying to change password"
msgstr ""
@@ -4226,7 +4236,7 @@ msgstr ""
msgid "Accounts"
msgstr ""
#: src/settings/AccountsPage.qml:117
#: src/settings/AccountsPage.qml:118
#, kde-format
msgid "Add Account"
msgstr ""
@@ -4456,7 +4466,7 @@ msgctxt "@title"
msgid "Stickers & Emojis"
msgstr ""
#: src/settings/ExportKeysDialog.qml:18
#: src/settings/ExportKeysDialog.qml:17
#: src/settings/NeoChatSecurityPage.qml:107
#, kde-format
msgctxt "@title"
@@ -4605,7 +4615,7 @@ msgctxt "@action:button"
msgid "Unignore this user"
msgstr ""
#: src/settings/ImportKeysDialog.qml:22 src/settings/NeoChatSecurityPage.qml:84
#: src/settings/ImportKeysDialog.qml:21 src/settings/NeoChatSecurityPage.qml:84
#, kde-format
msgctxt "@title"
msgid "Import Keys"
@@ -4769,7 +4779,7 @@ msgctxt "@action:button"
msgid "Reset all configuration values to their default"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:19
#: src/settings/NeoChatSecurityPage.qml:18
#: src/settings/NeoChatSettingsView.qml:51
#, kde-format
msgctxt "@title"

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

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: kdeorg\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2024-11-13 00:40+0000\n"
"POT-Creation-Date: 2024-11-19 00:40+0000\n"
"PO-Revision-Date: 2024-04-23 19:24\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
@@ -47,33 +47,33 @@ msgstr "发送位置"
msgid "Send message"
msgstr "发送消息"
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Send an encrypted message…"
msgstr "发送一条加密消息..."
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Set an attachment caption…"
msgstr "设置附件说明"
#: src/chatbar/ChatBar.qml:201
#: src/chatbar/ChatBar.qml:202
#, kde-format
msgid "Send a message…"
msgstr "发送一条消息..."
#: src/chatbar/ChatBar.qml:376
#: src/chatbar/ChatBar.qml:375
#, kde-format
msgctxt "@action:button"
msgid "Cancel reply"
msgstr "取消回复"
#: src/chatbar/EmojiGrid.qml:87
#: src/chatbar/EmojiGrid.qml:88
#, kde-format
msgid "No stickers"
msgstr "无贴纸"
#: src/chatbar/EmojiGrid.qml:87
#: src/chatbar/EmojiGrid.qml:88
#, kde-format
msgid "No emojis"
msgstr "无表情"
@@ -910,7 +910,7 @@ msgstr "此服务器已禁用注册。"
msgid "Loading"
msgstr "加载中"
#: src/login/Loading.qml:16
#: src/login/Loading.qml:17
#, kde-format
msgid ""
"Please wait while your messages are loaded from the server. This might take "
@@ -934,7 +934,7 @@ msgstr "Matrix ID"
msgid "Loading…"
msgstr "加载中…"
#: src/login/Login.qml:38 src/login/WelcomePage.qml:232
#: src/login/Login.qml:38 src/login/WelcomePage.qml:249
#: src/settings/ThreePIdCard.qml:183
#, kde-format
msgctxt "@action:button"
@@ -976,7 +976,7 @@ msgstr "注册"
msgid "Password:"
msgstr "密码:"
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:152
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:154
#: src/settings/NetworkProxyPage.qml:122
#, kde-format
msgid "Password"
@@ -1030,47 +1030,47 @@ msgstr "用户名:"
msgid "Username unavailable"
msgstr "用户名不可用"
#: src/login/WelcomePage.qml:25
#: src/login/WelcomePage.qml:26
#, kde-format
msgid "Welcome"
msgstr "欢迎使用"
#: src/login/WelcomePage.qml:73 src/main.cpp:141
#: src/login/WelcomePage.qml:74 src/main.cpp:141
#, kde-format
msgid "NeoChat"
msgstr "NeoChat"
#: src/login/WelcomePage.qml:81
#: src/login/WelcomePage.qml:82
#, kde-format
msgctxt "@title"
msgid "Continue with an existing account"
msgstr "使用现有账户登录"
#: src/login/WelcomePage.qml:115
#: src/login/WelcomePage.qml:132
#, kde-format
msgctxt "As in 'this account is still loading'"
msgid "%1 (loading)"
msgstr "%1 (加载中)"
#: src/login/WelcomePage.qml:124
#: src/login/WelcomePage.qml:141
#, kde-format
msgctxt "@action:button"
msgid "Log out of this account"
msgstr ""
#: src/login/WelcomePage.qml:153
#: src/login/WelcomePage.qml:170
#, kde-format
msgctxt "@title"
msgid "Log in or Create a New Account"
msgstr "登录或创建一个新账户"
#: src/login/WelcomePage.qml:240
#: src/login/WelcomePage.qml:257
#, kde-format
msgctxt "@action:button"
msgid "Go back"
msgstr "返回"
#: src/login/WelcomePage.qml:252
#: src/login/WelcomePage.qml:269
#, kde-format
msgctxt "@action:button"
msgid "Settings"
@@ -1851,7 +1851,7 @@ msgstr "%1%2"
msgid "Open NeoChat in this room"
msgstr "在此聊天室打开 NeoChat"
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:110
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:111
#: src/qml/HoverActions.qml:123
#, kde-format
msgid "Reply"
@@ -1906,58 +1906,58 @@ msgctxt "@action:button"
msgid "Show QR code"
msgstr ""
#: src/qml/AccountMenu.qml:39 src/qml/UserInfo.qml:46
#: src/qml/AccountMenu.qml:40 src/qml/UserInfo.qml:46
#, kde-format
msgid "Edit this account"
msgstr "编辑此账户"
#: src/qml/AccountMenu.qml:44 src/settings/AccountsPage.qml:33
#: src/qml/AccountMenu.qml:45 src/settings/AccountsPage.qml:33
#: src/settings/AccountsPage.qml:50
#, kde-format
msgid "Account editor"
msgstr "账户编辑器"
#: src/qml/AccountMenu.qml:48
#: src/qml/AccountMenu.qml:49
#, kde-format
msgid "Notification settings"
msgstr "通知设置"
#: src/qml/AccountMenu.qml:55 src/settings/DevicesPage.qml:17
#: src/qml/AccountMenu.qml:56 src/settings/DevicesPage.qml:17
#: src/settings/NeoChatSettingsView.qml:89
#, kde-format
msgid "Devices"
msgstr "设备"
#: src/qml/AccountMenu.qml:62 src/settings/NeoChatGeneralPage.qml:269
#: src/qml/AccountMenu.qml:63 src/settings/NeoChatGeneralPage.qml:269
#, kde-format
msgid "Open developer tools"
msgstr "打开开发者工具"
#: src/qml/AccountMenu.qml:68
#: src/qml/AccountMenu.qml:69
#, kde-format
msgctxt "@title:window"
msgid "Developer Tools"
msgstr "开发者工具"
#: src/qml/AccountMenu.qml:74
#: src/qml/AccountMenu.qml:75
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Secret Backup"
msgstr ""
#: src/qml/AccountMenu.qml:78
#: src/qml/AccountMenu.qml:79
#, kde-format
msgctxt "@title:window"
msgid "Open Key Backup"
msgstr ""
#: src/qml/AccountMenu.qml:82
#: src/qml/AccountMenu.qml:83
#, kde-format
msgctxt "@action:inmenu"
msgid "Verify this Device"
msgstr ""
#: src/qml/AccountMenu.qml:88 src/settings/AccountsPage.qml:87
#: src/qml/AccountMenu.qml:89 src/settings/AccountsPage.qml:88
#, kde-format
msgid "Logout"
msgstr "退出登录"
@@ -2008,7 +2008,7 @@ msgid "Attachment:"
msgstr "附件:"
#: src/qml/AttachmentPane.qml:38 src/qml/HoverActions.qml:106
#: src/qml/ImageEditorPage.qml:21 src/qml/MessageDelegateContextMenu.qml:37
#: src/qml/ImageEditorPage.qml:20 src/qml/MessageDelegateContextMenu.qml:37
#, kde-format
msgid "Edit"
msgstr "编辑"
@@ -2144,61 +2144,29 @@ msgctxt "@action:button"
msgid "Open"
msgstr "打开"
#: src/qml/ContextMenu.qml:31
#, kde-format
msgid "Remove from Favorites"
msgstr "从收藏夹中移除"
#: src/qml/ContextMenu.qml:31
#, kde-format
msgid "Add to Favorites"
msgstr "添加到收藏夹"
#: src/qml/ContextMenu.qml:37 src/qml/ContextMenu.qml:197
#, kde-format
msgid "Reprioritize"
msgstr "恢复优先级"
#: src/qml/ContextMenu.qml:37 src/qml/ContextMenu.qml:197
#, kde-format
msgid "Deprioritize"
msgstr "降低优先级"
#: src/qml/ContextMenu.qml:43 src/qml/ContextMenu.qml:204
#: src/qml/ContextMenu.qml:31 src/qml/ContextMenu.qml:209
#, kde-format
msgid "Mark as Read"
msgstr "标记为已读"
#: src/qml/ContextMenu.qml:49
#: src/qml/ContextMenu.qml:40
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy user's Matrix ID to Clipboard"
msgstr "将用户的 Matrix ID 复制到剪贴板"
msgid "Notifications"
msgstr "通知"
#: src/qml/ContextMenu.qml:49 src/qml/SpaceListContextMenu.qml:38
#: src/qml/SpaceListContextMenu.qml:120
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Address to Clipboard"
msgstr "将地址复制到剪贴板"
#: src/qml/ContextMenu.qml:61
#, kde-format
msgid "Notification State"
msgstr "通知状态"
#: src/qml/ContextMenu.qml:65
#: src/qml/ContextMenu.qml:44
#, kde-format
msgid "Follow Global Setting"
msgstr "使用全局设置"
#: src/qml/ContextMenu.qml:76 src/settings/PushNotification.qml:39
#: src/qml/ContextMenu.qml:55 src/settings/PushNotification.qml:39
#, kde-format
msgctxt "As in 'notify for all messages'"
msgid "All"
msgstr "全部"
#: src/qml/ContextMenu.qml:87 src/settings/PushNotification.qml:47
#: src/qml/ContextMenu.qml:66 src/settings/PushNotification.qml:47
#, kde-format
msgctxt ""
"As in 'notify when the user is mentioned or the message contains a set "
@@ -2206,34 +2174,67 @@ msgctxt ""
msgid "@Mentions and Keywords"
msgstr "@提及 和关键词"
#: src/qml/ContextMenu.qml:98 src/settings/PushNotification.qml:55
#: src/qml/ContextMenu.qml:77 src/settings/PushNotification.qml:55
#, kde-format
msgctxt "As in 'do not notify for any messages'"
msgid "Off"
msgstr "关闭"
#: src/qml/ContextMenu.qml:111
#: src/qml/ContextMenu.qml:90
#, kde-format
msgid "Remove from Favorites"
msgstr "从收藏夹中移除"
#: src/qml/ContextMenu.qml:90
#, kde-format
msgid "Add to Favorites"
msgstr "添加到收藏夹"
#: src/qml/ContextMenu.qml:96 src/qml/ContextMenu.qml:202
#, kde-format
msgid "Reprioritize"
msgstr "恢复优先级"
#: src/qml/ContextMenu.qml:96 src/qml/ContextMenu.qml:202
#, kde-format
msgid "Deprioritize"
msgstr "降低优先级"
#: src/qml/ContextMenu.qml:104
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy user's Matrix ID to Clipboard"
msgstr "将用户的 Matrix ID 复制到剪贴板"
#: src/qml/ContextMenu.qml:104 src/qml/SpaceListContextMenu.qml:38
#: src/qml/SpaceListContextMenu.qml:120
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Address to Clipboard"
msgstr "将地址复制到剪贴板"
#: src/qml/ContextMenu.qml:116
#, kde-format
msgctxt "@action:inmenu"
msgid "Room Settings"
msgstr "聊天室设置"
#: src/qml/ContextMenu.qml:121 src/qml/ContextMenu.qml:211
#: src/qml/ContextMenu.qml:126 src/qml/ContextMenu.qml:216
#, kde-format
msgid "Leave Room"
msgstr "离开聊天室"
#: src/qml/ContextMenu.qml:182
#: src/qml/ContextMenu.qml:187
#, kde-format
msgid "Remove from Favourites"
msgstr "移出收藏夹"
#: src/qml/ContextMenu.qml:182
#: src/qml/ContextMenu.qml:187
#, kde-format
msgid "Add to Favourites"
msgstr "移入收藏夹"
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:192
#, kde-format
msgctxt "@action:button"
msgid "Room Settings"
@@ -2356,74 +2357,74 @@ msgctxt "@action:button"
msgid "Ok"
msgstr "确定"
#: src/qml/DelegateContextMenu.qml:83
#: src/qml/DelegateContextMenu.qml:84
#, kde-format
msgid "View Source"
msgstr "查看源码"
#: src/qml/DelegateContextMenu.qml:90 src/settings/ThreePIdCard.qml:66
#: src/qml/DelegateContextMenu.qml:91 src/settings/ThreePIdCard.qml:66
#, kde-format
msgctxt "@action:button"
msgid "Remove"
msgstr "移除"
#: src/qml/DelegateContextMenu.qml:95 src/qml/DelegateContextMenu.qml:100
#: src/qml/FileDelegateContextMenu.qml:76
#: src/qml/FileDelegateContextMenu.qml:81
#: src/qml/DelegateContextMenu.qml:96 src/qml/DelegateContextMenu.qml:101
#: src/qml/FileDelegateContextMenu.qml:82
#: src/qml/FileDelegateContextMenu.qml:87
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Message"
msgstr "移除消息"
#: src/qml/DelegateContextMenu.qml:96 src/qml/FileDelegateContextMenu.qml:77
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:83
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this message"
msgstr "移除此消息的原因"
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:78
#: src/qml/DelegateContextMenu.qml:98 src/qml/FileDelegateContextMenu.qml:84
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove this message'"
msgid "Remove"
msgstr "移除"
#: src/qml/DelegateContextMenu.qml:120 src/qml/DelegateContextMenu.qml:128
#: src/qml/DelegateContextMenu.qml:121 src/qml/DelegateContextMenu.qml:129
#, kde-format
msgctxt ""
"@action:button 'Report' as in 'Report this event to the administrators'"
msgid "Report"
msgstr "举报"
#: src/qml/DelegateContextMenu.qml:125
#: src/qml/DelegateContextMenu.qml:126
#, kde-format
msgctxt "@title:dialog"
msgid "Report Message"
msgstr "举报消息"
#: src/qml/DelegateContextMenu.qml:126
#: src/qml/DelegateContextMenu.qml:127
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for reporting this message"
msgstr "举报此消息的原因"
#: src/qml/DelegateContextMenu.qml:130
#: src/qml/DelegateContextMenu.qml:131
#, kde-format
msgctxt "@title"
msgid "Report Message"
msgstr "举报消息"
#: src/qml/DelegateContextMenu.qml:140
#: src/qml/DelegateContextMenu.qml:141
#, kde-format
msgctxt "@action:inmenu"
msgid "Show User"
msgstr "查看用户"
#: src/qml/DelegateContextMenu.qml:188
#: src/qml/DelegateContextMenu.qml:204
#, kde-format
msgid "Search for '%1'"
msgstr "搜索 '%1'"
#: src/qml/DelegateContextMenu.qml:210
#: src/qml/DelegateContextMenu.qml:226
#, kde-format
msgid "Configure Web Shortcuts..."
msgstr "配置网页快捷键..."
@@ -2618,23 +2619,25 @@ msgctxt "@info:label"
msgid "No public rooms found"
msgstr "未找到公共聊天室"
#: src/qml/FileDelegateContextMenu.qml:46
#: src/qml/FileDelegateContextMenu.qml:50
#, kde-format
msgid "Open Externally"
msgstr "在外部打开"
msgctxt "@action:inmenu"
msgid "Open Image"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:53
#: src/qml/FileDelegateContextMenu.qml:57
#, kde-format
msgid "Save As"
msgstr "另存为"
msgctxt "@action:inmenu"
msgid "Save Image…"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:63
#: src/qml/MessageDelegateContextMenu.qml:64
#: src/qml/FileDelegateContextMenu.qml:66
#, kde-format
msgid "Copy"
msgstr "复制"
msgctxt "@action:inmenu"
msgid "Copy Image"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:71
#: src/qml/FileDelegateContextMenu.qml:77
#, kde-format
msgid "Remove"
msgstr "移除"
@@ -2784,55 +2787,55 @@ msgctxt "@info screenreader"
msgid "The currently selected link"
msgstr "当前选择的链接"
#: src/qml/ImageEditorPage.qml:37
#: src/qml/ImageEditorPage.qml:36
#, kde-format
msgctxt "@action:button Undo modification"
msgid "Undo"
msgstr "撤销"
#: src/qml/ImageEditorPage.qml:44
#: src/qml/ImageEditorPage.qml:43
#, kde-format
msgctxt "@action:button Accept image modification"
msgid "Accept"
msgstr "接受"
#: src/qml/ImageEditorPage.qml:52
#: src/qml/ImageEditorPage.qml:51
#, kde-format
msgid ""
"Unable to save file. Check if you have the correct permission to edit the "
"cache directory."
msgstr "无法保存文件。请检查您是否有编辑缓存目录的正确权限。"
#: src/qml/ImageEditorPage.qml:124
#: src/qml/ImageEditorPage.qml:123
#, kde-format
msgid "Cancel"
msgstr "取消"
#: src/qml/ImageEditorPage.qml:124 src/qml/ImageEditorPage.qml:140
#: src/qml/ImageEditorPage.qml:123 src/qml/ImageEditorPage.qml:139
#, kde-format
msgctxt "@action:button Crop an image"
msgid "Crop"
msgstr "裁剪"
#: src/qml/ImageEditorPage.qml:145
#: src/qml/ImageEditorPage.qml:144
#, kde-format
msgctxt "@action:button Rotate an image to the left"
msgid "Rotate left"
msgstr "旋转 (向左)"
#: src/qml/ImageEditorPage.qml:151
#: src/qml/ImageEditorPage.qml:150
#, kde-format
msgctxt "@action:button Rotate an image to the right"
msgid "Rotate right"
msgstr "旋转 (向右)"
#: src/qml/ImageEditorPage.qml:157
#: src/qml/ImageEditorPage.qml:156
#, kde-format
msgctxt "@action:button Mirror an image vertically"
msgid "Flip"
msgstr "翻转"
#: src/qml/ImageEditorPage.qml:163
#: src/qml/ImageEditorPage.qml:162
#, kde-format
msgctxt "@action:button Mirror an image horizontally"
msgid "Mirror"
@@ -3060,8 +3063,8 @@ msgstr "输入内容不是有效的用户 ID"
#: src/qml/MessageDelegateContextMenu.qml:47
#, kde-format
msgctxt "@action:inmenu As in 'Forward this message'"
msgid "Forward"
msgstr "转发"
msgid "Forward"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:53
#, kde-format
@@ -3069,10 +3072,17 @@ msgctxt "@title"
msgid "Forward Message"
msgstr "转发消息"
#: src/qml/MessageDelegateContextMenu.qml:67
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Text"
msgstr ""
#: src/qml/MessageDelegateContextMenu.qml:72
#, kde-format
msgid "Copy Link"
msgstr "复制链接"
msgctxt "@action:inmenu"
msgid "Copy Message Link"
msgstr ""
#: src/qml/MessageSourceSheet.qml:46
#, kde-format
@@ -3166,7 +3176,7 @@ msgctxt "@action:button"
msgid "Join"
msgstr "加入"
#: src/qml/RecommendedSpaceDialog.qml:61
#: src/qml/RecommendedSpaceDialog.qml:63
#, kde-format
msgctxt "@action:button"
msgid "Ignore"
@@ -3200,18 +3210,18 @@ msgstr "已静音的聊天室"
msgid "Configure room"
msgstr "配置聊天室"
#: src/qml/RoomDrawer.qml:111 src/qml/RoomDrawerPage.qml:45
#: src/qml/RoomDrawer.qml:114 src/qml/RoomDrawerPage.qml:45
#, kde-format
msgctxt "@action:button"
msgid "Room settings"
msgstr "聊天室设置"
#: src/qml/RoomDrawer.qml:160 src/qml/RoomDrawerPage.qml:85
#: src/qml/RoomDrawer.qml:163 src/qml/RoomDrawerPage.qml:85
#, kde-format
msgid "Information"
msgstr "信息"
#: src/qml/RoomDrawer.qml:165 src/qml/RoomDrawerPage.qml:90
#: src/qml/RoomDrawer.qml:168 src/qml/RoomDrawerPage.qml:90
#, kde-format
msgid "Media"
msgstr "媒体"
@@ -3225,7 +3235,7 @@ msgstr "空间成员"
#: src/qml/RoomInformation.qml:42
#, kde-format
msgctxt "@action:title"
msgid "Room information"
msgid "Room Information"
msgstr "聊天室信息"
#: src/qml/RoomInformation.qml:70
@@ -3266,6 +3276,12 @@ msgstr ""
msgid "Show locations for this room"
msgstr "显示此聊天室的位置"
#: src/qml/RoomInformation.qml:136 src/qml/SpaceHomePage.qml:65
#, kde-format
msgctxt "@action:button"
msgid "Leave this space"
msgstr ""
#: src/qml/RoomInformation.qml:136
#, kde-format
msgctxt "@action:button"
@@ -3336,7 +3352,7 @@ msgctxt "@action:title"
msgid "Room Media"
msgstr "聊天室媒体"
#: src/qml/RoomPage.qml:93
#: src/qml/RoomPage.qml:92
#, kde-format
msgid "NeoChat is offline. Please check your network connection."
msgstr "NeoChat 处于离线状态。请检查您的网络连接。"
@@ -3572,12 +3588,6 @@ msgctxt "@button"
msgid "Invite user to space"
msgstr "邀请用户加入空间"
#: src/qml/SpaceHomePage.qml:65
#, kde-format
msgctxt "@button"
msgid "Leave the space"
msgstr "离开空间"
#: src/qml/SpaceHomePage.qml:76 src/qml/SpaceListContextMenu.qml:48
#: src/qml/SpaceListContextMenu.qml:130
#, kde-format
@@ -3630,7 +3640,7 @@ msgid "%2 is typing"
msgid_plural "%2 are typing"
msgstr[0] "%2 正在输入"
#: src/qml/UnlockSSSSDialog.qml:17
#: src/qml/UnlockSSSSDialog.qml:16
#, kde-format
msgctxt "@title:window"
msgid "Load your encrypted messages"
@@ -3720,129 +3730,129 @@ msgctxt "@title:menu Account details dialog"
msgid "Account Details"
msgstr "账户详情"
#: src/qml/UserDetailDialog.qml:109
#: src/qml/UserDetailDialog.qml:111
#, kde-format
msgid "Unignore this user"
msgstr "取消忽略此用户"
#: src/qml/UserDetailDialog.qml:109
#: src/qml/UserDetailDialog.qml:111
#, kde-format
msgid "Ignore this user"
msgstr "忽略此用户"
#: src/qml/UserDetailDialog.qml:122
#: src/qml/UserDetailDialog.qml:124
#, kde-format
msgid "Kick this user"
msgstr "踢出此用户"
#: src/qml/UserDetailDialog.qml:126 src/qml/UserDetailDialog.qml:131
#: src/qml/UserDetailDialog.qml:128 src/qml/UserDetailDialog.qml:133
#, kde-format
msgctxt "@title:dialog"
msgid "Kick User"
msgstr ""
#: src/qml/UserDetailDialog.qml:127
#: src/qml/UserDetailDialog.qml:129
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for kicking this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:128
#: src/qml/UserDetailDialog.qml:130
#, kde-format
msgctxt "@action:button 'Kick' as in 'Kick this user from the room'"
msgid "Kick"
msgstr ""
#: src/qml/UserDetailDialog.qml:147
#: src/qml/UserDetailDialog.qml:149
#, kde-format
msgid "Invite this user"
msgstr "邀请此用户"
#: src/qml/UserDetailDialog.qml:160
#: src/qml/UserDetailDialog.qml:162
#, kde-format
msgid "Ban this user"
msgstr "封禁此用户"
#: src/qml/UserDetailDialog.qml:165 src/qml/UserDetailDialog.qml:170
#: src/qml/UserDetailDialog.qml:167 src/qml/UserDetailDialog.qml:172
#, kde-format
msgctxt "@title:dialog"
msgid "Ban User"
msgstr "封禁用户"
#: src/qml/UserDetailDialog.qml:166
#: src/qml/UserDetailDialog.qml:168
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for banning this user"
msgstr "封禁此用户的原因"
#: src/qml/UserDetailDialog.qml:167
#: src/qml/UserDetailDialog.qml:169
#, kde-format
msgctxt "@action:button 'Ban' as in 'Ban this user'"
msgid "Ban"
msgstr "封禁"
#: src/qml/UserDetailDialog.qml:185
#: src/qml/UserDetailDialog.qml:187
#, kde-format
msgid "Unban this user"
msgstr "解封此用户"
#: src/qml/UserDetailDialog.qml:198
#: src/qml/UserDetailDialog.qml:200
#, kde-format
msgid "Set user power level"
msgstr "设置用户权力等级"
#: src/qml/UserDetailDialog.qml:223
#: src/qml/UserDetailDialog.qml:225
#, kde-format
msgctxt "@action:button"
msgid "Remove recent messages by this user"
msgstr "移除此用户最近的消息"
#: src/qml/UserDetailDialog.qml:228
#: src/qml/UserDetailDialog.qml:230
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Messages"
msgstr "移除消息"
#: src/qml/UserDetailDialog.qml:229
#: src/qml/UserDetailDialog.qml:231
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this user's recent messages"
msgstr "移除此用户最近消息的原因"
#: src/qml/UserDetailDialog.qml:230
#: src/qml/UserDetailDialog.qml:232
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove these messages'"
msgid "Remove"
msgstr "移除"
#: src/qml/UserDetailDialog.qml:233
#: src/qml/UserDetailDialog.qml:235
#, kde-format
msgctxt "@title"
msgid "Remove Messages"
msgstr "移除消息"
#: src/qml/UserDetailDialog.qml:247
#: src/qml/UserDetailDialog.qml:249
#, kde-format
msgctxt "%1 is the name of the user."
msgid "Chat with %1"
msgstr "与 %1 聊天"
#: src/qml/UserDetailDialog.qml:247
#: src/qml/UserDetailDialog.qml:249
#, kde-format
msgid "Invite to private chat"
msgstr "邀请到私人聊天"
#: src/qml/UserDetailDialog.qml:258
#: src/qml/UserDetailDialog.qml:260
#, kde-format
msgid "Copy link"
msgstr "复制链接"
#: src/qml/UserInfo.qml:91
#: src/qml/UserInfo.qml:92
#, kde-format
msgid "Switch User"
msgstr "切换用户"
#: src/qml/UserInfo.qml:100
#: src/qml/UserInfo.qml:101
#, kde-format
msgid "Open Settings"
msgstr "打开设置"
@@ -4063,7 +4073,7 @@ msgstr "继续"
msgid "Working"
msgstr "正在处理"
#: src/roommanager.cpp:146
#: src/roommanager.cpp:145
#, kde-format
msgid "Malformed or empty Matrix id<br />%1 is not a correct Matrix identifier"
msgstr ""
@@ -4088,126 +4098,126 @@ msgstr ""
msgid "Edit Account"
msgstr "编辑账户"
#: src/settings/AccountEditorPage.qml:61
#: src/settings/AccountEditorPage.qml:62
#, kde-format
msgid "Upload new avatar"
msgstr "上传新头像"
#: src/settings/AccountEditorPage.qml:78
#: src/settings/AccountEditorPage.qml:79
#, kde-format
msgid "Remove current avatar"
msgstr "移除当前头像"
#: src/settings/AccountEditorPage.qml:101
#: src/settings/AccountEditorPage.qml:102
#, kde-format
msgid "User Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:106
#: src/settings/AccountEditorPage.qml:107
#, kde-format
msgid "Display Name:"
msgstr ""
#: src/settings/AccountEditorPage.qml:112
#: src/settings/AccountEditorPage.qml:113
#, kde-format
msgid "Label:"
msgstr "标签:"
#: src/settings/AccountEditorPage.qml:113
#: src/settings/AccountEditorPage.qml:114
#, kde-format
msgid "Work"
msgstr ""
#: src/settings/AccountEditorPage.qml:118
#: src/settings/AccountEditorPage.qml:119
#, kde-format
msgctxt "@action:button"
msgid "Show QR Code"
msgstr ""
#: src/settings/AccountEditorPage.qml:135
#: src/settings/AccountEditorPage.qml:191
#: src/settings/AccountEditorPage.qml:137
#: src/settings/AccountEditorPage.qml:193
#: src/settings/EmoticonEditorPage.qml:108 src/settings/RoomGeneralPage.qml:98
#, kde-format
msgid "Save"
msgstr "保存"
#: src/settings/AccountEditorPage.qml:157
#: src/settings/AccountEditorPage.qml:159
#, kde-format
msgid "Your server doesn't support changing your password"
msgstr "您的服务器不支持更改您的密码"
#: src/settings/AccountEditorPage.qml:164
#: src/settings/AccountEditorPage.qml:166
#, kde-format
msgid "Current Password:"
msgstr "当前密码:"
#: src/settings/AccountEditorPage.qml:171
#: src/settings/AccountEditorPage.qml:173
#, kde-format
msgid "New Password:"
msgstr "新密码:"
#: src/settings/AccountEditorPage.qml:178
#: src/settings/AccountEditorPage.qml:180
#, kde-format
msgid "Confirm new Password:"
msgstr "确认新密码:"
#: src/settings/AccountEditorPage.qml:183
#: src/settings/AccountEditorPage.qml:185
#, kde-format
msgid "Passwords don't match"
msgstr "密码不匹配"
#: src/settings/AccountEditorPage.qml:198
#: src/settings/AccountEditorPage.qml:200
#, kde-format
msgid "Passwords do not match"
msgstr "密码不匹配"
#: src/settings/AccountEditorPage.qml:205
#: src/settings/AccountEditorPage.qml:207
#, kde-format
msgid "Email Addresses"
msgstr "电子邮件地址"
#: src/settings/AccountEditorPage.qml:211
#: src/settings/AccountEditorPage.qml:213
#, kde-format
msgid "Phone Numbers"
msgstr "电话号码"
#: src/settings/AccountEditorPage.qml:216
#: src/settings/AccountEditorPage.qml:218
#, kde-format
msgid "Identity Server"
msgstr ""
#: src/settings/AccountEditorPage.qml:225
#: src/settings/AccountEditorPage.qml:227
#, kde-format
msgid "Server Information"
msgstr "服务器信息"
#: src/settings/AccountEditorPage.qml:229
#: src/settings/AccountEditorPage.qml:231
#, kde-format
msgid "Homeserver url"
msgstr "主服务器 URL"
#: src/settings/AccountEditorPage.qml:250
#: src/settings/AccountEditorPage.qml:252
#, kde-format
msgctxt "@title"
msgid "Account Management"
msgstr "账户管理"
#: src/settings/AccountEditorPage.qml:255
#: src/settings/AccountEditorPage.qml:257
#, kde-format
msgid "Deactivate Account"
msgstr "停用账户"
#: src/settings/AccountEditorPage.qml:271
#: src/settings/AccountEditorPage.qml:273
#, kde-format
msgid "Password changed successfully"
msgstr "密码修改成功"
#: src/settings/AccountEditorPage.qml:273
#: src/settings/AccountEditorPage.qml:275
#, kde-format
msgid "Wrong password entered"
msgstr "输入的密码错误"
#: src/settings/AccountEditorPage.qml:275
#: src/settings/AccountEditorPage.qml:277
#, kde-format
msgid "Unknown problem while trying to change password"
msgstr "尝试更改密码时出现未知问题"
@@ -4218,7 +4228,7 @@ msgstr "尝试更改密码时出现未知问题"
msgid "Accounts"
msgstr "账户"
#: src/settings/AccountsPage.qml:117
#: src/settings/AccountsPage.qml:118
#, kde-format
msgid "Add Account"
msgstr "添加账户"
@@ -4448,7 +4458,7 @@ msgctxt "@title"
msgid "Stickers & Emojis"
msgstr "贴纸和表情"
#: src/settings/ExportKeysDialog.qml:18
#: src/settings/ExportKeysDialog.qml:17
#: src/settings/NeoChatSecurityPage.qml:107
#, kde-format
msgctxt "@title"
@@ -4597,7 +4607,7 @@ msgctxt "@action:button"
msgid "Unignore this user"
msgstr "取消忽略此用户"
#: src/settings/ImportKeysDialog.qml:22 src/settings/NeoChatSecurityPage.qml:84
#: src/settings/ImportKeysDialog.qml:21 src/settings/NeoChatSecurityPage.qml:84
#, kde-format
msgctxt "@title"
msgid "Import Keys"
@@ -4761,7 +4771,7 @@ msgctxt "@action:button"
msgid "Reset all configuration values to their default"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:19
#: src/settings/NeoChatSecurityPage.qml:18
#: src/settings/NeoChatSettingsView.qml:51
#, kde-format
msgctxt "@title"

File diff suppressed because it is too large Load Diff

View File

@@ -10,12 +10,6 @@ endif()
add_library(neochat STATIC
controller.cpp
controller.h
models/emojimodel.cpp
models/emojimodel.h
emojitones.cpp
emojitones.h
models/customemojimodel.cpp
models/customemojimodel.h
clipboard.cpp
clipboard.h
models/messageeventmodel.cpp
@@ -26,8 +20,6 @@ add_library(neochat STATIC
models/roomlistmodel.h
models/sortfilterspacelistmodel.cpp
models/sortfilterspacelistmodel.h
models/accountemoticonmodel.cpp
models/accountemoticonmodel.h
spacehierarchycache.cpp
spacehierarchycache.h
roommanager.cpp
@@ -50,8 +42,6 @@ add_library(neochat STATIC
models/userdirectorylistmodel.h
models/pushrulemodel.cpp
models/pushrulemodel.h
models/emoticonfiltermodel.cpp
models/emoticonfiltermodel.h
notificationsmanager.cpp
notificationsmanager.h
models/sortfilterroomlistmodel.cpp
@@ -101,10 +91,6 @@ add_library(neochat STATIC
texthandler.h
logger.cpp
logger.h
models/stickermodel.cpp
models/stickermodel.h
models/imagepacksmodel.cpp
models/imagepacksmodel.h
events/imagepackevent.cpp
events/imagepackevent.h
events/joinrulesevent.cpp
@@ -282,6 +268,9 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/ConfirmLeaveDialog.qml
qml/CodeMaximizeComponent.qml
qml/EditStateDialog.qml
qml/EmojiPickerTypeHeader.qml
qml/EmojiPickerPackHeader.qml
qml/QuickReaction.qml
qml/ConsentDialog.qml
qml/AskDirectChatConfirmation.qml
qml/HoverLinkIndicator.qml

View File

@@ -176,13 +176,14 @@ QQC2.Control {
RowLayout {
QQC2.ScrollView {
id: chatBarScrollView
Layout.topMargin: Kirigami.Units.smallSpacing
Layout.bottomMargin: Kirigami.Units.smallSpacing
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.fillWidth: true
Layout.maximumHeight: Kirigami.Units.gridUnit * 8
Layout.topMargin: Kirigami.Units.smallSpacing
Layout.bottomMargin: Kirigami.Units.smallSpacing
Layout.minimumHeight: Kirigami.Units.gridUnit * 2
Layout.minimumHeight: Kirigami.Units.gridUnit * 3
// HACK: This is to stop the ScrollBar flickering on and off as the height is increased
QQC2.ScrollBar.vertical.policy: chatBarHeightAnimation.running && implicitHeight <= height ? QQC2.ScrollBar.AlwaysOff : QQC2.ScrollBar.AsNeeded
@@ -320,12 +321,11 @@ QQC2.Control {
id: actionsRow
spacing: 0
Layout.alignment: Qt.AlignBottom
Layout.bottomMargin: Kirigami.Units.smallSpacing * 1.5
Layout.bottomMargin: Kirigami.Units.smallSpacing * 4
Repeater {
model: root.actions
delegate: QQC2.ToolButton {
Layout.alignment: Qt.AlignVCenter
icon.name: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
onClicked: modelData.trigger()
@@ -342,7 +342,6 @@ QQC2.Control {
}
}
}
DelegateSizeHelper {
id: chatBarSizeHelper
startBreakpoint: Kirigami.Units.gridUnit * 46
@@ -520,7 +519,6 @@ QQC2.Control {
y: -implicitHeight
modal: false
includeCustom: true
closeOnChosen: false
currentRoom: root.currentRoom

View File

@@ -5,56 +5,30 @@ import QtQuick
import QtQuick.Controls as QQC2
import org.kde.kirigami as Kirigami
QQC2.ItemDelegate {
QQC2.Button {
id: root
property string name
property string emoji
required property string toolTip
property bool showTones: false
property bool isImage: false
QQC2.ToolTip.text: root.name
QQC2.ToolTip.visible: hovered && root.name !== ""
QQC2.ToolTip.text: toolTip
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
leftInset: Kirigami.Units.smallSpacing
topInset: Kirigami.Units.smallSpacing
rightInset: Kirigami.Units.smallSpacing
bottomInset: Kirigami.Units.smallSpacing
contentItem: Item {
Kirigami.Heading {
anchors.fill: parent
visible: !root.emoji.startsWith("mxc") && !root.isImage
text: root.emoji
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.family: "emoji"
flat: true
Kirigami.Icon {
width: Kirigami.Units.gridUnit * 0.5
height: Kirigami.Units.gridUnit * 0.5
source: "arrow-down-symbolic"
anchors.bottom: parent.bottom
anchors.right: parent.right
visible: root.showTones
}
}
Image {
anchors.fill: parent
visible: root.emoji.startsWith("mxc") || root.isImage
source: visible ? root.emoji : ""
}
}
contentItem: Kirigami.Heading {
text: root.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
background: Rectangle {
color: root.checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
radius: Kirigami.Units.cornerRadius
Rectangle {
radius: Kirigami.Units.cornerRadius
anchors.fill: parent
color: Kirigami.Theme.highlightColor
opacity: root.hovered && !root.pressed ? 0.2 : 0
Kirigami.Icon {
width: Kirigami.Units.gridUnit * 0.5
height: Kirigami.Units.gridUnit * 0.5
source: "arrow-down-symbolic"
anchors.bottom: parent.bottom
anchors.right: parent.right
visible: root.showTones
}
}
}

View File

@@ -16,9 +16,7 @@ QQC2.Popup {
*/
property NeoChatRoom currentRoom
property bool includeCustom: false
property bool closeOnChosen: true
property bool showQuickReaction: false
signal chosen(string emoji)
@@ -64,15 +62,15 @@ QQC2.Popup {
padding: 2
implicitHeight: Kirigami.Units.gridUnit * 20 + 2 * padding
width: Math.min(contentItem.categoryIconSize * 11 + 2 * padding, applicationWindow().width)
width: Math.min(contentItem.implicitWidth + 2 * padding, applicationWindow().width)
contentItem: EmojiPicker {
id: emojiPicker
height: 400
currentRoom: root.currentRoom
includeCustom: root.includeCustom
showQuickReaction: root.showQuickReaction
onChosen: emoji => {
root.chosen(emoji);
ImageContentManager.emojiUsed(emoji)
if (root.closeOnChosen) {
root.close();
}

View File

@@ -1,20 +1,17 @@
// SPDX-FileCopyrightText: 2022 Tobias Fella
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
import QtQuick.Controls as QQC2
import org.kde.kirigami as Kirigami
import org.kde.neochat
import org.kde.textaddons.emoticons
QQC2.ScrollView {
id: root
property alias model: emojis.model
property alias count: emojis.count
required property int targetIconSize
readonly property int emojisPerRow: emojis.width / targetIconSize
required property bool withCustom
readonly property var searchCategory: withCustom ? EmojiModel.Search : EmojiModel.SearchNoCustom
readonly property int emojisPerRow: emojis.width / Kirigami.Units.iconSizes.large
required property QtObject header
property bool stickers: false
@@ -25,6 +22,8 @@ QQC2.ScrollView {
emojis.forceActiveFocus();
}
width: Kirigami.Units.gridUnit * 24
GridView {
id: emojis
@@ -41,7 +40,9 @@ QQC2.ScrollView {
onModelChanged: currentIndex = -1
cellWidth: emojis.width / root.emojisPerRow
cellHeight: root.targetIconSize
cellHeight: Kirigami.Units.iconSizes.large
model: EmojiModelManager.emojiModel
KeyNavigation.up: root.header
@@ -49,49 +50,49 @@ QQC2.ScrollView {
delegate: EmojiDelegate {
id: emojiDelegate
checked: emojis.currentIndex === model.index
emoji: !!modelData ? modelData.unicode : model.url
name: !!modelData ? modelData.shortName : model.body
required property string unicode
required property string identifier
required property int index
text: emojiDelegate.unicode
toolTip: emojiDelegate.identifier
checked: emojis.currentIndex === emojiDelegate.index
width: emojis.cellWidth
height: emojis.cellHeight
isImage: root.stickers
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
onClicked: {
if (root.stickers) {
root.stickerChosen(model.index);
}
root.chosen(modelData.isCustom ? modelData.shortName : modelData.unicode);
EmojiModel.emojiUsed(modelData);
}
Keys.onSpacePressed: pressAndHold()
onPressAndHold: {
if (EmojiModel.tones(modelData.shortName).length === 0) {
return;
}
let tones = tonesPopupComponent.createObject(emojiDelegate, {
shortName: modelData.shortName,
unicode: modelData.unicode,
categoryIconSize: root.targetIconSize
});
tones.open();
tones.forceActiveFocus();
}
showTones: !!modelData && EmojiModel.tones(modelData.shortName).length > 0
// onClicked: {
// if (root.stickers) {
// root.stickerChosen(model.index);
// }
// root.chosen(modelData.isCustom ? modelData.shortName : modelData.unicode);
// EmojiModel.emojiUsed(modelData);
// }
// Keys.onSpacePressed: pressAndHold()
// onPressAndHold: {
// if (!showTones) {
// return;
// }
// let tones = Qt.createComponent("org.kde.neochat", "EmojiTonesPicker").createObject(emojiDelegate, {
// shortName: modelData.shortName,
// unicode: modelData.unicode,
// categoryIconSize: root.targetIconSize,
// onChosen: root.chosen(emoji => root.chosen(emoji))
// });
// tones.open();
// tones.forceActiveFocus();
// }
// showTones: model.hasTones
}
Kirigami.PlaceholderMessage {
anchors.centerIn: parent
text: root.stickers ? i18n("No stickers") : i18n("No emojis")
icon.name: root.stickers ? "stickers" : "preferences-desktop-emoticons"
text: root.stickers ? i18nc("@info", "No stickers") : i18nc("@info", "No emojis")
visible: emojis.count === 0
}
}
Component {
id: tonesPopupComponent
EmojiTonesPicker {
onChosen: root.chosen(emoji)
}
}
}

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
// SPDX-FileCopyrightText: 2022-2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
@@ -6,6 +6,7 @@ import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.neochat
import org.kde.textaddons.emoticons
ColumnLayout {
id: root
@@ -13,86 +14,29 @@ ColumnLayout {
/**
* @brief The current room that user is viewing.
*/
property NeoChatRoom currentRoom
property bool includeCustom: false
property bool showQuickReaction: false
readonly property var currentEmojiModel: {
if (includeCustom) {
EmojiModel.categoriesWithCustom;
} else {
EmojiModel.categories;
}
}
readonly property int categoryIconSize: Math.round(Kirigami.Units.gridUnit * 2.5)
readonly property var currentCategory: currentEmojiModel[categories.currentIndex].category
readonly property alias categoryCount: categories.count
property int selectedType: 0
required property NeoChatRoom currentRoom
signal chosen(string emoji)
spacing: 0
onActiveFocusChanged: if (activeFocus) {
searchField.forceActiveFocus();
}
spacing: 0
EmojiPickerTypeHeader {
id: emoticonPickerTypeHeader
Kirigami.NavigationTabBar {
id: types
Layout.fillWidth: true
Kirigami.Theme.colorSet: Kirigami.Theme.View
background: null
actions: [
Kirigami.Action {
id: emojis
icon.name: "smiley"
text: i18n("Emojis")
checked: true
onTriggered: root.selectedType = 0
},
Kirigami.Action {
id: stickers
icon.name: "stickers"
text: i18n("Stickers")
onTriggered: root.selectedType = 1
}
]
onSelectedTypeChanged: emoticonPickerCategoryHeader.currentIndex = 0
}
QQC2.ScrollView {
EmojiPickerPackHeader {
id: emoticonPickerCategoryHeader
Layout.fillWidth: true
Layout.preferredHeight: root.categoryIconSize + QQC2.ScrollBar.horizontal.height
QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
ListView {
id: categories
clip: true
focus: true
orientation: ListView.Horizontal
Keys.onReturnPressed: if (emojiGrid.count > 0) {
emojiGrid.focus = true;
}
Keys.onEnterPressed: if (emojiGrid.count > 0) {
emojiGrid.focus = true;
}
KeyNavigation.down: emojiGrid.count > 0 ? emojiGrid : categories
KeyNavigation.tab: emojiGrid.count > 0 ? emojiGrid : categories
keyNavigationEnabled: true
keyNavigationWraps: true
Keys.forwardTo: searchField
interactive: width !== contentWidth
model: root.selectedType === 0 ? root.currentEmojiModel : stickerPackModel
Component.onCompleted: categories.forceActiveFocus()
delegate: root.selectedType === 0 ? emojiDelegate : stickerDelegate
}
model: UnicodeEmoticonManager.categories
}
Kirigami.Separator {
@@ -104,114 +48,34 @@ ColumnLayout {
id: searchField
Layout.margins: Kirigami.Units.smallSpacing
Layout.fillWidth: true
visible: selectedType === 0
/**
* The focus is manged by the parent and we don't want to use the standard
* shortcut as it could block other SearchFields from using it.
*/
focusSequence: ""
}
EmojiGrid {
id: emojiGrid
targetIconSize: root.currentCategory === EmojiModel.Custom ? Kirigami.Units.gridUnit * 3 : root.categoryIconSize // Custom emojis are bigger
model: root.selectedType === 1 ? emoticonFilterModel : searchField.text.length === 0 ? EmojiModel.emojis(root.currentCategory) : (root.includeCustom ? EmojiModel.filterModel(searchField.text, false) : EmojiModel.filterModelNoCustom(searchField.text, false))
Layout.fillWidth: true
Layout.fillHeight: true
withCustom: root.includeCustom
onChosen: unicode => root.chosen(unicode)
header: categories
header: emoticonPickerCategoryHeader
Keys.forwardTo: searchField
stickers: root.selectedType === 1
stickers: emoticonPickerTypeHeader.selectedType === EmojiPickerTypeHeader.EmoticonType.Sticker
onStickerChosen: stickerModel.postSticker(emoticonFilterModel.mapToSource(emoticonFilterModel.index(index, 0)).row)
}
Kirigami.Separator {
visible: showQuickReaction
Layout.fillWidth: true
Layout.preferredHeight: 1
}
QQC2.ScrollView {
visible: showQuickReaction
QuickReaction {
id: quickReaction
onChosen: root.chosen(text)
Layout.fillWidth: true
Layout.preferredHeight: root.categoryIconSize + QQC2.ScrollBar.horizontal.height
QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
ListView {
id: quickReactions
Layout.fillWidth: true
model: ["👍", "👎", "😄", "🎉", "😕", "❤", "🚀", "👀"]
delegate: EmojiDelegate {
emoji: modelData
height: root.categoryIconSize
width: height
onClicked: root.chosen(modelData)
}
orientation: Qt.Horizontal
}
}
ImagePacksModel {
id: stickerPackModel
room: root.currentRoom
showStickers: true
showEmoticons: false
}
StickerModel {
id: stickerModel
model: stickerPackModel
packIndex: 0
room: root.currentRoom
}
EmoticonFilterModel {
id: emoticonFilterModel
sourceModel: stickerModel
showStickers: true
}
Component {
id: emojiDelegate
Kirigami.NavigationTabButton {
width: root.categoryIconSize
height: width
checked: categories.currentIndex === model.index
text: modelData ? modelData.emoji : ""
QQC2.ToolTip.text: modelData ? modelData.name : ""
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
onClicked: {
categories.currentIndex = index;
categories.focus = true;
}
}
}
Component {
id: stickerDelegate
Kirigami.NavigationTabButton {
width: root.categoryIconSize
height: width
checked: stickerModel.packIndex === model.index
contentItem: Image {
source: model.avatarUrl
}
QQC2.ToolTip.text: model.name
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered && !!model.name
onClicked: stickerModel.packIndex = model.index
}
}
function clearSearchField() {
searchField.text = "";
searchField.text = ""
}
}

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
@@ -54,8 +54,8 @@ QQC2.Popup {
delegate: EmojiDelegate {
id: emojiDelegate
checked: tonesList.currentIndex === model.index
emoji: modelData.unicode
name: modelData.shortName
text: modelData.unicode
toolTip: modelData.shortName
width: root.categoryIconSize
height: width

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +0,0 @@
// SPDX-FileCopyrightText: None
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "emojitones.h"
#include "models/emojimodel.h"
QMultiHash<QString, QVariant> EmojiTones::_tones = {
#include "emojitones_data.h"
};

View File

@@ -1,21 +0,0 @@
// SPDX-FileCopyrightText: None
// SPDX-License-Identifier: LGPL-2.0-or-later
#pragma once
#include <QVariant>
/**
* @class EmojiTones
*
* This class provides a _tones variable with the available emoji tones to EmojiModel.
*
* @sa EmojiModel
*/
class EmojiTones
{
private:
static QMultiHash<QString, QVariant> _tones;
friend class EmojiModel;
};

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,7 @@ LoginStep {
id: root
FormCard.FormTextDelegate {
textItem.wrapMode: Text.Wrap
text: i18n("Please wait while your messages are loaded from the server. This might take a little while.")
}
FormCard.AbstractFormDelegate {

View File

@@ -7,6 +7,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
import org.kde.neochat
import org.kde.neochat.settings
@@ -90,11 +91,27 @@ Kirigami.Page {
id: loadedAccounts
model: AccountRegistry
delegate: FormCard.FormButtonDelegate {
text: model.userId
id: delegate
required property string userId
required property NeoChatConnection connection
text: QmlUtils.escapeString(connection.localUser.displayName)
description: connection.localUser.id
leadingPadding: Kirigami.Units.largeSpacing
onClicked: {
Controller.activeConnection = model.connection;
Controller.activeConnection = delegate.connection;
root.connectionChosen();
}
leading: KirigamiComponents.Avatar {
id: avatar
name: delegate.text
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl.
source: delegate.connection.localUser.avatarUrl.toString().length > 0 ? delegate.connection.makeMediaUrl(delegate.connection.localUser.avatarUrl) : ""
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
}
}
}
Repeater {

View File

@@ -1,222 +0,0 @@
// SPDX-FileCopyrightText: 2021-2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "accountemoticonmodel.h"
#include <QImage>
#include <QMimeDatabase>
#include <Quotient/csapi/content-repo.h>
#include <Quotient/events/eventcontent.h>
#include <qcoro/qcorosignal.h>
#include "neochatconnection.h"
using namespace Quotient;
AccountEmoticonModel::AccountEmoticonModel(QObject *parent)
: QAbstractListModel(parent)
{
}
int AccountEmoticonModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index);
if (!m_images) {
return 0;
}
return m_images->images.size();
}
QVariant AccountEmoticonModel::data(const QModelIndex &index, int role) const
{
if (m_connection == nullptr) {
return {};
}
const auto &row = index.row();
const auto &image = m_images->images[row];
if (role == UrlRole) {
return m_connection->makeMediaUrl(image.url).toString();
}
if (role == BodyRole) {
if (image.body) {
return *image.body;
}
}
if (role == ShortCodeRole) {
return image.shortcode;
}
if (role == IsStickerRole) {
if (image.usage) {
return image.usage->isEmpty() || image.usage->contains("sticker"_ls);
}
if (m_images->pack && m_images->pack->usage) {
return m_images->pack->usage->isEmpty() || m_images->pack->usage->contains("sticker"_ls);
}
return true;
}
if (role == IsEmojiRole) {
if (image.usage) {
return image.usage->isEmpty() || image.usage->contains("emoticon"_ls);
}
if (m_images->pack && m_images->pack->usage) {
return m_images->pack->usage->isEmpty() || m_images->pack->usage->contains("emoticon"_ls);
}
return true;
}
return {};
}
QHash<int, QByteArray> AccountEmoticonModel::roleNames() const
{
return {
{AccountEmoticonModel::UrlRole, "url"},
{AccountEmoticonModel::BodyRole, "body"},
{AccountEmoticonModel::ShortCodeRole, "shortcode"},
{AccountEmoticonModel::IsStickerRole, "isSticker"},
{AccountEmoticonModel::IsEmojiRole, "isEmoji"},
};
}
NeoChatConnection *AccountEmoticonModel::connection() const
{
return m_connection;
}
void AccountEmoticonModel::setConnection(NeoChatConnection *connection)
{
if (m_connection) {
disconnect(m_connection, nullptr, this, nullptr);
}
m_connection = connection;
Q_EMIT connectionChanged();
connect(m_connection, &Connection::accountDataChanged, this, [this](QString type) {
if (type == QStringLiteral("im.ponies.user_emotes")) {
reloadEmoticons();
}
});
reloadEmoticons();
}
void AccountEmoticonModel::reloadEmoticons()
{
if (m_connection == nullptr) {
return;
}
QJsonObject json;
if (m_connection->hasAccountData("im.ponies.user_emotes"_ls)) {
json = m_connection->accountData("im.ponies.user_emotes"_ls)->contentJson();
}
const auto &content = ImagePackEventContent(json);
beginResetModel();
m_images = content;
endResetModel();
}
void AccountEmoticonModel::deleteEmoticon(int index)
{
if (m_connection == nullptr) {
return;
}
QJsonObject data;
m_images->images.removeAt(index);
m_images->fillJson(&data);
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
}
void AccountEmoticonModel::setEmoticonBody(int index, const QString &text)
{
if (m_connection == nullptr) {
return;
}
m_images->images[index].body = text;
QJsonObject data;
m_images->fillJson(&data);
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
}
void AccountEmoticonModel::setEmoticonShortcode(int index, const QString &shortcode)
{
if (m_connection == nullptr) {
return;
}
m_images->images[index].shortcode = shortcode;
QJsonObject data;
m_images->fillJson(&data);
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
}
void AccountEmoticonModel::setEmoticonImage(int index, const QUrl &source)
{
if (m_connection == nullptr) {
return;
}
doSetEmoticonImage(index, source);
}
QCoro::Task<void> AccountEmoticonModel::doSetEmoticonImage(int index, QUrl source)
{
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
co_await qCoro(job.get(), &BaseJob::finished);
if (job->error() != BaseJob::NoError) {
co_return;
}
m_images->images[index].url = job->contentUri();
auto mime = QMimeDatabase().mimeTypeForUrl(source);
source.setScheme("file"_ls);
QFileInfo fileInfo(source.isLocalFile() ? source.toLocalFile() : source.toString());
EventContent::ImageInfo info;
if (mime.name().startsWith("image/"_ls)) {
QImage image(source.toLocalFile());
info = EventContent::ImageInfo(source, fileInfo.size(), mime, image.size(), fileInfo.fileName());
}
m_images->images[index].info = info;
QJsonObject data;
m_images->fillJson(&data);
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
}
QCoro::Task<void> AccountEmoticonModel::doAddEmoticon(QUrl source, QString shortcode, QString description, QString type)
{
auto job = m_connection->uploadFile(source.isLocalFile() ? source.toLocalFile() : source.toString());
co_await qCoro(job.get(), &BaseJob::finished);
if (job->error() != BaseJob::NoError) {
co_return;
}
auto mime = QMimeDatabase().mimeTypeForUrl(source);
source.setScheme("file"_ls);
QFileInfo fileInfo(source.isLocalFile() ? source.toLocalFile() : source.toString());
EventContent::ImageInfo info;
if (mime.name().startsWith("image/"_ls)) {
QImage image(source.toLocalFile());
info = EventContent::ImageInfo(source, fileInfo.size(), mime, image.size(), fileInfo.fileName());
}
m_images->images.append(ImagePackEventContent::ImagePackImage{
shortcode,
job->contentUri(),
description,
info,
QStringList{type},
});
QJsonObject data;
m_images->fillJson(&data);
m_connection->setAccountData("im.ponies.user_emotes"_ls, data);
}
void AccountEmoticonModel::addEmoticon(const QUrl &source, const QString &shortcode, const QString &description, const QString &type)
{
if (m_connection == nullptr) {
return;
}
doAddEmoticon(source, shortcode, description, type);
}
#include "moc_accountemoticonmodel.cpp"

View File

@@ -1,104 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#pragma once
#include "events/imagepackevent.h"
#include <QAbstractListModel>
#include <QCoroTask>
#include <QList>
#include <QObject>
#include <QPointer>
#include <QQmlEngine>
class NeoChatConnection;
/**
* @class AccountEmoticonModel
*
* This class defines the model for visualising the account stickers and emojis.
*
* This is based upon the im.ponies.user_emotes spec (MSC2545).
*/
class AccountEmoticonModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
/**
* @brief The connection to get emoticons from.
*/
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
public:
enum Roles {
UrlRole = Qt::UserRole + 1, /**< The URL for the emoticon. */
ShortCodeRole, /**< The shortcode for the emoticon. */
BodyRole, //**< A textual description of the emoticon */
IsStickerRole, //**< Whether this emoticon is a sticker */
IsEmojiRole, //**< Whether this emoticon is an emoji */
};
explicit AccountEmoticonModel(QObject *parent = nullptr);
/**
* @brief Number of rows in the model.
*
* @sa QAbstractItemModel::rowCount
*/
[[nodiscard]] int rowCount(const QModelIndex &index) const override;
/**
* @brief Get the given role value at the given index.
*
* @sa QAbstractItemModel::data
*/
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
/**
* @brief Returns a mapping from Role enum values to role names.
*
* @sa Roles, QAbstractItemModel::roleNames()
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
/**
* @brief Deletes the emoticon at the given index.
*/
Q_INVOKABLE void deleteEmoticon(int index);
/**
* @brief Changes the description for the emoticon at the given index.
*/
Q_INVOKABLE void setEmoticonBody(int index, const QString &text);
/**
* @brief Changes the shortcode for the emoticon at the given index.
*/
Q_INVOKABLE void setEmoticonShortcode(int index, const QString &shortCode);
/**
* @brief Changes the image for the emoticon at the given index.
*/
Q_INVOKABLE void setEmoticonImage(int index, const QUrl &source);
/**
* @brief Add an emoticon with the given parameters.
*/
Q_INVOKABLE void addEmoticon(const QUrl &source, const QString &shortcode, const QString &description, const QString &type);
Q_SIGNALS:
void connectionChanged();
private:
std::optional<Quotient::ImagePackEventContent> m_images;
QPointer<NeoChatConnection> m_connection;
QCoro::Task<void> doSetEmoticonImage(int index, QUrl source);
QCoro::Task<void> doAddEmoticon(QUrl source, QString shortcode, QString description, QString type);
void reloadEmoticons();
};

View File

@@ -600,14 +600,19 @@ bool ActionsModel::handleQuickEditAction(NeoChatRoom *room, const QString &messa
} else {
originalString = event->plainBody();
}
QString replaceId = event->id();
const auto eventRelation = event->relatesTo();
if (eventRelation && eventRelation->type == "m.replace"_L1) {
replaceId = eventRelation->eventId;
}
if (flags == "/g"_L1) {
room->postHtmlMessage(messageText, originalString.replace(regex, replacement), event->msgtype(), {}, event->id());
room->postHtmlMessage(messageText, originalString.replace(regex, replacement), event->msgtype(), {}, replaceId);
} else {
room->postHtmlMessage(messageText,
originalString.replace(originalString.indexOf(regex), regex.size(), replacement),
event->msgtype(),
{},
event->id());
replaceId);
}
return true;
}

View File

@@ -6,8 +6,7 @@
#include "actionsmodel.h"
#include "completionproxymodel.h"
#include "customemojimodel.h"
#include "emojimodel.h"
// #include "emojimodel.h"
#include "neochatroom.h"
#include "roommanager.h"
#include "userlistmodel.h"
@@ -16,11 +15,13 @@ CompletionModel::CompletionModel(QObject *parent)
: QAbstractListModel(parent)
, m_filterModel(new CompletionProxyModel())
, m_userListModel(RoomManager::instance().userListModel())
, m_emojiModel(new QConcatenateTablesProxyModel(this))
//, m_emojiModel(new QConcatenateTablesProxyModel(this))
{
connect(this, &CompletionModel::textChanged, this, &CompletionModel::updateCompletion);
m_emojiModel->addSourceModel(&CustomEmojiModel::instance());
m_emojiModel->addSourceModel(&EmojiModel::instance());
connect(this, &CompletionModel::roomChanged, this, [this]() {
m_userListModel->setRoom(m_room);
});
// TODO m_emojiModel->addSourceModel(&EmojiModel::instance());
}
QString CompletionModel::text() const
@@ -85,29 +86,23 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
}
if (role == IconNameRole) {
auto mediaId = m_filterModel->data(filterIndex, RoomListModel::AvatarRole).toString();
if (mediaId.isEmpty()) {
return QVariant();
}
if (m_room) {
return m_room->connection()->makeMediaUrl(QUrl(QStringLiteral("mxc://%1").arg(mediaId)));
}
}
}
if (m_autoCompletionType == Emoji) {
if (role == DisplayNameRole) {
return m_filterModel->data(filterIndex, CustomEmojiModel::DisplayRole);
}
if (role == IconNameRole) {
return m_filterModel->data(filterIndex, CustomEmojiModel::MxcUrl);
}
if (role == ReplacedTextRole) {
return m_filterModel->data(filterIndex, CustomEmojiModel::ReplacedTextRole);
}
if (role == SubtitleRole) {
return m_filterModel->data(filterIndex, EmojiModel::DescriptionRole);
return m_filterModel->data(filterIndex, RoomListModel::AvatarRole).toString();
}
}
// if (m_autoCompletionType == Emoji) {
// if (role == DisplayNameRole) {
// return m_filterModel->data(filterIndex, CustomEmojiModel::DisplayRole);
// }
// if (role == IconNameRole) {
// return m_filterModel->data(filterIndex, CustomEmojiModel::MxcUrl);
// }
// if (role == ReplacedTextRole) {
// return m_filterModel->data(filterIndex, CustomEmojiModel::ReplacedTextRole);
// }
// if (role == SubtitleRole) {
// // TODO return m_filterModel->data(filterIndex, EmojiModel::DescriptionRole);
// }
// }
return {};
}
@@ -153,8 +148,8 @@ void CompletionModel::updateCompletion()
|| (m_fullText.indexOf(QLatin1Char(' ')) != -1 && m_fullText.indexOf(QLatin1Char(':'), 1) > m_fullText.indexOf(QLatin1Char(' '), 1)))) {
m_filterModel->setSourceModel(m_emojiModel);
m_autoCompletionType = Emoji;
m_filterModel->setFilterRole(CustomEmojiModel::Name);
m_filterModel->setSecondaryFilterRole(EmojiModel::DescriptionRole);
// m_filterModel->setFilterRole(CustomEmojiModel::Name);
// TODO m_filterModel->setSecondaryFilterRole(EmojiModel::DescriptionRole);
m_filterModel->setFullText(m_fullText);
m_filterModel->setFilterText(m_text);
m_filterModel->invalidate();

View File

@@ -1,213 +0,0 @@
// SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "customemojimodel.h"
#include <QImage>
#include <QMimeDatabase>
#include "emojimodel.h"
#include <Quotient/csapi/account-data.h>
#include <Quotient/csapi/content-repo.h>
using namespace Quotient;
void CustomEmojiModel::setConnection(NeoChatConnection *connection)
{
if (connection == m_connection) {
return;
}
m_connection = connection;
Q_EMIT connectionChanged();
fetchEmojis();
}
NeoChatConnection *CustomEmojiModel::connection() const
{
return m_connection;
}
void CustomEmojiModel::fetchEmojis()
{
if (!m_connection) {
return;
}
const auto &data = m_connection->accountData("im.ponies.user_emotes"_ls);
if (data == nullptr) {
return;
}
QJsonObject emojis = data->contentJson()["images"_ls].toObject();
// TODO: Remove with stable migration
const auto legacyEmojis = data->contentJson()["emoticons"_ls].toObject();
for (const auto &emoji : legacyEmojis.keys()) {
if (!emojis.contains(emoji)) {
emojis[emoji] = legacyEmojis[emoji];
}
}
beginResetModel();
m_emojis.clear();
for (const auto &emoji : emojis.keys()) {
const auto &data = emojis[emoji];
const auto e = emoji.startsWith(":"_ls) ? emoji : (QStringLiteral(":") + emoji + QStringLiteral(":"));
m_emojis << CustomEmoji{e, data.toObject()["url"_ls].toString(), QRegularExpression(e)};
}
endResetModel();
}
void CustomEmojiModel::addEmoji(const QString &name, const QUrl &location)
{
using namespace Quotient;
auto job = m_connection->uploadFile(location.toLocalFile());
connect(job, &BaseJob::success, this, [name, location, job, this] {
const auto &data = m_connection->accountData("im.ponies.user_emotes"_ls);
auto json = data != nullptr ? data->contentJson() : QJsonObject();
auto emojiData = json["images"_ls].toObject();
QString url;
url = job->contentUri().toString();
QImage image(location.toLocalFile());
QJsonObject imageInfo;
imageInfo["w"_ls] = image.width();
imageInfo["h"_ls] = image.height();
imageInfo["mimetype"_ls] = QMimeDatabase().mimeTypeForFile(location.toLocalFile()).name();
imageInfo["size"_ls] = image.sizeInBytes();
emojiData[QStringLiteral("%1").arg(name)] = QJsonObject({
{QStringLiteral("url"), url},
{QStringLiteral("info"), imageInfo},
{QStringLiteral("body"), location.fileName()},
{"usage"_ls, "emoticon"_ls},
});
json["images"_ls] = emojiData;
m_connection->setAccountData("im.ponies.user_emotes"_ls, json);
});
}
void CustomEmojiModel::removeEmoji(const QString &name)
{
using namespace Quotient;
const auto &data = m_connection->accountData("im.ponies.user_emotes"_ls);
Q_ASSERT(data);
auto json = data->contentJson();
const QString _name = name.mid(1).chopped(1);
auto emojiData = json["images"_ls].toObject();
if (emojiData.contains(name)) {
emojiData.remove(name);
json["images"_ls] = emojiData;
}
if (emojiData.contains(_name)) {
emojiData.remove(_name);
json["images"_ls] = emojiData;
}
emojiData = json["emoticons"_ls].toObject();
if (emojiData.contains(name)) {
emojiData.remove(name);
json["emoticons"_ls] = emojiData;
}
if (emojiData.contains(_name)) {
emojiData.remove(_name);
json["emoticons"_ls] = emojiData;
}
m_connection->setAccountData("im.ponies.user_emotes"_ls, json);
}
CustomEmojiModel::CustomEmojiModel(QObject *parent)
: QAbstractListModel(parent)
{
connect(this, &CustomEmojiModel::connectionChanged, this, [this]() {
if (!m_connection) {
return;
}
CustomEmojiModel::fetchEmojis();
connect(m_connection, &Connection::accountDataChanged, this, [this](const QString &id) {
if (id != QStringLiteral("im.ponies.user_emotes")) {
return;
}
fetchEmojis();
});
});
CustomEmojiModel::fetchEmojis();
}
QVariant CustomEmojiModel::data(const QModelIndex &idx, int role) const
{
const auto row = idx.row();
if (row >= m_emojis.length()) {
return QVariant();
}
const auto &data = m_emojis[row];
switch (Roles(role)) {
case Roles::ModelData:
return QVariant::fromValue(Emoji(m_connection->makeMediaUrl(QUrl(data.url)).toString(), data.name, true));
case Roles::Name:
case Roles::DisplayRole:
case Roles::ReplacedTextRole:
return data.name;
case Roles::ImageURL:
return m_connection->makeMediaUrl(QUrl(data.url));
case Roles::MxcUrl:
return m_connection->makeMediaUrl(QUrl(data.url));
default:
return {};
}
return QVariant();
}
int CustomEmojiModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_emojis.length();
}
QHash<int, QByteArray> CustomEmojiModel::roleNames() const
{
return {
{Name, "name"},
{ImageURL, "imageURL"},
{ModelData, "modelData"},
{MxcUrl, "mxcUrl"},
};
}
QString CustomEmojiModel::preprocessText(QString text)
{
for (const auto &emoji : std::as_const(m_emojis)) {
text.replace(
emoji.regexp,
QStringLiteral(R"(<img data-mx-emoticon="" src="%1" alt="%2" title="%2" height="32" vertical-align="middle" />)").arg(emoji.url, emoji.name));
}
return text;
}
QVariantList CustomEmojiModel::filterModel(const QString &filter)
{
QVariantList results;
for (const auto &emoji : std::as_const(m_emojis)) {
if (results.length() >= 10)
break;
if (!emoji.name.contains(filter, Qt::CaseInsensitive))
continue;
results << QVariant::fromValue(Emoji(m_connection->makeMediaUrl(QUrl(emoji.url)).toString(), emoji.name, true));
}
return results;
}
#include "moc_customemojimodel.cpp"

View File

@@ -1,116 +0,0 @@
// SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QAbstractListModel>
#include <QQmlEngine>
#include <QRegularExpression>
#include "neochatconnection.h"
struct CustomEmoji {
QString name; // with :semicolons:
QString url; // mxc://
QRegularExpression regexp;
Q_GADGET
Q_PROPERTY(QString unicode MEMBER url)
Q_PROPERTY(QString name MEMBER name)
};
/**
* @class CustomEmojiModel
*
* This class defines the model for custom user emojis.
*
* This is based upon the im.ponies.user_emotes spec (MSC2545).
*/
class CustomEmojiModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
public:
/**
* @brief Defines the model roles.
*/
enum Roles {
Name = Qt::DisplayRole, /**< The name of the emoji. */
ImageURL, /**< The URL for the custom emoji. */
ModelData, /**< for emulating the regular emoji model's usage, otherwise the UI code would get too complicated. */
MxcUrl = 50, /**< The mxc source URL for the custom emoji. */
DisplayRole = 51, /**< The name of the emoji. For compatibility with EmojiModel. */
ReplacedTextRole = 52, /**< The name of the emoji. For compatibility with EmojiModel. */
DescriptionRole = 53, /**< Invalid, reserved. For compatibility with EmojiModel. */
};
Q_ENUM(Roles)
static CustomEmojiModel &instance()
{
static CustomEmojiModel _instance;
return _instance;
}
static CustomEmojiModel *create(QQmlEngine *engine, QJSEngine *)
{
engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership);
return &instance();
}
/**
* @brief Get the given role value at the given index.
*
* @sa QAbstractItemModel::data
*/
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
/**
* @brief Number of rows in the model.
*
* @sa QAbstractItemModel::rowCount
*/
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
/**
* @brief Returns a mapping from Role enum values to role names.
*
* @sa Roles, QAbstractItemModel::roleNames()
*/
QHash<int, QByteArray> roleNames() const override;
/**
* @brief Substitute any custom emojis for an image in the input text.
*/
Q_INVOKABLE QString preprocessText(QString text);
/**
* @brief Return a list of custom emojis where the name contains the filter text.
*/
Q_INVOKABLE QVariantList filterModel(const QString &filter);
/**
* @brief Add a new emoji to the model.
*/
Q_INVOKABLE void addEmoji(const QString &name, const QUrl &location);
/**
* @brief Remove an emoji from the model.
*/
Q_INVOKABLE void removeEmoji(const QString &name);
void setConnection(NeoChatConnection *connection);
NeoChatConnection *connection() const;
Q_SIGNALS:
void connectionChanged();
private:
explicit CustomEmojiModel(QObject *parent = nullptr);
QList<CustomEmoji> m_emojis;
QPointer<NeoChatConnection> m_connection;
void fetchEmojis();
};

View File

@@ -1,242 +0,0 @@
// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <QVariant>
#include "emojimodel.h"
#include "emojitones.h"
#include <QDebug>
#include <algorithm>
#include "customemojimodel.h"
#include <KLocalizedString>
EmojiModel::EmojiModel(QObject *parent)
: QAbstractListModel(parent)
, m_config(KSharedConfig::openStateConfig())
, m_configGroup(KConfigGroup(m_config, QStringLiteral("Editor")))
{
if (_emojis.isEmpty()) {
#include "emojis.h"
}
}
int EmojiModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
int total = 0;
for (const auto &category : std::as_const(_emojis)) {
total += category.count();
}
return total;
}
QVariant EmojiModel::data(const QModelIndex &index, int role) const
{
auto row = index.row();
for (const auto &category : std::as_const(_emojis)) {
if (row >= category.count()) {
row -= category.count();
continue;
}
auto emoji = category[row].value<Emoji>();
switch (role) {
case ShortNameRole:
return QStringLiteral(":%1:").arg(emoji.shortName);
case UnicodeRole:
case ReplacedTextRole:
return emoji.unicode;
case InvalidRole:
return QStringLiteral("invalid");
case DisplayRole:
return QStringLiteral("%2 :%1:").arg(emoji.shortName, emoji.unicode);
case DescriptionRole:
return emoji.description;
}
}
return {};
}
QHash<int, QByteArray> EmojiModel::roleNames() const
{
return {{ShortNameRole, "shortName"}, {UnicodeRole, "unicode"}};
}
QStringList EmojiModel::lastUsedEmojis() const
{
return m_configGroup.readEntry(QStringLiteral("lastUsedEmojis"), QStringList());
}
QVariantList EmojiModel::filterModel(const QString &filter, bool limit)
{
auto emojis = CustomEmojiModel::instance().filterModel(filter);
emojis += filterModelNoCustom(filter, limit);
return emojis;
}
QVariantList EmojiModel::filterModelNoCustom(const QString &filter, bool limit)
{
QVariantList result;
const auto &values = _emojis.values();
for (const auto &e : values) {
for (const auto &variant : e) {
const auto &emoji = qvariant_cast<Emoji>(variant);
if (emoji.shortName.contains(filter, Qt::CaseInsensitive)) {
result.append(variant);
if (result.length() > 10 && limit) {
return result;
}
}
}
}
return result;
}
void EmojiModel::emojiUsed(const QVariant &modelData)
{
auto list = lastUsedEmojis();
const auto emoji = modelData.value<Emoji>();
auto it = list.begin();
while (it != list.end()) {
if (*it == emoji.shortName) {
it = list.erase(it);
} else {
it++;
}
}
list.push_front(emoji.shortName);
m_configGroup.writeEntry(QStringLiteral("lastUsedEmojis"), list);
Q_EMIT historyChanged();
}
QVariantList EmojiModel::emojis(Category category) const
{
if (category == History) {
return emojiHistory();
}
if (category == HistoryNoCustom) {
QVariantList list;
const auto &history = emojiHistory();
for (const auto &e : history) {
auto emoji = qvariant_cast<Emoji>(e);
if (!emoji.isCustom) {
list.append(e);
}
}
return list;
}
if (category == Custom) {
return CustomEmojiModel::instance().filterModel({});
}
return _emojis[category];
}
QVariantList EmojiModel::tones(const QString &baseEmoji) const
{
if (baseEmoji.endsWith(QStringLiteral("tone"))) {
return EmojiTones::_tones.values(baseEmoji.split(QStringLiteral(":"))[0]);
}
return EmojiTones::_tones.values(baseEmoji);
}
QHash<EmojiModel::Category, QVariantList> EmojiModel::_emojis;
QVariantList EmojiModel::categories() const
{
return QVariantList{
{QVariantMap{
{QStringLiteral("category"), EmojiModel::HistoryNoCustom},
{QStringLiteral("name"), i18nc("Previously used emojis", "History")},
{QStringLiteral("emoji"), QStringLiteral("⌛️")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Smileys},
{QStringLiteral("name"), i18nc("'Smileys' is a category of emoji", "Smileys")},
{QStringLiteral("emoji"), QStringLiteral("😏")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::People},
{QStringLiteral("name"), i18nc("'People' is a category of emoji", "People")},
{QStringLiteral("emoji"), QStringLiteral("🙋‍♂️")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Nature},
{QStringLiteral("name"), i18nc("'Nature' is a category of emoji", "Nature")},
{QStringLiteral("emoji"), QStringLiteral("🌲")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Food},
{QStringLiteral("name"), i18nc("'Food' is a category of emoji", "Food")},
{QStringLiteral("emoji"), QStringLiteral("🍛")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Activities},
{QStringLiteral("name"), i18nc("'Activities' is a category of emoji", "Activities")},
{QStringLiteral("emoji"), QStringLiteral("🚁")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Travel},
{QStringLiteral("name"), i18nc("'Travel' is a category of emoji", "Travel")},
{QStringLiteral("emoji"), QStringLiteral("🚅")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Objects},
{QStringLiteral("name"), i18nc("'Objects' is a category of emoji", "Objects")},
{QStringLiteral("emoji"), QStringLiteral("💡")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Symbols},
{QStringLiteral("name"), i18nc("'Symbols' is a category of emoji", "Symbols")},
{QStringLiteral("emoji"), QStringLiteral("🔣")},
}},
{QVariantMap{
{QStringLiteral("category"), EmojiModel::Flags},
{QStringLiteral("name"), i18nc("'Flags' is a category of emoji", "Flags")},
{QStringLiteral("emoji"), QStringLiteral("🏁")},
}},
};
}
QVariantList EmojiModel::categoriesWithCustom() const
{
auto cats = categories();
cats.removeAt(0);
cats.insert(0,
QVariantMap{
{QStringLiteral("category"), EmojiModel::History},
{QStringLiteral("name"), i18nc("Previously used emojis", "History")},
{QStringLiteral("emoji"), QStringLiteral("⌛️")},
});
cats.insert(1,
QVariantMap{
{QStringLiteral("category"), EmojiModel::Custom},
{QStringLiteral("name"), i18nc("'Custom' is a category of emoji", "Custom")},
{QStringLiteral("emoji"), QStringLiteral("🖼️")},
});
;
return cats;
}
QVariantList EmojiModel::emojiHistory() const
{
QVariantList list;
const auto &lastUsed = lastUsedEmojis();
for (const auto &historicEmoji : lastUsed) {
for (const auto &emojiCategory : std::as_const(_emojis)) {
for (const auto &emoji : emojiCategory) {
if (qvariant_cast<Emoji>(emoji).shortName == historicEmoji) {
list.append(emoji);
}
}
}
}
return list;
}
#include "moc_emojimodel.cpp"

View File

@@ -1,184 +0,0 @@
// SPDX-FileCopyrightText: 2018 Black Hat <bhat@encom.eu.org>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <KConfigGroup>
#include <KSharedConfig>
#include <QAbstractListModel>
#include <QObject>
#include <QQmlEngine>
struct Emoji {
Emoji(QString unicode, QString shortname, bool isCustom = false)
: unicode(std::move(unicode))
, shortName(std::move(shortname))
, isCustom(isCustom)
{
}
Emoji(QString unicode, QString shortname, QString description)
: unicode(std::move(unicode))
, shortName(std::move(shortname))
, description(std::move(description))
{
}
Emoji() = default;
QString unicode;
QString shortName;
QString description;
bool isCustom = false;
Q_GADGET
Q_PROPERTY(QString unicode MEMBER unicode)
Q_PROPERTY(QString shortName MEMBER shortName)
Q_PROPERTY(QString description MEMBER description)
Q_PROPERTY(bool isCustom MEMBER isCustom)
};
Q_DECLARE_METATYPE(Emoji)
/**
* @class EmojiModel
*
* This class defines the model for visualising a list of emojis.
*/
class EmojiModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
/**
* @brief Return a list of emoji categories.
*
* @note No custom emoji categories will be included.
*/
Q_PROPERTY(QVariantList categories READ categories CONSTANT)
/**
* @brief Return a list of emoji categories with custom emojis.
*/
Q_PROPERTY(QVariantList categoriesWithCustom READ categoriesWithCustom CONSTANT)
public:
static EmojiModel &instance()
{
static EmojiModel _instance;
return _instance;
}
static EmojiModel *create(QQmlEngine *engine, QJSEngine *)
{
engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership);
return &instance();
}
/**
* @brief Defines the model roles.
*/
enum RoleNames {
ShortNameRole = Qt::DisplayRole, /**< The name of the emoji. */
UnicodeRole, /**< The unicode character of the emoji. */
InvalidRole = 50, /**< Invalid, reserved. */
DisplayRole = 51, /**< The display text for an emoji. */
ReplacedTextRole = 52, /**< The text to replace the short name with (i.e. the unicode character). */
DescriptionRole = 53, /**< The long description of an emoji. */
};
Q_ENUM(RoleNames)
/**
* @brief Defines the potential categories an emoji can be placed in.
*/
enum Category {
Custom, /**< A custom user emoji. */
Search, /**< The results of a filter. */
SearchNoCustom, /**< The results of a filter with no custom emojis. */
History, /**< Recently used emojis. */
HistoryNoCustom, /**< Recently used emojis with no custom emojis. */
Smileys, /**< Smileys & emotion emojis. */
People, /**< People & Body emojis. */
Nature, /**< Animals & Nature emojis. */
Food, /**< Food & Drink emojis. */
Activities, /**< Activities emojis. */
Travel, /**< Travel & Places emojis. */
Objects, /**< Objects emojis. */
Symbols, /**< Symbols emojis. */
Flags, /**< Flags emojis. */
Component, /**< ??? */
};
Q_ENUM(Category)
/**
* @brief Get the given role value at the given index.
*
* @sa QAbstractItemModel::data
*/
[[nodiscard]] QVariant data(const QModelIndex &idx, 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 RoleNames, QAbstractItemModel::roleNames()
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
/**
* @brief Return a filtered list of emojis.
*
* @note This includes custom emojis, use filterModelNoCustom to return a result
* without custom emojis.
*
* @sa filterModelNoCustom
*/
Q_INVOKABLE static QVariantList filterModel(const QString &filter, bool limit = true);
/**
* @brief Return a filtered list of emojis without custom emojis.
*
* @note Use filterModel to return a result with custom emojis.
*
* @sa filterModel
*/
Q_INVOKABLE static QVariantList filterModelNoCustom(const QString &filter, bool limit = true);
/**
* @brief Return a list of emojis for the given category.
*/
Q_INVOKABLE QVariantList emojis(Category category) const;
/**
* @brief Return a list of emoji tones for the given base emoji.
*/
Q_INVOKABLE QVariantList tones(const QString &baseEmoji) const;
/**
* @brief Return a list of the last used emoji shortnames
*/
QStringList lastUsedEmojis() const;
QVariantList categories() const;
QVariantList categoriesWithCustom() const;
Q_SIGNALS:
void historyChanged();
public Q_SLOTS:
void emojiUsed(const QVariant &modelData);
private:
static QHash<Category, QVariantList> _emojis;
/// Returns QVariants containing the last used Emojis
QVariantList emojiHistory() const;
KSharedConfig::Ptr m_config;
KConfigGroup m_configGroup;
EmojiModel(QObject *parent = nullptr);
};

View File

@@ -1,57 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "emoticonfiltermodel.h"
#include "accountemoticonmodel.h"
#include "stickermodel.h"
EmoticonFilterModel::EmoticonFilterModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
connect(this, &EmoticonFilterModel::sourceModelChanged, this, [this]() {
if (dynamic_cast<StickerModel *>(sourceModel())) {
m_stickerRole = StickerModel::IsStickerRole;
m_emojiRole = StickerModel::IsEmojiRole;
} else {
m_stickerRole = AccountEmoticonModel::IsStickerRole;
m_emojiRole = AccountEmoticonModel::IsEmojiRole;
}
});
}
bool EmoticonFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
Q_UNUSED(sourceParent);
auto stickerUsage = sourceModel()->data(sourceModel()->index(sourceRow, 0), m_stickerRole).toBool();
auto emojiUsage = sourceModel()->data(sourceModel()->index(sourceRow, 0), m_emojiRole).toBool();
return (stickerUsage && m_showStickers) || (emojiUsage && m_showEmojis);
}
bool EmoticonFilterModel::showStickers() const
{
return m_showStickers;
}
void EmoticonFilterModel::setShowStickers(bool showStickers)
{
beginResetModel();
m_showStickers = showStickers;
endResetModel();
Q_EMIT showStickersChanged();
}
bool EmoticonFilterModel::showEmojis() const
{
return m_showEmojis;
}
void EmoticonFilterModel::setShowEmojis(bool showEmojis)
{
beginResetModel();
m_showEmojis = showEmojis;
endResetModel();
Q_EMIT showEmojisChanged();
}
#include "moc_emoticonfiltermodel.cpp"

View File

@@ -1,55 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QQmlEngine>
#include <QSortFilterProxyModel>
/**
* @class EmoticonFilterModel
*
* This class creates a custom QSortFilterProxyModel for filtering a emoticon by type
* (Sticker or Emoji).
*/
class EmoticonFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
QML_ELEMENT
/**
* @brief Whether stickers should be shown
*/
Q_PROPERTY(bool showStickers READ showStickers WRITE setShowStickers NOTIFY showStickersChanged)
/**
* @brief Whether emojis show be shown
*/
Q_PROPERTY(bool showEmojis READ showEmojis WRITE setShowEmojis NOTIFY showEmojisChanged)
public:
explicit EmoticonFilterModel(QObject *parent = nullptr);
/**
* @brief Custom filter function checking the type of emoticon
*
* @note The filter cannot be modified and will always use the same filter properties.
*/
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
[[nodiscard]] bool showStickers() const;
void setShowStickers(bool showStickers);
[[nodiscard]] bool showEmojis() const;
void setShowEmojis(bool showEmojis);
Q_SIGNALS:
void showStickersChanged();
void showEmojisChanged();
private:
bool m_showStickers = false;
bool m_showEmojis = false;
int m_stickerRole = 0;
int m_emojiRole = 0;
};

View File

@@ -1,170 +0,0 @@
// SPDX-FileCopyrightText: 2021 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "imagepacksmodel.h"
#include "neochatroom.h"
#include <KLocalizedString>
using namespace Quotient;
ImagePacksModel::ImagePacksModel(QObject *parent)
: QAbstractListModel(parent)
{
}
int ImagePacksModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index);
return m_events.count();
}
QVariant ImagePacksModel::data(const QModelIndex &index, int role) const
{
const auto row = index.row();
if (row < 0 || row >= m_events.size()) {
return {};
}
const auto &event = m_events[row];
if (role == DisplayNameRole) {
if (event.pack->displayName) {
return *event.pack->displayName;
}
}
if (role == AvatarUrlRole) {
if (event.pack->avatarUrl) {
return m_room->connection()->makeMediaUrl(*event.pack->avatarUrl);
} else if (!event.images.empty()) {
return m_room->connection()->makeMediaUrl(event.images[0].url);
}
}
return {};
}
QHash<int, QByteArray> ImagePacksModel::roleNames() const
{
return {
{DisplayNameRole, "displayName"},
{AvatarUrlRole, "avatarUrl"},
{AttributionRole, "attribution"},
{IdRole, "id"},
};
}
NeoChatRoom *ImagePacksModel::room() const
{
return m_room;
}
void ImagePacksModel::setRoom(NeoChatRoom *room)
{
if (m_room) {
disconnect(m_room, nullptr, this, nullptr);
disconnect(m_room->connection(), nullptr, this, nullptr);
}
m_room = room;
if (m_room) {
connect(m_room->connection(), &Connection::accountDataChanged, this, [this](const QString &type) {
if (type == "im.ponies.user_emotes"_ls) {
reloadImages();
}
});
}
// TODO listen to packs changing
reloadImages();
Q_EMIT roomChanged();
}
void ImagePacksModel::reloadImages()
{
if (!m_room) {
return;
}
beginResetModel();
m_events.clear();
// Load emoticons from the account data
if (m_room->connection()->hasAccountData("im.ponies.user_emotes"_ls)) {
auto json = m_room->connection()->accountData("im.ponies.user_emotes"_ls)->contentJson();
json["pack"_ls] = QJsonObject{
{"display_name"_ls,
m_showStickers ? i18nc("As in 'The user's own Stickers'", "Own Stickers") : i18nc("As in 'The user's own emojis", "Own Emojis")},
};
const auto &content = ImagePackEventContent(json);
if (!content.images.isEmpty()) {
m_events += ImagePackEventContent(json);
}
}
// Load emoticons from the saved rooms
const auto &accountData = m_room->connection()->accountData("im.ponies.emote_rooms"_ls);
if (accountData) {
const auto &rooms = accountData->contentJson()["rooms"_ls].toObject();
for (const auto &roomId : rooms.keys()) {
if (roomId == m_room->id()) {
continue;
}
auto packs = rooms[roomId].toObject();
const auto &stickerRoom = m_room->connection()->room(roomId);
if (!stickerRoom) {
continue;
}
for (const auto &packKey : packs.keys()) {
if (const auto &pack = stickerRoom->currentState().get<ImagePackEvent>(packKey)) {
const auto packContent = pack->content();
if ((!packContent.pack || !packContent.pack->usage || (packContent.pack->usage->contains("emoticon"_ls) && showEmoticons())
|| (packContent.pack->usage->contains("sticker"_ls) && showStickers()))
&& !packContent.images.isEmpty()) {
m_events += packContent;
}
}
}
}
}
// Load emoticons from the current room
auto events = m_room->currentState().eventsOfType("im.ponies.room_emotes"_ls);
for (const auto &event : events) {
auto packContent = eventCast<const ImagePackEvent>(event)->content();
if (packContent.pack.has_value()) {
if (!packContent.pack->usage || (packContent.pack->usage->contains("emoticon"_ls) && showEmoticons())
|| (packContent.pack->usage->contains("sticker"_ls) && showStickers())) {
m_events += packContent;
}
}
}
Q_EMIT imagesLoaded();
endResetModel();
}
bool ImagePacksModel::showStickers() const
{
return m_showStickers;
}
void ImagePacksModel::setShowStickers(bool showStickers)
{
m_showStickers = showStickers;
Q_EMIT showStickersChanged();
}
bool ImagePacksModel::showEmoticons() const
{
return m_showEmoticons;
}
void ImagePacksModel::setShowEmoticons(bool showEmoticons)
{
m_showEmoticons = showEmoticons;
Q_EMIT showEmoticonsChanged();
}
QList<Quotient::ImagePackEventContent::ImagePackImage> ImagePacksModel::images(int index)
{
if (index < 0 || index >= m_events.size()) {
return {};
}
return m_events[index].images;
}
#include "moc_imagepacksmodel.cpp"

View File

@@ -1,103 +0,0 @@
// SPDX-FileCopyrightText: 2021-2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#pragma once
#include "events/imagepackevent.h"
#include <QAbstractListModel>
#include <QList>
#include <QPointer>
#include <QQmlEngine>
class NeoChatRoom;
/**
* @class ImagePacksModel
*
* Defines the model for visualising image packs.
*
* See Matrix MSC2545 for more details on image packs.
* https://github.com/Sorunome/matrix-doc/blob/soru/emotes/proposals/2545-emotes.md
*/
class ImagePacksModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
/**
* @brief The current room that the model is being used in.
*/
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
/**
* @brief Whether sticker image packs should be shown.
*/
Q_PROPERTY(bool showStickers READ showStickers WRITE setShowStickers NOTIFY showStickersChanged)
/**
* @brief Whether emoticon image packs should be shown.
*/
Q_PROPERTY(bool showEmoticons READ showEmoticons WRITE setShowEmoticons NOTIFY showEmoticonsChanged)
public:
/**
* @brief Defines the model roles.
*/
enum Roles {
DisplayNameRole = Qt::DisplayRole, /**< The display name of the image pack. */
AvatarUrlRole, /**< The source mxc URL for the pack avatar. */
AttributionRole, /**< The attribution for the pack author(s). */
IdRole, /**< The ID of the image pack. */
};
Q_ENUM(Roles)
explicit ImagePacksModel(QObject *parent = nullptr);
/**
* @brief Get the given role value at the given index.
*
* @sa QAbstractItemModel::data
*/
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
/**
* @brief Number of rows in the model.
*
* @sa QAbstractItemModel::rowCount
*/
[[nodiscard]] int rowCount(const QModelIndex &index) const override;
/**
* @brief Returns a mapping from Role enum values to role names.
*
* @sa Roles, QAbstractItemModel::roleNames()
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] NeoChatRoom *room() const;
void setRoom(NeoChatRoom *room);
[[nodiscard]] bool showStickers() const;
void setShowStickers(bool showStickers);
[[nodiscard]] bool showEmoticons() const;
void setShowEmoticons(bool showEmoticons);
/**
* @brief Return a vector of the images in the pack at the given index.
*/
[[nodiscard]] QList<Quotient::ImagePackEventContent::ImagePackImage> images(int index);
Q_SIGNALS:
void roomChanged();
void showStickersChanged();
void showEmoticonsChanged();
void imagesLoaded();
private:
QPointer<NeoChatRoom> m_room;
QList<Quotient::ImagePackEventContent> m_events;
bool m_showStickers = true;
bool m_showEmoticons = true;
void reloadImages();
};

View File

@@ -588,15 +588,22 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
case MessageComponentType::Video: {
if (!event.first->is<StickerEvent>()) {
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event.first);
QList<MessageComponent> components;
components += MessageComponent{type, QString(), {}};
auto body = EventHandler::rawMessageBody(*roomMessageEvent);
components += TextHandler().textComponents(body,
EventHandler::messageBodyInputFormat(*roomMessageEvent),
m_room,
roomMessageEvent,
roomMessageEvent->isReplaced());
return components;
const auto fileContent = roomMessageEvent->get<EventContent::FileContentBase>();
if (fileContent != nullptr) {
const auto fileInfo = fileContent->commonInfo();
const auto body = EventHandler::rawMessageBody(*roomMessageEvent);
// Do not attach the description to the image, if it's the same as the original filename.
if (fileInfo.originalName != body) {
QList<MessageComponent> components;
components += MessageComponent{type, QString(), {}};
components += TextHandler().textComponents(body,
EventHandler::messageBodyInputFormat(*roomMessageEvent),
m_room,
roomMessageEvent,
roomMessageEvent->isReplaced());
return components;
}
}
}
}
default:

View File

@@ -212,7 +212,7 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const
return room->displayName().toHtmlEscaped();
}
if (role == AvatarRole) {
return room->avatarMediaId();
return room->avatarMediaUrl();
}
if (role == CanonicalAliasRole) {
return room->canonicalAlias();

View File

@@ -324,7 +324,7 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
return room->displayName();
}
if (role == AvatarRole) {
return room->avatarMediaId();
return room->avatarMediaUrl();
}
if (role == CanonicalAliasRole) {
return room->canonicalAlias();

View File

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

View File

@@ -431,9 +431,9 @@ QDateTime NeoChatRoom::lastActiveTime()
return messageEvents().rbegin()->get()->originTimestamp();
}
QString NeoChatRoom::avatarMediaId() const
QUrl NeoChatRoom::avatarMediaUrl() const
{
if (const auto avatar = Room::avatarMediaId(); !avatar.isEmpty()) {
if (const auto avatar = Room::avatarUrl(); !avatar.isEmpty()) {
return avatar;
}
@@ -441,7 +441,7 @@ QString NeoChatRoom::avatarMediaId() const
const auto directChatMembers = this->directChatMembers();
for (const auto member : directChatMembers) {
if (member != localMember()) {
return member.avatarMediaId();
return member.avatarUrl();
}
}

View File

@@ -69,9 +69,9 @@ class NeoChatRoom : public Quotient::Room
Q_PROPERTY(bool readMarkerLoaded READ readMarkerLoaded NOTIFY readMarkerLoadedChanged)
/**
* @brief The avatar image to be used for the room.
* @brief The avatar image to be used for the room, as a mxc:// URL.
*/
Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged STORED false)
Q_PROPERTY(QUrl avatarMediaUrl READ avatarMediaUrl NOTIFY avatarChanged STORED false)
/**
* @brief Get a RoomMember object for the other person in a direct chat.
@@ -320,7 +320,7 @@ public:
[[nodiscard]] bool readMarkerLoaded() const;
[[nodiscard]] QString avatarMediaId() const;
[[nodiscard]] QUrl avatarMediaUrl() const;
NeochatRoomMember *directChatRemoteMember();

View File

@@ -153,15 +153,6 @@ QColor NeochatRoomMember::color() const
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()) {

View File

@@ -70,7 +70,6 @@ public:
int hue() const;
qreal hueF() const;
QColor color() const;
QString avatarMediaId() const;
QUrl avatarUrl() const;
Q_SIGNALS:

View File

@@ -27,7 +27,8 @@ QQC2.Menu {
text: "https://matrix.to/#/" + root.connection.localUser.id,
title: root.connection.localUser.displayName,
subtitle: root.connection.localUser.id,
avatarSource: root.connection.makeMediaUrl(root.connection.localUser.avatarUrl)
// Note: User::avatarUrl does not set user_id, and thus cannot be used directly here. Hence the makeMediaUrl.
avatarSource: root.connection.localUser.avatarUrl.toString().length > 0 ? root.connection.makeMediaUrl(root.connection.localUser.avatarUrl) : ""
});
if (typeof root.closeDialog === "function") {
root.closeDialog();

View File

@@ -125,7 +125,7 @@ Kirigami.Dialog {
width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
}
source: userDelegate.connection.localUser.avatarMediaId ? userDelegate.connection.makeMediaUrl("mxc://" + userDelegate.connection.localUser.avatarMediaId) : ""
source: userDelegate.connection.localUser.avatarUrl.toString().length > 0 ? userDelegate.connection.makeMediaUrl(userDelegate.connection.localUser.avatarUrl) : ""
name: userDelegate.connection.localUser.displayName ?? userDelegate.connection.localUser.id
}

View File

@@ -18,7 +18,7 @@ QQC2.ItemDelegate {
required property NeoChatRoom currentRoom
required property bool categoryVisible
required property string filterText
required property string avatar
required property url avatar
required property string displayName
topPadding: Kirigami.Units.largeSpacing
@@ -32,7 +32,7 @@ QQC2.ItemDelegate {
visible: root.categoryVisible || filterText.length > 0
contentItem: KirigamiComponents.Avatar {
source: root.avatar ? root.currentRoom.connection.makeMediaUrl("mxc://" + root.avatar) : ""
source: root.avatar
name: root.displayName
sourceSize {

View File

@@ -27,38 +27,17 @@ Loader {
Component {
id: regularMenu
QQC2.Menu {
QQC2.MenuItem {
text: room.isFavourite ? i18n("Remove from Favorites") : i18n("Add to Favorites")
icon.name: room.isFavourite ? "bookmark-remove" : "bookmark-new"
onTriggered: room.isFavourite ? room.removeTag("m.favourite") : room.addTag("m.favourite", 1.0)
}
QQC2.MenuItem {
text: room.isLowPriority ? i18n("Reprioritize") : i18n("Deprioritize")
icon.name: room.isLowPriority ? "arrow-up-symbolic" : "arrow-down-symbolic"
onTriggered: room.isLowPriority ? room.removeTag("m.lowpriority") : room.addTag("m.lowpriority", 1.0)
}
QQC2.MenuItem {
text: i18n("Mark as Read")
icon.name: "checkmark"
enabled: room.notificationCount > 0
onTriggered: room.markAllMessagesAsRead()
}
QQC2.MenuItem {
text: room.isDirectChat() ? i18nc("@action:inmenu", "Copy user's Matrix ID to Clipboard") : i18nc("@action:inmenu", "Copy Address to Clipboard")
icon.name: "edit-copy"
onTriggered: if (room.isDirectChat()) {
Clipboard.saveText(room.directChatRemoteMember.id);
} else if (room.canonicalAlias.length === 0) {
Clipboard.saveText(room.id);
} else {
Clipboard.saveText(room.canonicalAlias);
}
}
QQC2.MenuSeparator {}
QQC2.Menu {
title: i18n("Notification State")
title: i18nc("@action:inmenu", "Notifications")
icon.name: "notifications"
QQC2.MenuItem {
@@ -107,6 +86,32 @@ Loader {
}
}
QQC2.MenuItem {
text: room.isFavourite ? i18n("Remove from Favorites") : i18n("Add to Favorites")
icon.name: room.isFavourite ? "rating" : "rating-unrated"
onTriggered: room.isFavourite ? room.removeTag("m.favourite") : room.addTag("m.favourite", 1.0)
}
QQC2.MenuItem {
text: room.isLowPriority ? i18n("Reprioritize") : i18n("Deprioritize")
icon.name: room.isLowPriority ? "arrow-up-symbolic" : "arrow-down-symbolic"
onTriggered: room.isLowPriority ? room.removeTag("m.lowpriority") : room.addTag("m.lowpriority", 1.0)
}
QQC2.MenuSeparator {}
QQC2.MenuItem {
text: room.isDirectChat() ? i18nc("@action:inmenu", "Copy user's Matrix ID to Clipboard") : i18nc("@action:inmenu", "Copy Address to Clipboard")
icon.name: "edit-copy"
onTriggered: if (room.isDirectChat()) {
Clipboard.saveText(room.directChatRemoteMember.id);
} else if (room.canonicalAlias.length === 0) {
Clipboard.saveText(room.id);
} else {
Clipboard.saveText(room.canonicalAlias);
}
}
QQC2.MenuItem {
text: i18nc("@action:inmenu", "Room Settings")
icon.name: 'settings-configure-symbolic'
@@ -163,7 +168,7 @@ Loader {
spacing: Kirigami.Units.largeSpacing
KirigamiComponents.Avatar {
id: avatar
source: room.avatarMediaId ? root.connection.makeMediaUrl("mxc://" + room.avatarMediaId) : ""
source: room.avatarMediaUrl
name: room.displayName
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
Layout.preferredHeight: Kirigami.Units.gridUnit * 3

View File

@@ -5,6 +5,7 @@
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import Qt.labs.qmlmodels
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components as KirigamiComponents
import org.kde.kirigamiaddons.formcard as FormCard
@@ -177,10 +178,25 @@ Loader {
Repeater {
model: root.actions
QQC2.MenuItem {
visible: modelData.visible
action: modelData
onClicked: root.item.close()
DelegateChooser {
role: "separator"
DelegateChoice {
roleValue: true
QQC2.MenuSeparator {
visible: modelData.visible
}
}
DelegateChoice {
roleValue: false
QQC2.MenuItem {
visible: modelData.visible
action: modelData
onClicked: root.item.close()
}
}
}
}
QQC2.Menu {
@@ -341,15 +357,30 @@ Loader {
id: listViewAction
model: root.actions
FormCard.FormButtonDelegate {
icon.name: modelData.icon.name
icon.color: modelData.icon.color ?? undefined
enabled: modelData.enabled
visible: modelData.visible
text: modelData.text
onClicked: {
modelData.triggered();
root.item.close();
DelegateChooser {
role: "separator"
DelegateChoice {
roleValue: true
FormCard.FormDelegateSeparator {
visible: modelData.visible
}
}
DelegateChoice {
roleValue: false
FormCard.FormButtonDelegate {
icon.name: modelData.icon.name
icon.color: modelData.icon.color ?? undefined
enabled: modelData.enabled
visible: modelData.visible
text: modelData.text
onClicked: {
modelData.triggered();
root.item.close();
}
}
}
}
}

View File

@@ -38,7 +38,7 @@ ColumnLayout {
contentItem: KirigamiComponents.Avatar {
name: root.room ? root.room.displayName : ""
source: root.room ? root.room.connection.makeMediaUrl("mxc://" + root.room.avatarMediaId) : ""
source: root.room ? root.room.avatarMediaUrl : ""
Rectangle {
visible: root.room.usesEncryption

View File

@@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.neochat
QQC2.ScrollView {
id: root
QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
required property var model
property int currentIndex: 0
readonly property string category: root.model.data(root.model.index(root.currentIndex, 0), ImageContentPackRole.IdentifierRole)
implicitHeight: Kirigami.Units.iconSizes.large + root.QQC2.ScrollBar.horizontal.height
ListView {
id: categories
clip: true
focus: true
orientation: ListView.Horizontal
currentIndex: root.currentIndex
Keys.onReturnPressed: if (emojiGrid.count > 0) emojiGrid.focus = true
Keys.onEnterPressed: if (emojiGrid.count > 0) emojiGrid.focus = true
KeyNavigation.down: emojiGrid.count > 0 ? emojiGrid : categories
KeyNavigation.tab: emojiGrid.count > 0 ? emojiGrid : categories
keyNavigationEnabled: true
keyNavigationWraps: true
Keys.forwardTo: searchField
interactive: width !== contentWidth
Component.onCompleted: categories.forceActiveFocus()
model: root.model
delegate: EmojiDelegate {
id: packDelegate
required property string name
required property string i18nName
width: Kirigami.Units.iconSizes.large
height: width
checked: categories.currentIndex === model.index
toolTip: packDelegate.i18nName
text: packDelegate.name
onClicked: {
root.currentIndex = index;
}
}
}
}

View File

@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
Kirigami.NavigationTabBar {
id: root
enum EmoticonType {
Emoji,
Sticker
}
Kirigami.Theme.colorSet: Kirigami.Theme.View
property var selectedType: EmojiPickerTypeHeader.EmoticonType.Emoji
background: null
actions: [
Kirigami.Action {
id: emojis
icon.name: "smiley"
text: i18n("Emojis")
checked: root.selectedType === EmojiPickerTypeHeader.EmoticonType.Emoji
onTriggered: root.selectedType = EmojiPickerTypeHeader.EmoticonType.Emoji
},
Kirigami.Action {
id: stickers
icon.name: "stickers"
text: i18n("Stickers")
checked: root.selectedType === EmojiPickerTypeHeader.EmoticonType.Sticker
onTriggered: root.selectedType = EmojiPickerTypeHeader.EmoticonType.Sticker
}
]
}

View File

@@ -42,30 +42,36 @@ DelegateContextMenu {
* Each action will be instantiated as a single line in the menu.
*/
property list<Kirigami.Action> actions: [
DelegateContextMenu.ReplyMessageAction {},
Kirigami.Action {
text: i18n("Open Externally")
separator: true
},
Kirigami.Action {
text: i18nc("@action:inmenu", "Open Image")
icon.name: "document-open"
onTriggered: {
currentRoom.openEventMediaExternally(root.eventId);
}
},
Kirigami.Action {
text: i18n("Save As")
text: i18nc("@action:inmenu", "Save Image…")
icon.name: "document-save"
onTriggered: {
var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay);
dialog.selectedFile = currentRoom.fileNameToDownload(eventId);
dialog.open();
dialog.currentFile = dialog.folder + "/" + currentRoom.fileNameToDownload(eventId);
}
},
DelegateContextMenu.ReplyMessageAction {},
Kirigami.Action {
text: i18n("Copy")
text: i18nc("@action:inmenu", "Copy Image")
icon.name: "edit-copy"
onTriggered: {
currentRoom.copyEventMedia(root.eventId);
}
},
Kirigami.Action {
separator: true
},
Kirigami.Action {
visible: author.id === currentRoom.localMember.id || currentRoom.canSendState("redact")
text: i18n("Remove")
@@ -88,7 +94,13 @@ DelegateContextMenu {
},
DelegateContextMenu.ReportMessageAction {},
DelegateContextMenu.ShowUserAction {},
DelegateContextMenu.ViewSourceAction {}
Kirigami.Action {
separator: true
visible: viewSourceAction.visible
},
DelegateContextMenu.ViewSourceAction {
id: viewSourceAction
}
]
/**

View File

@@ -102,7 +102,7 @@ Labs.MenuBar {
}
Labs.MenuItem {
text: i18nc("menu", "About KDE")
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDE"))
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDEPage"))
}
}
}

View File

@@ -34,7 +34,7 @@ ColumnLayout {
Layout.preferredHeight: Kirigami.Units.iconSizes.large
name: root.room ? root.room.displayName : ""
source: root.room ? root.room.connection.makeMediaUrl("mxc://" + root.room.avatarMediaId) : ""
source: root.room ? root.room.avatarMediaUrl : ""
Rectangle {
visible: room.usesEncryption
@@ -75,6 +75,7 @@ ColumnLayout {
textFormat: TextEdit.PlainText
visible: root.room && root.room.canonicalAlias
text: root.room && root.room.canonicalAlias ? root.room.canonicalAlias : ""
color: Kirigami.Theme.disabledTextColor
}
}
QQC2.AbstractButton {
@@ -92,7 +93,7 @@ ColumnLayout {
text: barcode.content,
title: root.room ? root.room.displayName : "",
subtitle: root.room ? root.room.id : "",
avatarSource: root.room && root.room.avatarMediaId ? root.room.connection.makeMediaUrl("mxc://" + root.room.avatarMediaId) : ""
avatarSource: root.room ? root.room.avatarMediaUrl : ""
});
map.open();
}

View File

@@ -156,7 +156,6 @@ QQC2.Control {
EmojiDialog {
id: emojiDialog
currentRoom: root.currentRoom
showQuickReaction: true
onChosen: emoji => {
root.currentRoom.toggleReaction(root.delegate.eventId, emoji);
if (!Kirigami.Settings.isMobile) {

View File

@@ -7,7 +7,6 @@ import QtQuick.Layouts
import QtCore as Core
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
import org.kde.kquickimageeditor as KQuickImageEditor
Kirigami.Page {
@@ -168,10 +167,11 @@ Kirigami.Page {
}
}
footer: KirigamiComponents.Banner {
footer: Kirigami.InlineMessage {
id: msg
type: Kirigami.MessageType.Error
showCloseButton: true
visible: false
position: Kirigami.InlineMessage.Position.Header
}
}

View File

@@ -42,7 +42,6 @@ Kirigami.ApplicationWindow {
}
onConnectionChanged: {
CustomEmojiModel.connection = root.connection;
SpaceHierarchyCache.connection = root.connection;
NeoChatSettingsView.connection = root.connection;
if (ShareHandler.text && root.connection) {
@@ -176,7 +175,6 @@ Kirigami.ApplicationWindow {
}
Component.onCompleted: {
CustomEmojiModel.connection = root.connection;
SpaceHierarchyCache.connection = root.connection;
RoomSettingsView.window = root;
NeoChatSettingsView.window = root;

View File

@@ -44,7 +44,7 @@ DelegateContextMenu {
},
DelegateContextMenu.ReplyMessageAction {},
Kirigami.Action {
text: i18nc("@action:inmenu As in 'Forward this message'", "Forward")
text: i18nc("@action:inmenu As in 'Forward this message'", "Forward")
icon.name: "mail-forward-symbolic"
onTriggered: {
let page = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), {
@@ -59,21 +59,33 @@ DelegateContextMenu {
});
}
},
Kirigami.Action {
separator: true
},
DelegateContextMenu.RemoveMessageAction {},
Kirigami.Action {
text: i18n("Copy")
text: i18nc("@action:inmenu", "Copy Text")
icon.name: "edit-copy"
onTriggered: Clipboard.saveText(root.selectedText.length > 0 ? root.selectedText : root.plainText)
},
DelegateContextMenu.ReportMessageAction {},
DelegateContextMenu.ShowUserAction {},
DelegateContextMenu.ViewSourceAction {},
Kirigami.Action {
text: i18n("Copy Link")
text: i18nc("@action:inmenu", "Copy Message Link")
icon.name: "edit-copy"
onTriggered: {
Clipboard.saveText("https://matrix.to/#/" + currentRoom.id + "/" + root.eventId);
}
},
Kirigami.Action {
separator: true
},
DelegateContextMenu.ReportMessageAction {},
DelegateContextMenu.ShowUserAction {},
Kirigami.Action {
separator: true
visible: viewSourceAction.visible
},
DelegateContextMenu.ViewSourceAction {
id: viewSourceAction
}
]
}

View File

@@ -110,8 +110,8 @@ Components.AlbumMaximizeComponent {
onSaveItem: {
var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay);
dialog.selectedFile = currentRoom.fileNameToDownload(root.currentEventId);
dialog.open();
dialog.currentFile = dialog.folder + "/" + currentRoom.fileNameToDownload(root.currentEventId);
}
Connections {

View File

@@ -12,7 +12,7 @@ Components.AbstractMaximizeComponent {
required property string text
property color avatarColor
required property string avatarSource
required property url avatarSource
onOpened: forceActiveFocus()

37
src/qml/QuickReaction.qml Normal file
View File

@@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.neochat
QQC2.ScrollView {
id: root
signal chosen(string text)
QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
implicitHeight: Kirigami.Units.iconSizes.large + QQC2.ScrollBar.horizontal.height
ListView {
id: quickReactions
Layout.fillWidth: true
model: ["👍", "👎", "😄", "🎉", "😕", "❤", "🚀", "👀"]
delegate: EmojiDelegate {
height: Kirigami.Units.iconSizes.large
width: height
text: modelData
onClicked: root.chosen(modelData)
}
orientation: Qt.Horizontal
}
}

View File

@@ -30,9 +30,9 @@ Kirigami.Dialog {
FormCard.AbstractFormDelegate {
background: null
contentItem: RowLayout {
spacing: Kirigami.Units.largeSpacing * 4
spacing: Kirigami.Units.largeSpacing
Avatar {
source: root.connection.makeMediaUrl(SpaceHierarchyCache.recommendedSpaceAvatar)
source: SpaceHierarchyCache.recommendedSpaceAvatar.toString().length > 0 ? root.connection.makeMediaUrl(SpaceHierarchyCache.recommendedSpaceAvatar) : 0
name: SpaceHierarchyCache.recommendedSpaceDisplayName
}
ColumnLayout {
@@ -51,6 +51,7 @@ Kirigami.Dialog {
FormCard.FormDelegateSeparator {}
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "Join")
icon.name: "list-add-symbolic"
onClicked: {
SpaceHierarchyCache.recommendedSpaceHidden = true;
RoomManager.resolveResource(SpaceHierarchyCache.recommendedSpaceId, "join");
@@ -58,6 +59,7 @@ Kirigami.Dialog {
}
}
FormCard.FormButtonDelegate {
icon.name: "mail-thread-ignored-symbolic"
text: i18nc("@action:button", "Ignore")
onClicked: {
SpaceHierarchyCache.recommendedSpaceHidden = true;

View File

@@ -21,7 +21,7 @@ Delegates.RoundedItemDelegate {
required property bool hasHighlightNotifications
required property NeoChatRoom currentRoom
required property NeoChatConnection connection
required property string avatar
required property url avatar
required property string subtitleText
required property string displayName
@@ -55,7 +55,7 @@ Delegates.RoundedItemDelegate {
spacing: Kirigami.Units.largeSpacing
AvatarNotification {
source: root.avatar ? root.connection.makeMediaUrl("mxc://" + root.avatar) : ""
source: root.avatar
name: root.displayName
visible: NeoChatConfig.showAvatarInRoomDrawer
implicitHeight: Kirigami.Units.gridUnit + (NeoChatConfig.compactRoomList ? 0 : Kirigami.Units.largeSpacing * 2)

View File

@@ -99,8 +99,11 @@ Kirigami.OverlayDrawer {
Layout.preferredHeight: pageStack.globalToolBar.preferredHeight
contentItem: RowLayout {
spacing: 0
Kirigami.Heading {
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.largeSpacing
text: drawerItemLoader.item ? drawerItemLoader.item.title : ""
}

View File

@@ -39,7 +39,7 @@ QQC2.ScrollView {
/**
* @brief The title that should be displayed for this component if available.
*/
readonly property string title: root.room.isSpace ? i18nc("@action:title", "Space Members") : i18nc("@action:title", "Room information")
readonly property string title: root.room.isSpace ? i18nc("@action:title", "Space Members") : i18nc("@action:title", "Room Information")
// HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
@@ -133,7 +133,7 @@ QQC2.ScrollView {
Delegates.RoundedItemDelegate {
id: leaveButton
icon.name: "arrow-left-symbolic"
text: i18nc("@action:button", "Leave this room")
text: root.room.isSpace ? i18nc("@action:button", "Leave this space") : i18nc("@action:button", "Leave this room")
activeFocusOnTab: true
Layout.fillWidth: true
@@ -219,7 +219,7 @@ QQC2.ScrollView {
required property int index
required property string name
required property string userId
required property string avatar
required property url avatar
required property int powerLevel
required property string powerLevelString

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