Compare commits

..

1 Commits

Author SHA1 Message Date
Thiago Sueto
cfea50bc08 Make height of chatbar, userinfo bar and side tab bar the same 2024-11-15 13:32:52 -03:00
146 changed files with 12489 additions and 66599 deletions

View File

@@ -11,6 +11,7 @@
#include <qnamespace.h>
#include "enums/messagecomponenttype.h"
#include "models/customemojimodel.h"
#include "neochatconnection.h"
#include "testutils.h"
@@ -76,6 +77,7 @@ 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"));
}
@@ -533,7 +535,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,7 +59,6 @@
<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,20 +89,16 @@ 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-19 00:40+0000\n"
"POT-Creation-Date: 2024-11-13 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:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Send an encrypted message…"
msgstr ""
#: src/chatbar/ChatBar.qml:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Set an attachment caption…"
msgstr ""
#: src/chatbar/ChatBar.qml:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Send a message…"
msgstr ""
#: src/chatbar/ChatBar.qml:375
#: src/chatbar/ChatBar.qml:376
#, kde-format
msgctxt "@action:button"
msgid "Cancel reply"
msgstr ""
#: src/chatbar/EmojiGrid.qml:88
#: src/chatbar/EmojiGrid.qml:87
#, kde-format
msgid "No stickers"
msgstr ""
#: src/chatbar/EmojiGrid.qml:88
#: src/chatbar/EmojiGrid.qml:87
#, kde-format
msgid "No emojis"
msgstr ""
@@ -910,7 +910,7 @@ msgstr ""
msgid "Loading"
msgstr ""
#: src/login/Loading.qml:17
#: src/login/Loading.qml:16
#, 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:249
#: src/login/Login.qml:38 src/login/WelcomePage.qml:232
#: 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:154
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:152
#: src/settings/NetworkProxyPage.qml:122
#, kde-format
msgid "Password"
@@ -1030,47 +1030,47 @@ msgstr ""
msgid "Username unavailable"
msgstr ""
#: src/login/WelcomePage.qml:26
#: src/login/WelcomePage.qml:25
#, kde-format
msgid "Welcome"
msgstr ""
#: src/login/WelcomePage.qml:74 src/main.cpp:141
#: src/login/WelcomePage.qml:73 src/main.cpp:141
#, kde-format
msgid "NeoChat"
msgstr ""
#: src/login/WelcomePage.qml:82
#: src/login/WelcomePage.qml:81
#, kde-format
msgctxt "@title"
msgid "Continue with an existing account"
msgstr ""
#: src/login/WelcomePage.qml:132
#: src/login/WelcomePage.qml:115
#, kde-format
msgctxt "As in 'this account is still loading'"
msgid "%1 (loading)"
msgstr ""
#: src/login/WelcomePage.qml:141
#: src/login/WelcomePage.qml:124
#, kde-format
msgctxt "@action:button"
msgid "Log out of this account"
msgstr ""
#: src/login/WelcomePage.qml:170
#: src/login/WelcomePage.qml:153
#, kde-format
msgctxt "@title"
msgid "Log in or Create a New Account"
msgstr ""
#: src/login/WelcomePage.qml:257
#: src/login/WelcomePage.qml:240
#, kde-format
msgctxt "@action:button"
msgid "Go back"
msgstr ""
#: src/login/WelcomePage.qml:269
#: src/login/WelcomePage.qml:252
#, 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:111
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:110
#: 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:40 src/qml/UserInfo.qml:46
#: src/qml/AccountMenu.qml:39 src/qml/UserInfo.qml:46
#, kde-format
msgid "Edit this account"
msgstr ""
#: src/qml/AccountMenu.qml:45 src/settings/AccountsPage.qml:33
#: src/qml/AccountMenu.qml:44 src/settings/AccountsPage.qml:33
#: src/settings/AccountsPage.qml:50
#, kde-format
msgid "Account editor"
msgstr ""
#: src/qml/AccountMenu.qml:49
#: src/qml/AccountMenu.qml:48
#, kde-format
msgid "Notification settings"
msgstr ""
#: src/qml/AccountMenu.qml:56 src/settings/DevicesPage.qml:17
#: src/qml/AccountMenu.qml:55 src/settings/DevicesPage.qml:17
#: src/settings/NeoChatSettingsView.qml:89
#, kde-format
msgid "Devices"
msgstr ""
#: src/qml/AccountMenu.qml:63 src/settings/NeoChatGeneralPage.qml:269
#: src/qml/AccountMenu.qml:62 src/settings/NeoChatGeneralPage.qml:269
#, kde-format
msgid "Open developer tools"
msgstr ""
#: src/qml/AccountMenu.qml:69
#: src/qml/AccountMenu.qml:68
#, kde-format
msgctxt "@title:window"
msgid "Developer Tools"
msgstr ""
#: src/qml/AccountMenu.qml:75
#: src/qml/AccountMenu.qml:74
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Secret Backup"
msgstr ""
#: src/qml/AccountMenu.qml:79
#: src/qml/AccountMenu.qml:78
#, kde-format
msgctxt "@title:window"
msgid "Open Key Backup"
msgstr ""
#: src/qml/AccountMenu.qml:83
#: src/qml/AccountMenu.qml:82
#, kde-format
msgctxt "@action:inmenu"
msgid "Verify this Device"
msgstr ""
#: src/qml/AccountMenu.qml:89 src/settings/AccountsPage.qml:88
#: src/qml/AccountMenu.qml:88 src/settings/AccountsPage.qml:87
#, 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:20 src/qml/MessageDelegateContextMenu.qml:37
#: src/qml/ImageEditorPage.qml:21 src/qml/MessageDelegateContextMenu.qml:37
#, kde-format
msgid "Edit"
msgstr ""
@@ -2139,29 +2139,61 @@ msgctxt "@action:button"
msgid "Open"
msgstr ""
#: src/qml/ContextMenu.qml:31 src/qml/ContextMenu.qml:209
#: 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
#, kde-format
msgid "Mark as Read"
msgstr ""
#: src/qml/ContextMenu.qml:40
#: src/qml/ContextMenu.qml:49
#, kde-format
msgctxt "@action:inmenu"
msgid "Notifications"
msgid "Copy user's Matrix ID to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:44
#: 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
#, kde-format
msgid "Follow Global Setting"
msgstr ""
#: src/qml/ContextMenu.qml:55 src/settings/PushNotification.qml:39
#: src/qml/ContextMenu.qml:76 src/settings/PushNotification.qml:39
#, kde-format
msgctxt "As in 'notify for all messages'"
msgid "All"
msgstr ""
#: src/qml/ContextMenu.qml:66 src/settings/PushNotification.qml:47
#: src/qml/ContextMenu.qml:87 src/settings/PushNotification.qml:47
#, kde-format
msgctxt ""
"As in 'notify when the user is mentioned or the message contains a set "
@@ -2169,67 +2201,34 @@ msgctxt ""
msgid "@Mentions and Keywords"
msgstr ""
#: src/qml/ContextMenu.qml:77 src/settings/PushNotification.qml:55
#: src/qml/ContextMenu.qml:98 src/settings/PushNotification.qml:55
#, kde-format
msgctxt "As in 'do not notify for any messages'"
msgid "Off"
msgstr ""
#: 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
#: src/qml/ContextMenu.qml:111
#, kde-format
msgctxt "@action:inmenu"
msgid "Room Settings"
msgstr ""
#: src/qml/ContextMenu.qml:126 src/qml/ContextMenu.qml:216
#: src/qml/ContextMenu.qml:121 src/qml/ContextMenu.qml:211
#, kde-format
msgid "Leave Room"
msgstr ""
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:182
#, kde-format
msgid "Remove from Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:182
#, kde-format
msgid "Add to Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:192
#: src/qml/ContextMenu.qml:187
#, kde-format
msgctxt "@action:button"
msgid "Room Settings"
@@ -2352,74 +2351,74 @@ msgctxt "@action:button"
msgid "Ok"
msgstr ""
#: src/qml/DelegateContextMenu.qml:84
#: src/qml/DelegateContextMenu.qml:83
#, kde-format
msgid "View Source"
msgstr ""
#: src/qml/DelegateContextMenu.qml:91 src/settings/ThreePIdCard.qml:66
#: src/qml/DelegateContextMenu.qml:90 src/settings/ThreePIdCard.qml:66
#, kde-format
msgctxt "@action:button"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:96 src/qml/DelegateContextMenu.qml:101
#: src/qml/FileDelegateContextMenu.qml:82
#: src/qml/FileDelegateContextMenu.qml:87
#: src/qml/DelegateContextMenu.qml:95 src/qml/DelegateContextMenu.qml:100
#: src/qml/FileDelegateContextMenu.qml:76
#: src/qml/FileDelegateContextMenu.qml:81
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:83
#: src/qml/DelegateContextMenu.qml:96 src/qml/FileDelegateContextMenu.qml:77
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:98 src/qml/FileDelegateContextMenu.qml:84
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:78
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove this message'"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:121 src/qml/DelegateContextMenu.qml:129
#: src/qml/DelegateContextMenu.qml:120 src/qml/DelegateContextMenu.qml:128
#, kde-format
msgctxt ""
"@action:button 'Report' as in 'Report this event to the administrators'"
msgid "Report"
msgstr ""
#: src/qml/DelegateContextMenu.qml:126
#: src/qml/DelegateContextMenu.qml:125
#, kde-format
msgctxt "@title:dialog"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:127
#: src/qml/DelegateContextMenu.qml:126
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for reporting this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:131
#: src/qml/DelegateContextMenu.qml:130
#, kde-format
msgctxt "@title"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:141
#: src/qml/DelegateContextMenu.qml:140
#, kde-format
msgctxt "@action:inmenu"
msgid "Show User"
msgstr ""
#: src/qml/DelegateContextMenu.qml:204
#: src/qml/DelegateContextMenu.qml:188
#, kde-format
msgid "Search for '%1'"
msgstr ""
#: src/qml/DelegateContextMenu.qml:226
#: src/qml/DelegateContextMenu.qml:210
#, kde-format
msgid "Configure Web Shortcuts..."
msgstr ""
@@ -2614,25 +2613,23 @@ msgctxt "@info:label"
msgid "No public rooms found"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:50
#: src/qml/FileDelegateContextMenu.qml:46
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Image"
msgid "Open Externally"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:57
#: src/qml/FileDelegateContextMenu.qml:53
#, kde-format
msgctxt "@action:inmenu"
msgid "Save Image…"
msgid "Save As"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:66
#: src/qml/FileDelegateContextMenu.qml:63
#: src/qml/MessageDelegateContextMenu.qml:64
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Image"
msgid "Copy"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:77
#: src/qml/FileDelegateContextMenu.qml:71
#, kde-format
msgid "Remove"
msgstr ""
@@ -2782,55 +2779,55 @@ msgctxt "@info screenreader"
msgid "The currently selected link"
msgstr ""
#: src/qml/ImageEditorPage.qml:36
#: src/qml/ImageEditorPage.qml:37
#, kde-format
msgctxt "@action:button Undo modification"
msgid "Undo"
msgstr ""
#: src/qml/ImageEditorPage.qml:43
#: src/qml/ImageEditorPage.qml:44
#, kde-format
msgctxt "@action:button Accept image modification"
msgid "Accept"
msgstr ""
#: src/qml/ImageEditorPage.qml:51
#: src/qml/ImageEditorPage.qml:52
#, kde-format
msgid ""
"Unable to save file. Check if you have the correct permission to edit the "
"cache directory."
msgstr ""
#: src/qml/ImageEditorPage.qml:123
#: src/qml/ImageEditorPage.qml:124
#, kde-format
msgid "Cancel"
msgstr ""
#: src/qml/ImageEditorPage.qml:123 src/qml/ImageEditorPage.qml:139
#: src/qml/ImageEditorPage.qml:124 src/qml/ImageEditorPage.qml:140
#, kde-format
msgctxt "@action:button Crop an image"
msgid "Crop"
msgstr ""
#: src/qml/ImageEditorPage.qml:144
#: src/qml/ImageEditorPage.qml:145
#, kde-format
msgctxt "@action:button Rotate an image to the left"
msgid "Rotate left"
msgstr ""
#: src/qml/ImageEditorPage.qml:150
#: src/qml/ImageEditorPage.qml:151
#, kde-format
msgctxt "@action:button Rotate an image to the right"
msgid "Rotate right"
msgstr ""
#: src/qml/ImageEditorPage.qml:156
#: src/qml/ImageEditorPage.qml:157
#, kde-format
msgctxt "@action:button Mirror an image vertically"
msgid "Flip"
msgstr ""
#: src/qml/ImageEditorPage.qml:162
#: src/qml/ImageEditorPage.qml:163
#, kde-format
msgctxt "@action:button Mirror an image horizontally"
msgid "Mirror"
@@ -3058,7 +3055,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
@@ -3067,16 +3064,9 @@ 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
msgctxt "@action:inmenu"
msgid "Copy Message Link"
msgid "Copy Link"
msgstr ""
#: src/qml/MessageSourceSheet.qml:46
@@ -3171,7 +3161,7 @@ msgctxt "@action:button"
msgid "Join"
msgstr ""
#: src/qml/RecommendedSpaceDialog.qml:63
#: src/qml/RecommendedSpaceDialog.qml:61
#, kde-format
msgctxt "@action:button"
msgid "Ignore"
@@ -3205,18 +3195,18 @@ msgstr ""
msgid "Configure room"
msgstr ""
#: src/qml/RoomDrawer.qml:114 src/qml/RoomDrawerPage.qml:45
#: src/qml/RoomDrawer.qml:111 src/qml/RoomDrawerPage.qml:45
#, kde-format
msgctxt "@action:button"
msgid "Room settings"
msgstr ""
#: src/qml/RoomDrawer.qml:163 src/qml/RoomDrawerPage.qml:85
#: src/qml/RoomDrawer.qml:160 src/qml/RoomDrawerPage.qml:85
#, kde-format
msgid "Information"
msgstr ""
#: src/qml/RoomDrawer.qml:168 src/qml/RoomDrawerPage.qml:90
#: src/qml/RoomDrawer.qml:165 src/qml/RoomDrawerPage.qml:90
#, kde-format
msgid "Media"
msgstr ""
@@ -3230,7 +3220,7 @@ msgstr ""
#: src/qml/RoomInformation.qml:42
#, kde-format
msgctxt "@action:title"
msgid "Room Information"
msgid "Room information"
msgstr ""
#: src/qml/RoomInformation.qml:70
@@ -3271,12 +3261,6 @@ 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"
@@ -3348,7 +3332,7 @@ msgctxt "@action:title"
msgid "Room Media"
msgstr ""
#: src/qml/RoomPage.qml:92
#: src/qml/RoomPage.qml:93
#, kde-format
msgid "NeoChat is offline. Please check your network connection."
msgstr ""
@@ -3586,6 +3570,12 @@ 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
@@ -3639,7 +3629,7 @@ msgid_plural "%2 are typing"
msgstr[0] ""
msgstr[1] ""
#: src/qml/UnlockSSSSDialog.qml:16
#: src/qml/UnlockSSSSDialog.qml:17
#, kde-format
msgctxt "@title:window"
msgid "Load your encrypted messages"
@@ -3727,129 +3717,129 @@ msgctxt "@title:menu Account details dialog"
msgid "Account Details"
msgstr ""
#: src/qml/UserDetailDialog.qml:111
#: src/qml/UserDetailDialog.qml:109
#, kde-format
msgid "Unignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:111
#: src/qml/UserDetailDialog.qml:109
#, kde-format
msgid "Ignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:124
#: src/qml/UserDetailDialog.qml:122
#, kde-format
msgid "Kick this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:128 src/qml/UserDetailDialog.qml:133
#: src/qml/UserDetailDialog.qml:126 src/qml/UserDetailDialog.qml:131
#, kde-format
msgctxt "@title:dialog"
msgid "Kick User"
msgstr ""
#: src/qml/UserDetailDialog.qml:129
#: src/qml/UserDetailDialog.qml:127
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for kicking this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:130
#: src/qml/UserDetailDialog.qml:128
#, kde-format
msgctxt "@action:button 'Kick' as in 'Kick this user from the room'"
msgid "Kick"
msgstr ""
#: src/qml/UserDetailDialog.qml:149
#: src/qml/UserDetailDialog.qml:147
#, kde-format
msgid "Invite this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:162
#: src/qml/UserDetailDialog.qml:160
#, kde-format
msgid "Ban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:167 src/qml/UserDetailDialog.qml:172
#: src/qml/UserDetailDialog.qml:165 src/qml/UserDetailDialog.qml:170
#, kde-format
msgctxt "@title:dialog"
msgid "Ban User"
msgstr ""
#: src/qml/UserDetailDialog.qml:168
#: src/qml/UserDetailDialog.qml:166
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for banning this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:169
#: src/qml/UserDetailDialog.qml:167
#, kde-format
msgctxt "@action:button 'Ban' as in 'Ban this user'"
msgid "Ban"
msgstr ""
#: src/qml/UserDetailDialog.qml:187
#: src/qml/UserDetailDialog.qml:185
#, kde-format
msgid "Unban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:200
#: src/qml/UserDetailDialog.qml:198
#, kde-format
msgid "Set user power level"
msgstr ""
#: src/qml/UserDetailDialog.qml:225
#: src/qml/UserDetailDialog.qml:223
#, kde-format
msgctxt "@action:button"
msgid "Remove recent messages by this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:230
#: src/qml/UserDetailDialog.qml:228
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:231
#: src/qml/UserDetailDialog.qml:229
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this user's recent messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:232
#: src/qml/UserDetailDialog.qml:230
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove these messages'"
msgid "Remove"
msgstr ""
#: src/qml/UserDetailDialog.qml:235
#: src/qml/UserDetailDialog.qml:233
#, kde-format
msgctxt "@title"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:249
#: src/qml/UserDetailDialog.qml:247
#, kde-format
msgctxt "%1 is the name of the user."
msgid "Chat with %1"
msgstr ""
#: src/qml/UserDetailDialog.qml:249
#: src/qml/UserDetailDialog.qml:247
#, kde-format
msgid "Invite to private chat"
msgstr ""
#: src/qml/UserDetailDialog.qml:260
#: src/qml/UserDetailDialog.qml:258
#, kde-format
msgid "Copy link"
msgstr ""
#: src/qml/UserInfo.qml:92
#: src/qml/UserInfo.qml:91
#, kde-format
msgid "Switch User"
msgstr ""
#: src/qml/UserInfo.qml:101
#: src/qml/UserInfo.qml:100
#, kde-format
msgid "Open Settings"
msgstr ""
@@ -4067,7 +4057,7 @@ msgstr ""
msgid "Working"
msgstr ""
#: src/roommanager.cpp:145
#: src/roommanager.cpp:146
#, kde-format
msgid "Malformed or empty Matrix id<br />%1 is not a correct Matrix identifier"
msgstr ""
@@ -4092,126 +4082,126 @@ msgstr ""
msgid "Edit Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:62
#: src/settings/AccountEditorPage.qml:61
#, kde-format
msgid "Upload new avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:79
#: src/settings/AccountEditorPage.qml:78
#, kde-format
msgid "Remove current avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:102
#: src/settings/AccountEditorPage.qml:101
#, kde-format
msgid "User Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:107
#: src/settings/AccountEditorPage.qml:106
#, kde-format
msgid "Display Name:"
msgstr ""
#: src/settings/AccountEditorPage.qml:113
#: src/settings/AccountEditorPage.qml:112
#, kde-format
msgid "Label:"
msgstr ""
#: src/settings/AccountEditorPage.qml:114
#: src/settings/AccountEditorPage.qml:113
#, kde-format
msgid "Work"
msgstr ""
#: src/settings/AccountEditorPage.qml:119
#: src/settings/AccountEditorPage.qml:118
#, kde-format
msgctxt "@action:button"
msgid "Show QR Code"
msgstr ""
#: src/settings/AccountEditorPage.qml:137
#: src/settings/AccountEditorPage.qml:193
#: src/settings/AccountEditorPage.qml:135
#: src/settings/AccountEditorPage.qml:191
#: src/settings/EmoticonEditorPage.qml:108 src/settings/RoomGeneralPage.qml:98
#, kde-format
msgid "Save"
msgstr ""
#: src/settings/AccountEditorPage.qml:159
#: src/settings/AccountEditorPage.qml:157
#, kde-format
msgid "Your server doesn't support changing your password"
msgstr ""
#: src/settings/AccountEditorPage.qml:166
#: src/settings/AccountEditorPage.qml:164
#, kde-format
msgid "Current Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:173
#: src/settings/AccountEditorPage.qml:171
#, kde-format
msgid "New Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:180
#: src/settings/AccountEditorPage.qml:178
#, kde-format
msgid "Confirm new Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:185
#: src/settings/AccountEditorPage.qml:183
#, kde-format
msgid "Passwords don't match"
msgstr ""
#: src/settings/AccountEditorPage.qml:200
#: src/settings/AccountEditorPage.qml:198
#, kde-format
msgid "Passwords do not match"
msgstr ""
#: src/settings/AccountEditorPage.qml:207
#: src/settings/AccountEditorPage.qml:205
#, kde-format
msgid "Email Addresses"
msgstr ""
#: src/settings/AccountEditorPage.qml:213
#: src/settings/AccountEditorPage.qml:211
#, kde-format
msgid "Phone Numbers"
msgstr ""
#: src/settings/AccountEditorPage.qml:218
#: src/settings/AccountEditorPage.qml:216
#, kde-format
msgid "Identity Server"
msgstr ""
#: src/settings/AccountEditorPage.qml:227
#: src/settings/AccountEditorPage.qml:225
#, kde-format
msgid "Server Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:231
#: src/settings/AccountEditorPage.qml:229
#, kde-format
msgid "Homeserver url"
msgstr ""
#: src/settings/AccountEditorPage.qml:252
#: src/settings/AccountEditorPage.qml:250
#, kde-format
msgctxt "@title"
msgid "Account Management"
msgstr ""
#: src/settings/AccountEditorPage.qml:257
#: src/settings/AccountEditorPage.qml:255
#, kde-format
msgid "Deactivate Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:273
#: src/settings/AccountEditorPage.qml:271
#, kde-format
msgid "Password changed successfully"
msgstr ""
#: src/settings/AccountEditorPage.qml:275
#: src/settings/AccountEditorPage.qml:273
#, kde-format
msgid "Wrong password entered"
msgstr ""
#: src/settings/AccountEditorPage.qml:277
#: src/settings/AccountEditorPage.qml:275
#, kde-format
msgid "Unknown problem while trying to change password"
msgstr ""
@@ -4222,7 +4212,7 @@ msgstr ""
msgid "Accounts"
msgstr ""
#: src/settings/AccountsPage.qml:118
#: src/settings/AccountsPage.qml:117
#, kde-format
msgid "Add Account"
msgstr ""
@@ -4452,7 +4442,7 @@ msgctxt "@title"
msgid "Stickers & Emojis"
msgstr ""
#: src/settings/ExportKeysDialog.qml:17
#: src/settings/ExportKeysDialog.qml:18
#: src/settings/NeoChatSecurityPage.qml:107
#, kde-format
msgctxt "@title"
@@ -4601,7 +4591,7 @@ msgctxt "@action:button"
msgid "Unignore this user"
msgstr ""
#: src/settings/ImportKeysDialog.qml:21 src/settings/NeoChatSecurityPage.qml:84
#: src/settings/ImportKeysDialog.qml:22 src/settings/NeoChatSecurityPage.qml:84
#, kde-format
msgctxt "@title"
msgid "Import Keys"
@@ -4765,7 +4755,7 @@ msgctxt "@action:button"
msgid "Reset all configuration values to their default"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:18
#: src/settings/NeoChatSecurityPage.qml:19
#: 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-19 00:40+0000\n"
"POT-Creation-Date: 2024-11-13 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:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Send an encrypted message…"
msgstr ""
#: src/chatbar/ChatBar.qml:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Set an attachment caption…"
msgstr ""
#: src/chatbar/ChatBar.qml:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Send a message…"
msgstr ""
#: src/chatbar/ChatBar.qml:375
#: src/chatbar/ChatBar.qml:376
#, kde-format
msgctxt "@action:button"
msgid "Cancel reply"
msgstr ""
#: src/chatbar/EmojiGrid.qml:88
#: src/chatbar/EmojiGrid.qml:87
#, kde-format
msgid "No stickers"
msgstr ""
#: src/chatbar/EmojiGrid.qml:88
#: src/chatbar/EmojiGrid.qml:87
#, kde-format
msgid "No emojis"
msgstr ""
@@ -906,7 +906,7 @@ msgstr ""
msgid "Loading"
msgstr ""
#: src/login/Loading.qml:17
#: src/login/Loading.qml:16
#, 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:249
#: src/login/Login.qml:38 src/login/WelcomePage.qml:232
#: 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:154
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:152
#: src/settings/NetworkProxyPage.qml:122
#, kde-format
msgid "Password"
@@ -1026,47 +1026,47 @@ msgstr ""
msgid "Username unavailable"
msgstr ""
#: src/login/WelcomePage.qml:26
#: src/login/WelcomePage.qml:25
#, kde-format
msgid "Welcome"
msgstr ""
#: src/login/WelcomePage.qml:74 src/main.cpp:141
#: src/login/WelcomePage.qml:73 src/main.cpp:141
#, kde-format
msgid "NeoChat"
msgstr ""
#: src/login/WelcomePage.qml:82
#: src/login/WelcomePage.qml:81
#, kde-format
msgctxt "@title"
msgid "Continue with an existing account"
msgstr ""
#: src/login/WelcomePage.qml:132
#: src/login/WelcomePage.qml:115
#, kde-format
msgctxt "As in 'this account is still loading'"
msgid "%1 (loading)"
msgstr ""
#: src/login/WelcomePage.qml:141
#: src/login/WelcomePage.qml:124
#, kde-format
msgctxt "@action:button"
msgid "Log out of this account"
msgstr ""
#: src/login/WelcomePage.qml:170
#: src/login/WelcomePage.qml:153
#, kde-format
msgctxt "@title"
msgid "Log in or Create a New Account"
msgstr ""
#: src/login/WelcomePage.qml:257
#: src/login/WelcomePage.qml:240
#, kde-format
msgctxt "@action:button"
msgid "Go back"
msgstr ""
#: src/login/WelcomePage.qml:269
#: src/login/WelcomePage.qml:252
#, 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:111
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:110
#: 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:40 src/qml/UserInfo.qml:46
#: src/qml/AccountMenu.qml:39 src/qml/UserInfo.qml:46
#, kde-format
msgid "Edit this account"
msgstr ""
#: src/qml/AccountMenu.qml:45 src/settings/AccountsPage.qml:33
#: src/qml/AccountMenu.qml:44 src/settings/AccountsPage.qml:33
#: src/settings/AccountsPage.qml:50
#, kde-format
msgid "Account editor"
msgstr ""
#: src/qml/AccountMenu.qml:49
#: src/qml/AccountMenu.qml:48
#, kde-format
msgid "Notification settings"
msgstr ""
#: src/qml/AccountMenu.qml:56 src/settings/DevicesPage.qml:17
#: src/qml/AccountMenu.qml:55 src/settings/DevicesPage.qml:17
#: src/settings/NeoChatSettingsView.qml:89
#, kde-format
msgid "Devices"
msgstr ""
#: src/qml/AccountMenu.qml:63 src/settings/NeoChatGeneralPage.qml:269
#: src/qml/AccountMenu.qml:62 src/settings/NeoChatGeneralPage.qml:269
#, kde-format
msgid "Open developer tools"
msgstr ""
#: src/qml/AccountMenu.qml:69
#: src/qml/AccountMenu.qml:68
#, kde-format
msgctxt "@title:window"
msgid "Developer Tools"
msgstr ""
#: src/qml/AccountMenu.qml:75
#: src/qml/AccountMenu.qml:74
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Secret Backup"
msgstr ""
#: src/qml/AccountMenu.qml:79
#: src/qml/AccountMenu.qml:78
#, kde-format
msgctxt "@title:window"
msgid "Open Key Backup"
msgstr ""
#: src/qml/AccountMenu.qml:83
#: src/qml/AccountMenu.qml:82
#, kde-format
msgctxt "@action:inmenu"
msgid "Verify this Device"
msgstr ""
#: src/qml/AccountMenu.qml:89 src/settings/AccountsPage.qml:88
#: src/qml/AccountMenu.qml:88 src/settings/AccountsPage.qml:87
#, 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:20 src/qml/MessageDelegateContextMenu.qml:37
#: src/qml/ImageEditorPage.qml:21 src/qml/MessageDelegateContextMenu.qml:37
#, kde-format
msgid "Edit"
msgstr ""
@@ -2132,29 +2132,61 @@ msgctxt "@action:button"
msgid "Open"
msgstr ""
#: src/qml/ContextMenu.qml:31 src/qml/ContextMenu.qml:209
#: 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
#, kde-format
msgid "Mark as Read"
msgstr ""
#: src/qml/ContextMenu.qml:40
#: src/qml/ContextMenu.qml:49
#, kde-format
msgctxt "@action:inmenu"
msgid "Notifications"
msgid "Copy user's Matrix ID to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:44
#: 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
#, kde-format
msgid "Follow Global Setting"
msgstr ""
#: src/qml/ContextMenu.qml:55 src/settings/PushNotification.qml:39
#: src/qml/ContextMenu.qml:76 src/settings/PushNotification.qml:39
#, kde-format
msgctxt "As in 'notify for all messages'"
msgid "All"
msgstr ""
#: src/qml/ContextMenu.qml:66 src/settings/PushNotification.qml:47
#: src/qml/ContextMenu.qml:87 src/settings/PushNotification.qml:47
#, kde-format
msgctxt ""
"As in 'notify when the user is mentioned or the message contains a set "
@@ -2162,67 +2194,34 @@ msgctxt ""
msgid "@Mentions and Keywords"
msgstr ""
#: src/qml/ContextMenu.qml:77 src/settings/PushNotification.qml:55
#: src/qml/ContextMenu.qml:98 src/settings/PushNotification.qml:55
#, kde-format
msgctxt "As in 'do not notify for any messages'"
msgid "Off"
msgstr ""
#: 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
#: src/qml/ContextMenu.qml:111
#, kde-format
msgctxt "@action:inmenu"
msgid "Room Settings"
msgstr ""
#: src/qml/ContextMenu.qml:126 src/qml/ContextMenu.qml:216
#: src/qml/ContextMenu.qml:121 src/qml/ContextMenu.qml:211
#, kde-format
msgid "Leave Room"
msgstr ""
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:182
#, kde-format
msgid "Remove from Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:182
#, kde-format
msgid "Add to Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:192
#: src/qml/ContextMenu.qml:187
#, kde-format
msgctxt "@action:button"
msgid "Room Settings"
@@ -2345,74 +2344,74 @@ msgctxt "@action:button"
msgid "Ok"
msgstr ""
#: src/qml/DelegateContextMenu.qml:84
#: src/qml/DelegateContextMenu.qml:83
#, kde-format
msgid "View Source"
msgstr ""
#: src/qml/DelegateContextMenu.qml:91 src/settings/ThreePIdCard.qml:66
#: src/qml/DelegateContextMenu.qml:90 src/settings/ThreePIdCard.qml:66
#, kde-format
msgctxt "@action:button"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:96 src/qml/DelegateContextMenu.qml:101
#: src/qml/FileDelegateContextMenu.qml:82
#: src/qml/FileDelegateContextMenu.qml:87
#: src/qml/DelegateContextMenu.qml:95 src/qml/DelegateContextMenu.qml:100
#: src/qml/FileDelegateContextMenu.qml:76
#: src/qml/FileDelegateContextMenu.qml:81
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:83
#: src/qml/DelegateContextMenu.qml:96 src/qml/FileDelegateContextMenu.qml:77
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:98 src/qml/FileDelegateContextMenu.qml:84
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:78
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove this message'"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:121 src/qml/DelegateContextMenu.qml:129
#: src/qml/DelegateContextMenu.qml:120 src/qml/DelegateContextMenu.qml:128
#, kde-format
msgctxt ""
"@action:button 'Report' as in 'Report this event to the administrators'"
msgid "Report"
msgstr ""
#: src/qml/DelegateContextMenu.qml:126
#: src/qml/DelegateContextMenu.qml:125
#, kde-format
msgctxt "@title:dialog"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:127
#: src/qml/DelegateContextMenu.qml:126
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for reporting this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:131
#: src/qml/DelegateContextMenu.qml:130
#, kde-format
msgctxt "@title"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:141
#: src/qml/DelegateContextMenu.qml:140
#, kde-format
msgctxt "@action:inmenu"
msgid "Show User"
msgstr ""
#: src/qml/DelegateContextMenu.qml:204
#: src/qml/DelegateContextMenu.qml:188
#, kde-format
msgid "Search for '%1'"
msgstr ""
#: src/qml/DelegateContextMenu.qml:226
#: src/qml/DelegateContextMenu.qml:210
#, kde-format
msgid "Configure Web Shortcuts..."
msgstr ""
@@ -2607,25 +2606,23 @@ msgctxt "@info:label"
msgid "No public rooms found"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:50
#: src/qml/FileDelegateContextMenu.qml:46
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Image"
msgid "Open Externally"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:57
#: src/qml/FileDelegateContextMenu.qml:53
#, kde-format
msgctxt "@action:inmenu"
msgid "Save Image…"
msgid "Save As"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:66
#: src/qml/FileDelegateContextMenu.qml:63
#: src/qml/MessageDelegateContextMenu.qml:64
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Image"
msgid "Copy"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:77
#: src/qml/FileDelegateContextMenu.qml:71
#, kde-format
msgid "Remove"
msgstr ""
@@ -2775,55 +2772,55 @@ msgctxt "@info screenreader"
msgid "The currently selected link"
msgstr ""
#: src/qml/ImageEditorPage.qml:36
#: src/qml/ImageEditorPage.qml:37
#, kde-format
msgctxt "@action:button Undo modification"
msgid "Undo"
msgstr ""
#: src/qml/ImageEditorPage.qml:43
#: src/qml/ImageEditorPage.qml:44
#, kde-format
msgctxt "@action:button Accept image modification"
msgid "Accept"
msgstr ""
#: src/qml/ImageEditorPage.qml:51
#: src/qml/ImageEditorPage.qml:52
#, kde-format
msgid ""
"Unable to save file. Check if you have the correct permission to edit the "
"cache directory."
msgstr ""
#: src/qml/ImageEditorPage.qml:123
#: src/qml/ImageEditorPage.qml:124
#, kde-format
msgid "Cancel"
msgstr ""
#: src/qml/ImageEditorPage.qml:123 src/qml/ImageEditorPage.qml:139
#: src/qml/ImageEditorPage.qml:124 src/qml/ImageEditorPage.qml:140
#, kde-format
msgctxt "@action:button Crop an image"
msgid "Crop"
msgstr ""
#: src/qml/ImageEditorPage.qml:144
#: src/qml/ImageEditorPage.qml:145
#, kde-format
msgctxt "@action:button Rotate an image to the left"
msgid "Rotate left"
msgstr ""
#: src/qml/ImageEditorPage.qml:150
#: src/qml/ImageEditorPage.qml:151
#, kde-format
msgctxt "@action:button Rotate an image to the right"
msgid "Rotate right"
msgstr ""
#: src/qml/ImageEditorPage.qml:156
#: src/qml/ImageEditorPage.qml:157
#, kde-format
msgctxt "@action:button Mirror an image vertically"
msgid "Flip"
msgstr ""
#: src/qml/ImageEditorPage.qml:162
#: src/qml/ImageEditorPage.qml:163
#, kde-format
msgctxt "@action:button Mirror an image horizontally"
msgid "Mirror"
@@ -3051,7 +3048,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
@@ -3060,16 +3057,9 @@ 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
msgctxt "@action:inmenu"
msgid "Copy Message Link"
msgid "Copy Link"
msgstr ""
#: src/qml/MessageSourceSheet.qml:46
@@ -3164,7 +3154,7 @@ msgctxt "@action:button"
msgid "Join"
msgstr ""
#: src/qml/RecommendedSpaceDialog.qml:63
#: src/qml/RecommendedSpaceDialog.qml:61
#, kde-format
msgctxt "@action:button"
msgid "Ignore"
@@ -3198,18 +3188,18 @@ msgstr ""
msgid "Configure room"
msgstr ""
#: src/qml/RoomDrawer.qml:114 src/qml/RoomDrawerPage.qml:45
#: src/qml/RoomDrawer.qml:111 src/qml/RoomDrawerPage.qml:45
#, kde-format
msgctxt "@action:button"
msgid "Room settings"
msgstr ""
#: src/qml/RoomDrawer.qml:163 src/qml/RoomDrawerPage.qml:85
#: src/qml/RoomDrawer.qml:160 src/qml/RoomDrawerPage.qml:85
#, kde-format
msgid "Information"
msgstr ""
#: src/qml/RoomDrawer.qml:168 src/qml/RoomDrawerPage.qml:90
#: src/qml/RoomDrawer.qml:165 src/qml/RoomDrawerPage.qml:90
#, kde-format
msgid "Media"
msgstr ""
@@ -3223,7 +3213,7 @@ msgstr ""
#: src/qml/RoomInformation.qml:42
#, kde-format
msgctxt "@action:title"
msgid "Room Information"
msgid "Room information"
msgstr ""
#: src/qml/RoomInformation.qml:70
@@ -3264,12 +3254,6 @@ 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"
@@ -3340,7 +3324,7 @@ msgctxt "@action:title"
msgid "Room Media"
msgstr ""
#: src/qml/RoomPage.qml:92
#: src/qml/RoomPage.qml:93
#, kde-format
msgid "NeoChat is offline. Please check your network connection."
msgstr ""
@@ -3576,6 +3560,12 @@ 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
@@ -3628,7 +3618,7 @@ msgid "%2 is typing"
msgid_plural "%2 are typing"
msgstr[0] ""
#: src/qml/UnlockSSSSDialog.qml:16
#: src/qml/UnlockSSSSDialog.qml:17
#, kde-format
msgctxt "@title:window"
msgid "Load your encrypted messages"
@@ -3716,129 +3706,129 @@ msgctxt "@title:menu Account details dialog"
msgid "Account Details"
msgstr ""
#: src/qml/UserDetailDialog.qml:111
#: src/qml/UserDetailDialog.qml:109
#, kde-format
msgid "Unignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:111
#: src/qml/UserDetailDialog.qml:109
#, kde-format
msgid "Ignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:124
#: src/qml/UserDetailDialog.qml:122
#, kde-format
msgid "Kick this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:128 src/qml/UserDetailDialog.qml:133
#: src/qml/UserDetailDialog.qml:126 src/qml/UserDetailDialog.qml:131
#, kde-format
msgctxt "@title:dialog"
msgid "Kick User"
msgstr ""
#: src/qml/UserDetailDialog.qml:129
#: src/qml/UserDetailDialog.qml:127
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for kicking this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:130
#: src/qml/UserDetailDialog.qml:128
#, kde-format
msgctxt "@action:button 'Kick' as in 'Kick this user from the room'"
msgid "Kick"
msgstr ""
#: src/qml/UserDetailDialog.qml:149
#: src/qml/UserDetailDialog.qml:147
#, kde-format
msgid "Invite this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:162
#: src/qml/UserDetailDialog.qml:160
#, kde-format
msgid "Ban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:167 src/qml/UserDetailDialog.qml:172
#: src/qml/UserDetailDialog.qml:165 src/qml/UserDetailDialog.qml:170
#, kde-format
msgctxt "@title:dialog"
msgid "Ban User"
msgstr ""
#: src/qml/UserDetailDialog.qml:168
#: src/qml/UserDetailDialog.qml:166
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for banning this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:169
#: src/qml/UserDetailDialog.qml:167
#, kde-format
msgctxt "@action:button 'Ban' as in 'Ban this user'"
msgid "Ban"
msgstr ""
#: src/qml/UserDetailDialog.qml:187
#: src/qml/UserDetailDialog.qml:185
#, kde-format
msgid "Unban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:200
#: src/qml/UserDetailDialog.qml:198
#, kde-format
msgid "Set user power level"
msgstr ""
#: src/qml/UserDetailDialog.qml:225
#: src/qml/UserDetailDialog.qml:223
#, kde-format
msgctxt "@action:button"
msgid "Remove recent messages by this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:230
#: src/qml/UserDetailDialog.qml:228
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:231
#: src/qml/UserDetailDialog.qml:229
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this user's recent messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:232
#: src/qml/UserDetailDialog.qml:230
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove these messages'"
msgid "Remove"
msgstr ""
#: src/qml/UserDetailDialog.qml:235
#: src/qml/UserDetailDialog.qml:233
#, kde-format
msgctxt "@title"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:249
#: src/qml/UserDetailDialog.qml:247
#, kde-format
msgctxt "%1 is the name of the user."
msgid "Chat with %1"
msgstr ""
#: src/qml/UserDetailDialog.qml:249
#: src/qml/UserDetailDialog.qml:247
#, kde-format
msgid "Invite to private chat"
msgstr ""
#: src/qml/UserDetailDialog.qml:260
#: src/qml/UserDetailDialog.qml:258
#, kde-format
msgid "Copy link"
msgstr ""
#: src/qml/UserInfo.qml:92
#: src/qml/UserInfo.qml:91
#, kde-format
msgid "Switch User"
msgstr ""
#: src/qml/UserInfo.qml:101
#: src/qml/UserInfo.qml:100
#, kde-format
msgid "Open Settings"
msgstr ""
@@ -4056,7 +4046,7 @@ msgstr ""
msgid "Working"
msgstr ""
#: src/roommanager.cpp:145
#: src/roommanager.cpp:146
#, kde-format
msgid "Malformed or empty Matrix id<br />%1 is not a correct Matrix identifier"
msgstr ""
@@ -4081,126 +4071,126 @@ msgstr ""
msgid "Edit Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:62
#: src/settings/AccountEditorPage.qml:61
#, kde-format
msgid "Upload new avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:79
#: src/settings/AccountEditorPage.qml:78
#, kde-format
msgid "Remove current avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:102
#: src/settings/AccountEditorPage.qml:101
#, kde-format
msgid "User Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:107
#: src/settings/AccountEditorPage.qml:106
#, kde-format
msgid "Display Name:"
msgstr ""
#: src/settings/AccountEditorPage.qml:113
#: src/settings/AccountEditorPage.qml:112
#, kde-format
msgid "Label:"
msgstr ""
#: src/settings/AccountEditorPage.qml:114
#: src/settings/AccountEditorPage.qml:113
#, kde-format
msgid "Work"
msgstr ""
#: src/settings/AccountEditorPage.qml:119
#: src/settings/AccountEditorPage.qml:118
#, kde-format
msgctxt "@action:button"
msgid "Show QR Code"
msgstr ""
#: src/settings/AccountEditorPage.qml:137
#: src/settings/AccountEditorPage.qml:193
#: src/settings/AccountEditorPage.qml:135
#: src/settings/AccountEditorPage.qml:191
#: src/settings/EmoticonEditorPage.qml:108 src/settings/RoomGeneralPage.qml:98
#, kde-format
msgid "Save"
msgstr ""
#: src/settings/AccountEditorPage.qml:159
#: src/settings/AccountEditorPage.qml:157
#, kde-format
msgid "Your server doesn't support changing your password"
msgstr ""
#: src/settings/AccountEditorPage.qml:166
#: src/settings/AccountEditorPage.qml:164
#, kde-format
msgid "Current Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:173
#: src/settings/AccountEditorPage.qml:171
#, kde-format
msgid "New Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:180
#: src/settings/AccountEditorPage.qml:178
#, kde-format
msgid "Confirm new Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:185
#: src/settings/AccountEditorPage.qml:183
#, kde-format
msgid "Passwords don't match"
msgstr ""
#: src/settings/AccountEditorPage.qml:200
#: src/settings/AccountEditorPage.qml:198
#, kde-format
msgid "Passwords do not match"
msgstr ""
#: src/settings/AccountEditorPage.qml:207
#: src/settings/AccountEditorPage.qml:205
#, kde-format
msgid "Email Addresses"
msgstr ""
#: src/settings/AccountEditorPage.qml:213
#: src/settings/AccountEditorPage.qml:211
#, kde-format
msgid "Phone Numbers"
msgstr ""
#: src/settings/AccountEditorPage.qml:218
#: src/settings/AccountEditorPage.qml:216
#, kde-format
msgid "Identity Server"
msgstr ""
#: src/settings/AccountEditorPage.qml:227
#: src/settings/AccountEditorPage.qml:225
#, kde-format
msgid "Server Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:231
#: src/settings/AccountEditorPage.qml:229
#, kde-format
msgid "Homeserver url"
msgstr ""
#: src/settings/AccountEditorPage.qml:252
#: src/settings/AccountEditorPage.qml:250
#, kde-format
msgctxt "@title"
msgid "Account Management"
msgstr ""
#: src/settings/AccountEditorPage.qml:257
#: src/settings/AccountEditorPage.qml:255
#, kde-format
msgid "Deactivate Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:273
#: src/settings/AccountEditorPage.qml:271
#, kde-format
msgid "Password changed successfully"
msgstr ""
#: src/settings/AccountEditorPage.qml:275
#: src/settings/AccountEditorPage.qml:273
#, kde-format
msgid "Wrong password entered"
msgstr ""
#: src/settings/AccountEditorPage.qml:277
#: src/settings/AccountEditorPage.qml:275
#, kde-format
msgid "Unknown problem while trying to change password"
msgstr ""
@@ -4211,7 +4201,7 @@ msgstr ""
msgid "Accounts"
msgstr ""
#: src/settings/AccountsPage.qml:118
#: src/settings/AccountsPage.qml:117
#, kde-format
msgid "Add Account"
msgstr ""
@@ -4441,7 +4431,7 @@ msgctxt "@title"
msgid "Stickers & Emojis"
msgstr ""
#: src/settings/ExportKeysDialog.qml:17
#: src/settings/ExportKeysDialog.qml:18
#: src/settings/NeoChatSecurityPage.qml:107
#, kde-format
msgctxt "@title"
@@ -4590,7 +4580,7 @@ msgctxt "@action:button"
msgid "Unignore this user"
msgstr ""
#: src/settings/ImportKeysDialog.qml:21 src/settings/NeoChatSecurityPage.qml:84
#: src/settings/ImportKeysDialog.qml:22 src/settings/NeoChatSecurityPage.qml:84
#, kde-format
msgctxt "@title"
msgid "Import Keys"
@@ -4754,7 +4744,7 @@ msgctxt "@action:button"
msgid "Reset all configuration values to their default"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:18
#: src/settings/NeoChatSecurityPage.qml:19
#: 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-19 00:40+0000\n"
"POT-Creation-Date: 2024-11-13 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:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Send an encrypted message…"
msgstr ""
#: src/chatbar/ChatBar.qml:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Set an attachment caption…"
msgstr ""
#: src/chatbar/ChatBar.qml:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Send a message…"
msgstr ""
#: src/chatbar/ChatBar.qml:375
#: src/chatbar/ChatBar.qml:376
#, kde-format
msgctxt "@action:button"
msgid "Cancel reply"
msgstr ""
#: src/chatbar/EmojiGrid.qml:88
#: src/chatbar/EmojiGrid.qml:87
#, kde-format
msgid "No stickers"
msgstr ""
#: src/chatbar/EmojiGrid.qml:88
#: src/chatbar/EmojiGrid.qml:87
#, kde-format
msgid "No emojis"
msgstr ""
@@ -913,7 +913,7 @@ msgstr ""
msgid "Loading"
msgstr ""
#: src/login/Loading.qml:17
#: src/login/Loading.qml:16
#, 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:249
#: src/login/Login.qml:38 src/login/WelcomePage.qml:232
#: 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:154
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:152
#: src/settings/NetworkProxyPage.qml:122
#, kde-format
msgid "Password"
@@ -1033,47 +1033,47 @@ msgstr ""
msgid "Username unavailable"
msgstr ""
#: src/login/WelcomePage.qml:26
#: src/login/WelcomePage.qml:25
#, kde-format
msgid "Welcome"
msgstr ""
#: src/login/WelcomePage.qml:74 src/main.cpp:141
#: src/login/WelcomePage.qml:73 src/main.cpp:141
#, kde-format
msgid "NeoChat"
msgstr ""
#: src/login/WelcomePage.qml:82
#: src/login/WelcomePage.qml:81
#, kde-format
msgctxt "@title"
msgid "Continue with an existing account"
msgstr ""
#: src/login/WelcomePage.qml:132
#: src/login/WelcomePage.qml:115
#, kde-format
msgctxt "As in 'this account is still loading'"
msgid "%1 (loading)"
msgstr ""
#: src/login/WelcomePage.qml:141
#: src/login/WelcomePage.qml:124
#, kde-format
msgctxt "@action:button"
msgid "Log out of this account"
msgstr ""
#: src/login/WelcomePage.qml:170
#: src/login/WelcomePage.qml:153
#, kde-format
msgctxt "@title"
msgid "Log in or Create a New Account"
msgstr ""
#: src/login/WelcomePage.qml:257
#: src/login/WelcomePage.qml:240
#, kde-format
msgctxt "@action:button"
msgid "Go back"
msgstr ""
#: src/login/WelcomePage.qml:269
#: src/login/WelcomePage.qml:252
#, 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:111
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:110
#: 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:40 src/qml/UserInfo.qml:46
#: src/qml/AccountMenu.qml:39 src/qml/UserInfo.qml:46
#, kde-format
msgid "Edit this account"
msgstr ""
#: src/qml/AccountMenu.qml:45 src/settings/AccountsPage.qml:33
#: src/qml/AccountMenu.qml:44 src/settings/AccountsPage.qml:33
#: src/settings/AccountsPage.qml:50
#, kde-format
msgid "Account editor"
msgstr ""
#: src/qml/AccountMenu.qml:49
#: src/qml/AccountMenu.qml:48
#, kde-format
msgid "Notification settings"
msgstr ""
#: src/qml/AccountMenu.qml:56 src/settings/DevicesPage.qml:17
#: src/qml/AccountMenu.qml:55 src/settings/DevicesPage.qml:17
#: src/settings/NeoChatSettingsView.qml:89
#, kde-format
msgid "Devices"
msgstr ""
#: src/qml/AccountMenu.qml:63 src/settings/NeoChatGeneralPage.qml:269
#: src/qml/AccountMenu.qml:62 src/settings/NeoChatGeneralPage.qml:269
#, kde-format
msgid "Open developer tools"
msgstr ""
#: src/qml/AccountMenu.qml:69
#: src/qml/AccountMenu.qml:68
#, kde-format
msgctxt "@title:window"
msgid "Developer Tools"
msgstr ""
#: src/qml/AccountMenu.qml:75
#: src/qml/AccountMenu.qml:74
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Secret Backup"
msgstr ""
#: src/qml/AccountMenu.qml:79
#: src/qml/AccountMenu.qml:78
#, kde-format
msgctxt "@title:window"
msgid "Open Key Backup"
msgstr ""
#: src/qml/AccountMenu.qml:83
#: src/qml/AccountMenu.qml:82
#, kde-format
msgctxt "@action:inmenu"
msgid "Verify this Device"
msgstr ""
#: src/qml/AccountMenu.qml:89 src/settings/AccountsPage.qml:88
#: src/qml/AccountMenu.qml:88 src/settings/AccountsPage.qml:87
#, 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:20 src/qml/MessageDelegateContextMenu.qml:37
#: src/qml/ImageEditorPage.qml:21 src/qml/MessageDelegateContextMenu.qml:37
#, kde-format
msgid "Edit"
msgstr ""
@@ -2146,29 +2146,61 @@ msgctxt "@action:button"
msgid "Open"
msgstr ""
#: src/qml/ContextMenu.qml:31 src/qml/ContextMenu.qml:209
#: 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
#, kde-format
msgid "Mark as Read"
msgstr ""
#: src/qml/ContextMenu.qml:40
#: src/qml/ContextMenu.qml:49
#, kde-format
msgctxt "@action:inmenu"
msgid "Notifications"
msgid "Copy user's Matrix ID to Clipboard"
msgstr ""
#: src/qml/ContextMenu.qml:44
#: 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
#, kde-format
msgid "Follow Global Setting"
msgstr ""
#: src/qml/ContextMenu.qml:55 src/settings/PushNotification.qml:39
#: src/qml/ContextMenu.qml:76 src/settings/PushNotification.qml:39
#, kde-format
msgctxt "As in 'notify for all messages'"
msgid "All"
msgstr ""
#: src/qml/ContextMenu.qml:66 src/settings/PushNotification.qml:47
#: src/qml/ContextMenu.qml:87 src/settings/PushNotification.qml:47
#, kde-format
msgctxt ""
"As in 'notify when the user is mentioned or the message contains a set "
@@ -2176,67 +2208,34 @@ msgctxt ""
msgid "@Mentions and Keywords"
msgstr ""
#: src/qml/ContextMenu.qml:77 src/settings/PushNotification.qml:55
#: src/qml/ContextMenu.qml:98 src/settings/PushNotification.qml:55
#, kde-format
msgctxt "As in 'do not notify for any messages'"
msgid "Off"
msgstr ""
#: 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
#: src/qml/ContextMenu.qml:111
#, kde-format
msgctxt "@action:inmenu"
msgid "Room Settings"
msgstr ""
#: src/qml/ContextMenu.qml:126 src/qml/ContextMenu.qml:216
#: src/qml/ContextMenu.qml:121 src/qml/ContextMenu.qml:211
#, kde-format
msgid "Leave Room"
msgstr ""
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:182
#, kde-format
msgid "Remove from Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:182
#, kde-format
msgid "Add to Favourites"
msgstr ""
#: src/qml/ContextMenu.qml:192
#: src/qml/ContextMenu.qml:187
#, kde-format
msgctxt "@action:button"
msgid "Room Settings"
@@ -2359,74 +2358,74 @@ msgctxt "@action:button"
msgid "Ok"
msgstr ""
#: src/qml/DelegateContextMenu.qml:84
#: src/qml/DelegateContextMenu.qml:83
#, kde-format
msgid "View Source"
msgstr ""
#: src/qml/DelegateContextMenu.qml:91 src/settings/ThreePIdCard.qml:66
#: src/qml/DelegateContextMenu.qml:90 src/settings/ThreePIdCard.qml:66
#, kde-format
msgctxt "@action:button"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:96 src/qml/DelegateContextMenu.qml:101
#: src/qml/FileDelegateContextMenu.qml:82
#: src/qml/FileDelegateContextMenu.qml:87
#: src/qml/DelegateContextMenu.qml:95 src/qml/DelegateContextMenu.qml:100
#: src/qml/FileDelegateContextMenu.qml:76
#: src/qml/FileDelegateContextMenu.qml:81
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:83
#: src/qml/DelegateContextMenu.qml:96 src/qml/FileDelegateContextMenu.qml:77
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:98 src/qml/FileDelegateContextMenu.qml:84
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:78
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove this message'"
msgid "Remove"
msgstr ""
#: src/qml/DelegateContextMenu.qml:121 src/qml/DelegateContextMenu.qml:129
#: src/qml/DelegateContextMenu.qml:120 src/qml/DelegateContextMenu.qml:128
#, kde-format
msgctxt ""
"@action:button 'Report' as in 'Report this event to the administrators'"
msgid "Report"
msgstr ""
#: src/qml/DelegateContextMenu.qml:126
#: src/qml/DelegateContextMenu.qml:125
#, kde-format
msgctxt "@title:dialog"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:127
#: src/qml/DelegateContextMenu.qml:126
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for reporting this message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:131
#: src/qml/DelegateContextMenu.qml:130
#, kde-format
msgctxt "@title"
msgid "Report Message"
msgstr ""
#: src/qml/DelegateContextMenu.qml:141
#: src/qml/DelegateContextMenu.qml:140
#, kde-format
msgctxt "@action:inmenu"
msgid "Show User"
msgstr ""
#: src/qml/DelegateContextMenu.qml:204
#: src/qml/DelegateContextMenu.qml:188
#, kde-format
msgid "Search for '%1'"
msgstr ""
#: src/qml/DelegateContextMenu.qml:226
#: src/qml/DelegateContextMenu.qml:210
#, kde-format
msgid "Configure Web Shortcuts..."
msgstr ""
@@ -2621,25 +2620,23 @@ msgctxt "@info:label"
msgid "No public rooms found"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:50
#: src/qml/FileDelegateContextMenu.qml:46
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Image"
msgid "Open Externally"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:57
#: src/qml/FileDelegateContextMenu.qml:53
#, kde-format
msgctxt "@action:inmenu"
msgid "Save Image…"
msgid "Save As"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:66
#: src/qml/FileDelegateContextMenu.qml:63
#: src/qml/MessageDelegateContextMenu.qml:64
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Image"
msgid "Copy"
msgstr ""
#: src/qml/FileDelegateContextMenu.qml:77
#: src/qml/FileDelegateContextMenu.qml:71
#, kde-format
msgid "Remove"
msgstr ""
@@ -2789,55 +2786,55 @@ msgctxt "@info screenreader"
msgid "The currently selected link"
msgstr ""
#: src/qml/ImageEditorPage.qml:36
#: src/qml/ImageEditorPage.qml:37
#, kde-format
msgctxt "@action:button Undo modification"
msgid "Undo"
msgstr ""
#: src/qml/ImageEditorPage.qml:43
#: src/qml/ImageEditorPage.qml:44
#, kde-format
msgctxt "@action:button Accept image modification"
msgid "Accept"
msgstr ""
#: src/qml/ImageEditorPage.qml:51
#: src/qml/ImageEditorPage.qml:52
#, kde-format
msgid ""
"Unable to save file. Check if you have the correct permission to edit the "
"cache directory."
msgstr ""
#: src/qml/ImageEditorPage.qml:123
#: src/qml/ImageEditorPage.qml:124
#, kde-format
msgid "Cancel"
msgstr ""
#: src/qml/ImageEditorPage.qml:123 src/qml/ImageEditorPage.qml:139
#: src/qml/ImageEditorPage.qml:124 src/qml/ImageEditorPage.qml:140
#, kde-format
msgctxt "@action:button Crop an image"
msgid "Crop"
msgstr ""
#: src/qml/ImageEditorPage.qml:144
#: src/qml/ImageEditorPage.qml:145
#, kde-format
msgctxt "@action:button Rotate an image to the left"
msgid "Rotate left"
msgstr ""
#: src/qml/ImageEditorPage.qml:150
#: src/qml/ImageEditorPage.qml:151
#, kde-format
msgctxt "@action:button Rotate an image to the right"
msgid "Rotate right"
msgstr ""
#: src/qml/ImageEditorPage.qml:156
#: src/qml/ImageEditorPage.qml:157
#, kde-format
msgctxt "@action:button Mirror an image vertically"
msgid "Flip"
msgstr ""
#: src/qml/ImageEditorPage.qml:162
#: src/qml/ImageEditorPage.qml:163
#, kde-format
msgctxt "@action:button Mirror an image horizontally"
msgid "Mirror"
@@ -3065,7 +3062,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
@@ -3074,16 +3071,9 @@ 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
msgctxt "@action:inmenu"
msgid "Copy Message Link"
msgid "Copy Link"
msgstr ""
#: src/qml/MessageSourceSheet.qml:46
@@ -3178,7 +3168,7 @@ msgctxt "@action:button"
msgid "Join"
msgstr ""
#: src/qml/RecommendedSpaceDialog.qml:63
#: src/qml/RecommendedSpaceDialog.qml:61
#, kde-format
msgctxt "@action:button"
msgid "Ignore"
@@ -3212,18 +3202,18 @@ msgstr ""
msgid "Configure room"
msgstr ""
#: src/qml/RoomDrawer.qml:114 src/qml/RoomDrawerPage.qml:45
#: src/qml/RoomDrawer.qml:111 src/qml/RoomDrawerPage.qml:45
#, kde-format
msgctxt "@action:button"
msgid "Room settings"
msgstr ""
#: src/qml/RoomDrawer.qml:163 src/qml/RoomDrawerPage.qml:85
#: src/qml/RoomDrawer.qml:160 src/qml/RoomDrawerPage.qml:85
#, kde-format
msgid "Information"
msgstr ""
#: src/qml/RoomDrawer.qml:168 src/qml/RoomDrawerPage.qml:90
#: src/qml/RoomDrawer.qml:165 src/qml/RoomDrawerPage.qml:90
#, kde-format
msgid "Media"
msgstr ""
@@ -3237,7 +3227,7 @@ msgstr ""
#: src/qml/RoomInformation.qml:42
#, kde-format
msgctxt "@action:title"
msgid "Room Information"
msgid "Room information"
msgstr ""
#: src/qml/RoomInformation.qml:70
@@ -3278,12 +3268,6 @@ 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"
@@ -3357,7 +3341,7 @@ msgctxt "@action:title"
msgid "Room Media"
msgstr ""
#: src/qml/RoomPage.qml:92
#: src/qml/RoomPage.qml:93
#, kde-format
msgid "NeoChat is offline. Please check your network connection."
msgstr ""
@@ -3599,6 +3583,12 @@ 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
@@ -3653,7 +3643,7 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
#: src/qml/UnlockSSSSDialog.qml:16
#: src/qml/UnlockSSSSDialog.qml:17
#, kde-format
msgctxt "@title:window"
msgid "Load your encrypted messages"
@@ -3741,129 +3731,129 @@ msgctxt "@title:menu Account details dialog"
msgid "Account Details"
msgstr ""
#: src/qml/UserDetailDialog.qml:111
#: src/qml/UserDetailDialog.qml:109
#, kde-format
msgid "Unignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:111
#: src/qml/UserDetailDialog.qml:109
#, kde-format
msgid "Ignore this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:124
#: src/qml/UserDetailDialog.qml:122
#, kde-format
msgid "Kick this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:128 src/qml/UserDetailDialog.qml:133
#: src/qml/UserDetailDialog.qml:126 src/qml/UserDetailDialog.qml:131
#, kde-format
msgctxt "@title:dialog"
msgid "Kick User"
msgstr ""
#: src/qml/UserDetailDialog.qml:129
#: src/qml/UserDetailDialog.qml:127
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for kicking this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:130
#: src/qml/UserDetailDialog.qml:128
#, kde-format
msgctxt "@action:button 'Kick' as in 'Kick this user from the room'"
msgid "Kick"
msgstr ""
#: src/qml/UserDetailDialog.qml:149
#: src/qml/UserDetailDialog.qml:147
#, kde-format
msgid "Invite this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:162
#: src/qml/UserDetailDialog.qml:160
#, kde-format
msgid "Ban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:167 src/qml/UserDetailDialog.qml:172
#: src/qml/UserDetailDialog.qml:165 src/qml/UserDetailDialog.qml:170
#, kde-format
msgctxt "@title:dialog"
msgid "Ban User"
msgstr ""
#: src/qml/UserDetailDialog.qml:168
#: src/qml/UserDetailDialog.qml:166
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for banning this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:169
#: src/qml/UserDetailDialog.qml:167
#, kde-format
msgctxt "@action:button 'Ban' as in 'Ban this user'"
msgid "Ban"
msgstr ""
#: src/qml/UserDetailDialog.qml:187
#: src/qml/UserDetailDialog.qml:185
#, kde-format
msgid "Unban this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:200
#: src/qml/UserDetailDialog.qml:198
#, kde-format
msgid "Set user power level"
msgstr ""
#: src/qml/UserDetailDialog.qml:225
#: src/qml/UserDetailDialog.qml:223
#, kde-format
msgctxt "@action:button"
msgid "Remove recent messages by this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:230
#: src/qml/UserDetailDialog.qml:228
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:231
#: src/qml/UserDetailDialog.qml:229
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this user's recent messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:232
#: src/qml/UserDetailDialog.qml:230
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove these messages'"
msgid "Remove"
msgstr ""
#: src/qml/UserDetailDialog.qml:235
#: src/qml/UserDetailDialog.qml:233
#, kde-format
msgctxt "@title"
msgid "Remove Messages"
msgstr ""
#: src/qml/UserDetailDialog.qml:249
#: src/qml/UserDetailDialog.qml:247
#, kde-format
msgctxt "%1 is the name of the user."
msgid "Chat with %1"
msgstr ""
#: src/qml/UserDetailDialog.qml:249
#: src/qml/UserDetailDialog.qml:247
#, kde-format
msgid "Invite to private chat"
msgstr ""
#: src/qml/UserDetailDialog.qml:260
#: src/qml/UserDetailDialog.qml:258
#, kde-format
msgid "Copy link"
msgstr ""
#: src/qml/UserInfo.qml:92
#: src/qml/UserInfo.qml:91
#, kde-format
msgid "Switch User"
msgstr ""
#: src/qml/UserInfo.qml:101
#: src/qml/UserInfo.qml:100
#, kde-format
msgid "Open Settings"
msgstr ""
@@ -4081,7 +4071,7 @@ msgstr ""
msgid "Working"
msgstr ""
#: src/roommanager.cpp:145
#: src/roommanager.cpp:146
#, kde-format
msgid "Malformed or empty Matrix id<br />%1 is not a correct Matrix identifier"
msgstr ""
@@ -4106,126 +4096,126 @@ msgstr ""
msgid "Edit Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:62
#: src/settings/AccountEditorPage.qml:61
#, kde-format
msgid "Upload new avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:79
#: src/settings/AccountEditorPage.qml:78
#, kde-format
msgid "Remove current avatar"
msgstr ""
#: src/settings/AccountEditorPage.qml:102
#: src/settings/AccountEditorPage.qml:101
#, kde-format
msgid "User Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:107
#: src/settings/AccountEditorPage.qml:106
#, kde-format
msgid "Display Name:"
msgstr ""
#: src/settings/AccountEditorPage.qml:113
#: src/settings/AccountEditorPage.qml:112
#, kde-format
msgid "Label:"
msgstr ""
#: src/settings/AccountEditorPage.qml:114
#: src/settings/AccountEditorPage.qml:113
#, kde-format
msgid "Work"
msgstr ""
#: src/settings/AccountEditorPage.qml:119
#: src/settings/AccountEditorPage.qml:118
#, kde-format
msgctxt "@action:button"
msgid "Show QR Code"
msgstr ""
#: src/settings/AccountEditorPage.qml:137
#: src/settings/AccountEditorPage.qml:193
#: src/settings/AccountEditorPage.qml:135
#: src/settings/AccountEditorPage.qml:191
#: src/settings/EmoticonEditorPage.qml:108 src/settings/RoomGeneralPage.qml:98
#, kde-format
msgid "Save"
msgstr ""
#: src/settings/AccountEditorPage.qml:159
#: src/settings/AccountEditorPage.qml:157
#, kde-format
msgid "Your server doesn't support changing your password"
msgstr ""
#: src/settings/AccountEditorPage.qml:166
#: src/settings/AccountEditorPage.qml:164
#, kde-format
msgid "Current Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:173
#: src/settings/AccountEditorPage.qml:171
#, kde-format
msgid "New Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:180
#: src/settings/AccountEditorPage.qml:178
#, kde-format
msgid "Confirm new Password:"
msgstr ""
#: src/settings/AccountEditorPage.qml:185
#: src/settings/AccountEditorPage.qml:183
#, kde-format
msgid "Passwords don't match"
msgstr ""
#: src/settings/AccountEditorPage.qml:200
#: src/settings/AccountEditorPage.qml:198
#, kde-format
msgid "Passwords do not match"
msgstr ""
#: src/settings/AccountEditorPage.qml:207
#: src/settings/AccountEditorPage.qml:205
#, kde-format
msgid "Email Addresses"
msgstr ""
#: src/settings/AccountEditorPage.qml:213
#: src/settings/AccountEditorPage.qml:211
#, kde-format
msgid "Phone Numbers"
msgstr ""
#: src/settings/AccountEditorPage.qml:218
#: src/settings/AccountEditorPage.qml:216
#, kde-format
msgid "Identity Server"
msgstr ""
#: src/settings/AccountEditorPage.qml:227
#: src/settings/AccountEditorPage.qml:225
#, kde-format
msgid "Server Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:231
#: src/settings/AccountEditorPage.qml:229
#, kde-format
msgid "Homeserver url"
msgstr ""
#: src/settings/AccountEditorPage.qml:252
#: src/settings/AccountEditorPage.qml:250
#, kde-format
msgctxt "@title"
msgid "Account Management"
msgstr ""
#: src/settings/AccountEditorPage.qml:257
#: src/settings/AccountEditorPage.qml:255
#, kde-format
msgid "Deactivate Account"
msgstr ""
#: src/settings/AccountEditorPage.qml:273
#: src/settings/AccountEditorPage.qml:271
#, kde-format
msgid "Password changed successfully"
msgstr ""
#: src/settings/AccountEditorPage.qml:275
#: src/settings/AccountEditorPage.qml:273
#, kde-format
msgid "Wrong password entered"
msgstr ""
#: src/settings/AccountEditorPage.qml:277
#: src/settings/AccountEditorPage.qml:275
#, kde-format
msgid "Unknown problem while trying to change password"
msgstr ""
@@ -4236,7 +4226,7 @@ msgstr ""
msgid "Accounts"
msgstr ""
#: src/settings/AccountsPage.qml:118
#: src/settings/AccountsPage.qml:117
#, kde-format
msgid "Add Account"
msgstr ""
@@ -4466,7 +4456,7 @@ msgctxt "@title"
msgid "Stickers & Emojis"
msgstr ""
#: src/settings/ExportKeysDialog.qml:17
#: src/settings/ExportKeysDialog.qml:18
#: src/settings/NeoChatSecurityPage.qml:107
#, kde-format
msgctxt "@title"
@@ -4615,7 +4605,7 @@ msgctxt "@action:button"
msgid "Unignore this user"
msgstr ""
#: src/settings/ImportKeysDialog.qml:21 src/settings/NeoChatSecurityPage.qml:84
#: src/settings/ImportKeysDialog.qml:22 src/settings/NeoChatSecurityPage.qml:84
#, kde-format
msgctxt "@title"
msgid "Import Keys"
@@ -4779,7 +4769,7 @@ msgctxt "@action:button"
msgid "Reset all configuration values to their default"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:18
#: src/settings/NeoChatSecurityPage.qml:19
#: 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-19 00:40+0000\n"
"POT-Creation-Date: 2024-11-13 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:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Send an encrypted message…"
msgstr "发送一条加密消息..."
#: src/chatbar/ChatBar.qml:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Set an attachment caption…"
msgstr "设置附件说明"
#: src/chatbar/ChatBar.qml:202
#: src/chatbar/ChatBar.qml:201
#, kde-format
msgid "Send a message…"
msgstr "发送一条消息..."
#: src/chatbar/ChatBar.qml:375
#: src/chatbar/ChatBar.qml:376
#, kde-format
msgctxt "@action:button"
msgid "Cancel reply"
msgstr "取消回复"
#: src/chatbar/EmojiGrid.qml:88
#: src/chatbar/EmojiGrid.qml:87
#, kde-format
msgid "No stickers"
msgstr "无贴纸"
#: src/chatbar/EmojiGrid.qml:88
#: src/chatbar/EmojiGrid.qml:87
#, kde-format
msgid "No emojis"
msgstr "无表情"
@@ -910,7 +910,7 @@ msgstr "此服务器已禁用注册。"
msgid "Loading"
msgstr "加载中"
#: src/login/Loading.qml:17
#: src/login/Loading.qml:16
#, 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:249
#: src/login/Login.qml:38 src/login/WelcomePage.qml:232
#: 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:154
#: src/login/Password.qml:32 src/settings/AccountEditorPage.qml:152
#: src/settings/NetworkProxyPage.qml:122
#, kde-format
msgid "Password"
@@ -1030,47 +1030,47 @@ msgstr "用户名:"
msgid "Username unavailable"
msgstr "用户名不可用"
#: src/login/WelcomePage.qml:26
#: src/login/WelcomePage.qml:25
#, kde-format
msgid "Welcome"
msgstr "欢迎使用"
#: src/login/WelcomePage.qml:74 src/main.cpp:141
#: src/login/WelcomePage.qml:73 src/main.cpp:141
#, kde-format
msgid "NeoChat"
msgstr "NeoChat"
#: src/login/WelcomePage.qml:82
#: src/login/WelcomePage.qml:81
#, kde-format
msgctxt "@title"
msgid "Continue with an existing account"
msgstr "使用现有账户登录"
#: src/login/WelcomePage.qml:132
#: src/login/WelcomePage.qml:115
#, kde-format
msgctxt "As in 'this account is still loading'"
msgid "%1 (loading)"
msgstr "%1 (加载中)"
#: src/login/WelcomePage.qml:141
#: src/login/WelcomePage.qml:124
#, kde-format
msgctxt "@action:button"
msgid "Log out of this account"
msgstr ""
#: src/login/WelcomePage.qml:170
#: src/login/WelcomePage.qml:153
#, kde-format
msgctxt "@title"
msgid "Log in or Create a New Account"
msgstr "登录或创建一个新账户"
#: src/login/WelcomePage.qml:257
#: src/login/WelcomePage.qml:240
#, kde-format
msgctxt "@action:button"
msgid "Go back"
msgstr "返回"
#: src/login/WelcomePage.qml:269
#: src/login/WelcomePage.qml:252
#, 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:111
#: src/notificationsmanager.cpp:246 src/qml/DelegateContextMenu.qml:110
#: 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:40 src/qml/UserInfo.qml:46
#: src/qml/AccountMenu.qml:39 src/qml/UserInfo.qml:46
#, kde-format
msgid "Edit this account"
msgstr "编辑此账户"
#: src/qml/AccountMenu.qml:45 src/settings/AccountsPage.qml:33
#: src/qml/AccountMenu.qml:44 src/settings/AccountsPage.qml:33
#: src/settings/AccountsPage.qml:50
#, kde-format
msgid "Account editor"
msgstr "账户编辑器"
#: src/qml/AccountMenu.qml:49
#: src/qml/AccountMenu.qml:48
#, kde-format
msgid "Notification settings"
msgstr "通知设置"
#: src/qml/AccountMenu.qml:56 src/settings/DevicesPage.qml:17
#: src/qml/AccountMenu.qml:55 src/settings/DevicesPage.qml:17
#: src/settings/NeoChatSettingsView.qml:89
#, kde-format
msgid "Devices"
msgstr "设备"
#: src/qml/AccountMenu.qml:63 src/settings/NeoChatGeneralPage.qml:269
#: src/qml/AccountMenu.qml:62 src/settings/NeoChatGeneralPage.qml:269
#, kde-format
msgid "Open developer tools"
msgstr "打开开发者工具"
#: src/qml/AccountMenu.qml:69
#: src/qml/AccountMenu.qml:68
#, kde-format
msgctxt "@title:window"
msgid "Developer Tools"
msgstr "开发者工具"
#: src/qml/AccountMenu.qml:75
#: src/qml/AccountMenu.qml:74
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Secret Backup"
msgstr ""
#: src/qml/AccountMenu.qml:79
#: src/qml/AccountMenu.qml:78
#, kde-format
msgctxt "@title:window"
msgid "Open Key Backup"
msgstr ""
#: src/qml/AccountMenu.qml:83
#: src/qml/AccountMenu.qml:82
#, kde-format
msgctxt "@action:inmenu"
msgid "Verify this Device"
msgstr ""
#: src/qml/AccountMenu.qml:89 src/settings/AccountsPage.qml:88
#: src/qml/AccountMenu.qml:88 src/settings/AccountsPage.qml:87
#, 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:20 src/qml/MessageDelegateContextMenu.qml:37
#: src/qml/ImageEditorPage.qml:21 src/qml/MessageDelegateContextMenu.qml:37
#, kde-format
msgid "Edit"
msgstr "编辑"
@@ -2144,29 +2144,61 @@ msgctxt "@action:button"
msgid "Open"
msgstr "打开"
#: src/qml/ContextMenu.qml:31 src/qml/ContextMenu.qml:209
#: 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
#, kde-format
msgid "Mark as Read"
msgstr "标记为已读"
#: src/qml/ContextMenu.qml:40
#: src/qml/ContextMenu.qml:49
#, kde-format
msgctxt "@action:inmenu"
msgid "Notifications"
msgstr "通知"
msgid "Copy user's Matrix ID to Clipboard"
msgstr "将用户的 Matrix ID 复制到剪贴板"
#: src/qml/ContextMenu.qml:44
#: 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
#, kde-format
msgid "Follow Global Setting"
msgstr "使用全局设置"
#: src/qml/ContextMenu.qml:55 src/settings/PushNotification.qml:39
#: src/qml/ContextMenu.qml:76 src/settings/PushNotification.qml:39
#, kde-format
msgctxt "As in 'notify for all messages'"
msgid "All"
msgstr "全部"
#: src/qml/ContextMenu.qml:66 src/settings/PushNotification.qml:47
#: src/qml/ContextMenu.qml:87 src/settings/PushNotification.qml:47
#, kde-format
msgctxt ""
"As in 'notify when the user is mentioned or the message contains a set "
@@ -2174,67 +2206,34 @@ msgctxt ""
msgid "@Mentions and Keywords"
msgstr "@提及 和关键词"
#: src/qml/ContextMenu.qml:77 src/settings/PushNotification.qml:55
#: src/qml/ContextMenu.qml:98 src/settings/PushNotification.qml:55
#, kde-format
msgctxt "As in 'do not notify for any messages'"
msgid "Off"
msgstr "关闭"
#: 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
#: src/qml/ContextMenu.qml:111
#, kde-format
msgctxt "@action:inmenu"
msgid "Room Settings"
msgstr "聊天室设置"
#: src/qml/ContextMenu.qml:126 src/qml/ContextMenu.qml:216
#: src/qml/ContextMenu.qml:121 src/qml/ContextMenu.qml:211
#, kde-format
msgid "Leave Room"
msgstr "离开聊天室"
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:182
#, kde-format
msgid "Remove from Favourites"
msgstr "移出收藏夹"
#: src/qml/ContextMenu.qml:187
#: src/qml/ContextMenu.qml:182
#, kde-format
msgid "Add to Favourites"
msgstr "移入收藏夹"
#: src/qml/ContextMenu.qml:192
#: src/qml/ContextMenu.qml:187
#, kde-format
msgctxt "@action:button"
msgid "Room Settings"
@@ -2357,74 +2356,74 @@ msgctxt "@action:button"
msgid "Ok"
msgstr "确定"
#: src/qml/DelegateContextMenu.qml:84
#: src/qml/DelegateContextMenu.qml:83
#, kde-format
msgid "View Source"
msgstr "查看源码"
#: src/qml/DelegateContextMenu.qml:91 src/settings/ThreePIdCard.qml:66
#: src/qml/DelegateContextMenu.qml:90 src/settings/ThreePIdCard.qml:66
#, kde-format
msgctxt "@action:button"
msgid "Remove"
msgstr "移除"
#: src/qml/DelegateContextMenu.qml:96 src/qml/DelegateContextMenu.qml:101
#: src/qml/FileDelegateContextMenu.qml:82
#: src/qml/FileDelegateContextMenu.qml:87
#: src/qml/DelegateContextMenu.qml:95 src/qml/DelegateContextMenu.qml:100
#: src/qml/FileDelegateContextMenu.qml:76
#: src/qml/FileDelegateContextMenu.qml:81
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Message"
msgstr "移除消息"
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:83
#: src/qml/DelegateContextMenu.qml:96 src/qml/FileDelegateContextMenu.qml:77
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this message"
msgstr "移除此消息的原因"
#: src/qml/DelegateContextMenu.qml:98 src/qml/FileDelegateContextMenu.qml:84
#: src/qml/DelegateContextMenu.qml:97 src/qml/FileDelegateContextMenu.qml:78
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove this message'"
msgid "Remove"
msgstr "移除"
#: src/qml/DelegateContextMenu.qml:121 src/qml/DelegateContextMenu.qml:129
#: src/qml/DelegateContextMenu.qml:120 src/qml/DelegateContextMenu.qml:128
#, kde-format
msgctxt ""
"@action:button 'Report' as in 'Report this event to the administrators'"
msgid "Report"
msgstr "举报"
#: src/qml/DelegateContextMenu.qml:126
#: src/qml/DelegateContextMenu.qml:125
#, kde-format
msgctxt "@title:dialog"
msgid "Report Message"
msgstr "举报消息"
#: src/qml/DelegateContextMenu.qml:127
#: src/qml/DelegateContextMenu.qml:126
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for reporting this message"
msgstr "举报此消息的原因"
#: src/qml/DelegateContextMenu.qml:131
#: src/qml/DelegateContextMenu.qml:130
#, kde-format
msgctxt "@title"
msgid "Report Message"
msgstr "举报消息"
#: src/qml/DelegateContextMenu.qml:141
#: src/qml/DelegateContextMenu.qml:140
#, kde-format
msgctxt "@action:inmenu"
msgid "Show User"
msgstr "查看用户"
#: src/qml/DelegateContextMenu.qml:204
#: src/qml/DelegateContextMenu.qml:188
#, kde-format
msgid "Search for '%1'"
msgstr "搜索 '%1'"
#: src/qml/DelegateContextMenu.qml:226
#: src/qml/DelegateContextMenu.qml:210
#, kde-format
msgid "Configure Web Shortcuts..."
msgstr "配置网页快捷键..."
@@ -2619,25 +2618,23 @@ msgctxt "@info:label"
msgid "No public rooms found"
msgstr "未找到公共聊天室"
#: src/qml/FileDelegateContextMenu.qml:50
#: src/qml/FileDelegateContextMenu.qml:46
#, kde-format
msgctxt "@action:inmenu"
msgid "Open Image"
msgstr ""
msgid "Open Externally"
msgstr "在外部打开"
#: src/qml/FileDelegateContextMenu.qml:57
#: src/qml/FileDelegateContextMenu.qml:53
#, kde-format
msgctxt "@action:inmenu"
msgid "Save Image…"
msgstr ""
msgid "Save As"
msgstr "另存为"
#: src/qml/FileDelegateContextMenu.qml:66
#: src/qml/FileDelegateContextMenu.qml:63
#: src/qml/MessageDelegateContextMenu.qml:64
#, kde-format
msgctxt "@action:inmenu"
msgid "Copy Image"
msgstr ""
msgid "Copy"
msgstr "复制"
#: src/qml/FileDelegateContextMenu.qml:77
#: src/qml/FileDelegateContextMenu.qml:71
#, kde-format
msgid "Remove"
msgstr "移除"
@@ -2787,55 +2784,55 @@ msgctxt "@info screenreader"
msgid "The currently selected link"
msgstr "当前选择的链接"
#: src/qml/ImageEditorPage.qml:36
#: src/qml/ImageEditorPage.qml:37
#, kde-format
msgctxt "@action:button Undo modification"
msgid "Undo"
msgstr "撤销"
#: src/qml/ImageEditorPage.qml:43
#: src/qml/ImageEditorPage.qml:44
#, kde-format
msgctxt "@action:button Accept image modification"
msgid "Accept"
msgstr "接受"
#: src/qml/ImageEditorPage.qml:51
#: src/qml/ImageEditorPage.qml:52
#, kde-format
msgid ""
"Unable to save file. Check if you have the correct permission to edit the "
"cache directory."
msgstr "无法保存文件。请检查您是否有编辑缓存目录的正确权限。"
#: src/qml/ImageEditorPage.qml:123
#: src/qml/ImageEditorPage.qml:124
#, kde-format
msgid "Cancel"
msgstr "取消"
#: src/qml/ImageEditorPage.qml:123 src/qml/ImageEditorPage.qml:139
#: src/qml/ImageEditorPage.qml:124 src/qml/ImageEditorPage.qml:140
#, kde-format
msgctxt "@action:button Crop an image"
msgid "Crop"
msgstr "裁剪"
#: src/qml/ImageEditorPage.qml:144
#: src/qml/ImageEditorPage.qml:145
#, kde-format
msgctxt "@action:button Rotate an image to the left"
msgid "Rotate left"
msgstr "旋转 (向左)"
#: src/qml/ImageEditorPage.qml:150
#: src/qml/ImageEditorPage.qml:151
#, kde-format
msgctxt "@action:button Rotate an image to the right"
msgid "Rotate right"
msgstr "旋转 (向右)"
#: src/qml/ImageEditorPage.qml:156
#: src/qml/ImageEditorPage.qml:157
#, kde-format
msgctxt "@action:button Mirror an image vertically"
msgid "Flip"
msgstr "翻转"
#: src/qml/ImageEditorPage.qml:162
#: src/qml/ImageEditorPage.qml:163
#, kde-format
msgctxt "@action:button Mirror an image horizontally"
msgid "Mirror"
@@ -3063,8 +3060,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
@@ -3072,17 +3069,10 @@ 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
msgctxt "@action:inmenu"
msgid "Copy Message Link"
msgstr ""
msgid "Copy Link"
msgstr "复制链接"
#: src/qml/MessageSourceSheet.qml:46
#, kde-format
@@ -3176,7 +3166,7 @@ msgctxt "@action:button"
msgid "Join"
msgstr "加入"
#: src/qml/RecommendedSpaceDialog.qml:63
#: src/qml/RecommendedSpaceDialog.qml:61
#, kde-format
msgctxt "@action:button"
msgid "Ignore"
@@ -3210,18 +3200,18 @@ msgstr "已静音的聊天室"
msgid "Configure room"
msgstr "配置聊天室"
#: src/qml/RoomDrawer.qml:114 src/qml/RoomDrawerPage.qml:45
#: src/qml/RoomDrawer.qml:111 src/qml/RoomDrawerPage.qml:45
#, kde-format
msgctxt "@action:button"
msgid "Room settings"
msgstr "聊天室设置"
#: src/qml/RoomDrawer.qml:163 src/qml/RoomDrawerPage.qml:85
#: src/qml/RoomDrawer.qml:160 src/qml/RoomDrawerPage.qml:85
#, kde-format
msgid "Information"
msgstr "信息"
#: src/qml/RoomDrawer.qml:168 src/qml/RoomDrawerPage.qml:90
#: src/qml/RoomDrawer.qml:165 src/qml/RoomDrawerPage.qml:90
#, kde-format
msgid "Media"
msgstr "媒体"
@@ -3235,7 +3225,7 @@ msgstr "空间成员"
#: src/qml/RoomInformation.qml:42
#, kde-format
msgctxt "@action:title"
msgid "Room Information"
msgid "Room information"
msgstr "聊天室信息"
#: src/qml/RoomInformation.qml:70
@@ -3276,12 +3266,6 @@ 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"
@@ -3352,7 +3336,7 @@ msgctxt "@action:title"
msgid "Room Media"
msgstr "聊天室媒体"
#: src/qml/RoomPage.qml:92
#: src/qml/RoomPage.qml:93
#, kde-format
msgid "NeoChat is offline. Please check your network connection."
msgstr "NeoChat 处于离线状态。请检查您的网络连接。"
@@ -3588,6 +3572,12 @@ 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
@@ -3640,7 +3630,7 @@ msgid "%2 is typing"
msgid_plural "%2 are typing"
msgstr[0] "%2 正在输入"
#: src/qml/UnlockSSSSDialog.qml:16
#: src/qml/UnlockSSSSDialog.qml:17
#, kde-format
msgctxt "@title:window"
msgid "Load your encrypted messages"
@@ -3730,129 +3720,129 @@ msgctxt "@title:menu Account details dialog"
msgid "Account Details"
msgstr "账户详情"
#: src/qml/UserDetailDialog.qml:111
#: src/qml/UserDetailDialog.qml:109
#, kde-format
msgid "Unignore this user"
msgstr "取消忽略此用户"
#: src/qml/UserDetailDialog.qml:111
#: src/qml/UserDetailDialog.qml:109
#, kde-format
msgid "Ignore this user"
msgstr "忽略此用户"
#: src/qml/UserDetailDialog.qml:124
#: src/qml/UserDetailDialog.qml:122
#, kde-format
msgid "Kick this user"
msgstr "踢出此用户"
#: src/qml/UserDetailDialog.qml:128 src/qml/UserDetailDialog.qml:133
#: src/qml/UserDetailDialog.qml:126 src/qml/UserDetailDialog.qml:131
#, kde-format
msgctxt "@title:dialog"
msgid "Kick User"
msgstr ""
#: src/qml/UserDetailDialog.qml:129
#: src/qml/UserDetailDialog.qml:127
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for kicking this user"
msgstr ""
#: src/qml/UserDetailDialog.qml:130
#: src/qml/UserDetailDialog.qml:128
#, kde-format
msgctxt "@action:button 'Kick' as in 'Kick this user from the room'"
msgid "Kick"
msgstr ""
#: src/qml/UserDetailDialog.qml:149
#: src/qml/UserDetailDialog.qml:147
#, kde-format
msgid "Invite this user"
msgstr "邀请此用户"
#: src/qml/UserDetailDialog.qml:162
#: src/qml/UserDetailDialog.qml:160
#, kde-format
msgid "Ban this user"
msgstr "封禁此用户"
#: src/qml/UserDetailDialog.qml:167 src/qml/UserDetailDialog.qml:172
#: src/qml/UserDetailDialog.qml:165 src/qml/UserDetailDialog.qml:170
#, kde-format
msgctxt "@title:dialog"
msgid "Ban User"
msgstr "封禁用户"
#: src/qml/UserDetailDialog.qml:168
#: src/qml/UserDetailDialog.qml:166
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for banning this user"
msgstr "封禁此用户的原因"
#: src/qml/UserDetailDialog.qml:169
#: src/qml/UserDetailDialog.qml:167
#, kde-format
msgctxt "@action:button 'Ban' as in 'Ban this user'"
msgid "Ban"
msgstr "封禁"
#: src/qml/UserDetailDialog.qml:187
#: src/qml/UserDetailDialog.qml:185
#, kde-format
msgid "Unban this user"
msgstr "解封此用户"
#: src/qml/UserDetailDialog.qml:200
#: src/qml/UserDetailDialog.qml:198
#, kde-format
msgid "Set user power level"
msgstr "设置用户权力等级"
#: src/qml/UserDetailDialog.qml:225
#: src/qml/UserDetailDialog.qml:223
#, kde-format
msgctxt "@action:button"
msgid "Remove recent messages by this user"
msgstr "移除此用户最近的消息"
#: src/qml/UserDetailDialog.qml:230
#: src/qml/UserDetailDialog.qml:228
#, kde-format
msgctxt "@title:dialog"
msgid "Remove Messages"
msgstr "移除消息"
#: src/qml/UserDetailDialog.qml:231
#: src/qml/UserDetailDialog.qml:229
#, kde-format
msgctxt "@info:placeholder"
msgid "Reason for removing this user's recent messages"
msgstr "移除此用户最近消息的原因"
#: src/qml/UserDetailDialog.qml:232
#: src/qml/UserDetailDialog.qml:230
#, kde-format
msgctxt "@action:button 'Remove' as in 'Remove these messages'"
msgid "Remove"
msgstr "移除"
#: src/qml/UserDetailDialog.qml:235
#: src/qml/UserDetailDialog.qml:233
#, kde-format
msgctxt "@title"
msgid "Remove Messages"
msgstr "移除消息"
#: src/qml/UserDetailDialog.qml:249
#: src/qml/UserDetailDialog.qml:247
#, kde-format
msgctxt "%1 is the name of the user."
msgid "Chat with %1"
msgstr "与 %1 聊天"
#: src/qml/UserDetailDialog.qml:249
#: src/qml/UserDetailDialog.qml:247
#, kde-format
msgid "Invite to private chat"
msgstr "邀请到私人聊天"
#: src/qml/UserDetailDialog.qml:260
#: src/qml/UserDetailDialog.qml:258
#, kde-format
msgid "Copy link"
msgstr "复制链接"
#: src/qml/UserInfo.qml:92
#: src/qml/UserInfo.qml:91
#, kde-format
msgid "Switch User"
msgstr "切换用户"
#: src/qml/UserInfo.qml:101
#: src/qml/UserInfo.qml:100
#, kde-format
msgid "Open Settings"
msgstr "打开设置"
@@ -4073,7 +4063,7 @@ msgstr "继续"
msgid "Working"
msgstr "正在处理"
#: src/roommanager.cpp:145
#: src/roommanager.cpp:146
#, kde-format
msgid "Malformed or empty Matrix id<br />%1 is not a correct Matrix identifier"
msgstr ""
@@ -4098,126 +4088,126 @@ msgstr ""
msgid "Edit Account"
msgstr "编辑账户"
#: src/settings/AccountEditorPage.qml:62
#: src/settings/AccountEditorPage.qml:61
#, kde-format
msgid "Upload new avatar"
msgstr "上传新头像"
#: src/settings/AccountEditorPage.qml:79
#: src/settings/AccountEditorPage.qml:78
#, kde-format
msgid "Remove current avatar"
msgstr "移除当前头像"
#: src/settings/AccountEditorPage.qml:102
#: src/settings/AccountEditorPage.qml:101
#, kde-format
msgid "User Information"
msgstr ""
#: src/settings/AccountEditorPage.qml:107
#: src/settings/AccountEditorPage.qml:106
#, kde-format
msgid "Display Name:"
msgstr ""
#: src/settings/AccountEditorPage.qml:113
#: src/settings/AccountEditorPage.qml:112
#, kde-format
msgid "Label:"
msgstr "标签:"
#: src/settings/AccountEditorPage.qml:114
#: src/settings/AccountEditorPage.qml:113
#, kde-format
msgid "Work"
msgstr ""
#: src/settings/AccountEditorPage.qml:119
#: src/settings/AccountEditorPage.qml:118
#, kde-format
msgctxt "@action:button"
msgid "Show QR Code"
msgstr ""
#: src/settings/AccountEditorPage.qml:137
#: src/settings/AccountEditorPage.qml:193
#: src/settings/AccountEditorPage.qml:135
#: src/settings/AccountEditorPage.qml:191
#: src/settings/EmoticonEditorPage.qml:108 src/settings/RoomGeneralPage.qml:98
#, kde-format
msgid "Save"
msgstr "保存"
#: src/settings/AccountEditorPage.qml:159
#: src/settings/AccountEditorPage.qml:157
#, kde-format
msgid "Your server doesn't support changing your password"
msgstr "您的服务器不支持更改您的密码"
#: src/settings/AccountEditorPage.qml:166
#: src/settings/AccountEditorPage.qml:164
#, kde-format
msgid "Current Password:"
msgstr "当前密码:"
#: src/settings/AccountEditorPage.qml:173
#: src/settings/AccountEditorPage.qml:171
#, kde-format
msgid "New Password:"
msgstr "新密码:"
#: src/settings/AccountEditorPage.qml:180
#: src/settings/AccountEditorPage.qml:178
#, kde-format
msgid "Confirm new Password:"
msgstr "确认新密码:"
#: src/settings/AccountEditorPage.qml:185
#: src/settings/AccountEditorPage.qml:183
#, kde-format
msgid "Passwords don't match"
msgstr "密码不匹配"
#: src/settings/AccountEditorPage.qml:200
#: src/settings/AccountEditorPage.qml:198
#, kde-format
msgid "Passwords do not match"
msgstr "密码不匹配"
#: src/settings/AccountEditorPage.qml:207
#: src/settings/AccountEditorPage.qml:205
#, kde-format
msgid "Email Addresses"
msgstr "电子邮件地址"
#: src/settings/AccountEditorPage.qml:213
#: src/settings/AccountEditorPage.qml:211
#, kde-format
msgid "Phone Numbers"
msgstr "电话号码"
#: src/settings/AccountEditorPage.qml:218
#: src/settings/AccountEditorPage.qml:216
#, kde-format
msgid "Identity Server"
msgstr ""
#: src/settings/AccountEditorPage.qml:227
#: src/settings/AccountEditorPage.qml:225
#, kde-format
msgid "Server Information"
msgstr "服务器信息"
#: src/settings/AccountEditorPage.qml:231
#: src/settings/AccountEditorPage.qml:229
#, kde-format
msgid "Homeserver url"
msgstr "主服务器 URL"
#: src/settings/AccountEditorPage.qml:252
#: src/settings/AccountEditorPage.qml:250
#, kde-format
msgctxt "@title"
msgid "Account Management"
msgstr "账户管理"
#: src/settings/AccountEditorPage.qml:257
#: src/settings/AccountEditorPage.qml:255
#, kde-format
msgid "Deactivate Account"
msgstr "停用账户"
#: src/settings/AccountEditorPage.qml:273
#: src/settings/AccountEditorPage.qml:271
#, kde-format
msgid "Password changed successfully"
msgstr "密码修改成功"
#: src/settings/AccountEditorPage.qml:275
#: src/settings/AccountEditorPage.qml:273
#, kde-format
msgid "Wrong password entered"
msgstr "输入的密码错误"
#: src/settings/AccountEditorPage.qml:277
#: src/settings/AccountEditorPage.qml:275
#, kde-format
msgid "Unknown problem while trying to change password"
msgstr "尝试更改密码时出现未知问题"
@@ -4228,7 +4218,7 @@ msgstr "尝试更改密码时出现未知问题"
msgid "Accounts"
msgstr "账户"
#: src/settings/AccountsPage.qml:118
#: src/settings/AccountsPage.qml:117
#, kde-format
msgid "Add Account"
msgstr "添加账户"
@@ -4458,7 +4448,7 @@ msgctxt "@title"
msgid "Stickers & Emojis"
msgstr "贴纸和表情"
#: src/settings/ExportKeysDialog.qml:17
#: src/settings/ExportKeysDialog.qml:18
#: src/settings/NeoChatSecurityPage.qml:107
#, kde-format
msgctxt "@title"
@@ -4607,7 +4597,7 @@ msgctxt "@action:button"
msgid "Unignore this user"
msgstr "取消忽略此用户"
#: src/settings/ImportKeysDialog.qml:21 src/settings/NeoChatSecurityPage.qml:84
#: src/settings/ImportKeysDialog.qml:22 src/settings/NeoChatSecurityPage.qml:84
#, kde-format
msgctxt "@title"
msgid "Import Keys"
@@ -4771,7 +4761,7 @@ msgctxt "@action:button"
msgid "Reset all configuration values to their default"
msgstr ""
#: src/settings/NeoChatSecurityPage.qml:18
#: src/settings/NeoChatSecurityPage.qml:19
#: src/settings/NeoChatSettingsView.qml:51
#, kde-format
msgctxt "@title"

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,12 @@ 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
@@ -20,6 +26,8 @@ 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
@@ -42,6 +50,8 @@ 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
@@ -91,6 +101,10 @@ 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
@@ -180,32 +194,6 @@ add_library(neochat STATIC
models/threadmodel.h
enums/messagetype.h
messagecomponent.h
imagecontentmanager.h
imagecontentmanager.cpp
models/imagecontentmodel.cpp
models/imagecontentmodel.h
models/emojipacksmodel.cpp
models/emojipacksmodel.h
models/accountimagepackmodel.cpp
models/accountimagepackmodel.h
models/historyimagepackmodel.cpp
models/historyimagepackmodel.h
models/imagepacksproxymodel.cpp
models/imagepacksproxymodel.h
models/imagepacksmodel.cpp
models/imagepacksmodel.h
models/recentimagecontentmodel.h
models/recentimagecontentmodel.cpp
models/recentimagecontentproxymodel.h
models/recentimagecontentproxymodel.cpp
models/allimagecontentmodel.h
models/allimagecontentmodel.cpp
models/roomimagepacksmodel.h
models/roomimagepacksmodel.cpp
models/imagepackroomsmodel.h
models/imagepackroomsmodel.cpp
models/imagecontentfiltermodel.h
models/imagecontentfiltermodel.cpp
)
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
@@ -294,9 +282,6 @@ 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
@@ -313,12 +298,6 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
org.kde.neochat.chatbar
)
qt_add_resources(neochat "emoji"
PREFIX "/"
FILES
data/emojis.json
)
add_subdirectory(settings)
add_subdirectory(timeline)
add_subdirectory(devtools)

View File

@@ -519,6 +519,7 @@ QQC2.Control {
y: -implicitHeight
modal: false
includeCustom: true
closeOnChosen: false
currentRoom: root.currentRoom

View File

@@ -5,30 +5,56 @@ import QtQuick
import QtQuick.Controls as QQC2
import org.kde.kirigami as Kirigami
QQC2.Button {
QQC2.ItemDelegate {
id: root
required property string toolTip
property string name
property string emoji
property bool showTones: false
property bool isImage: false
QQC2.ToolTip.text: toolTip
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: root.name
QQC2.ToolTip.visible: hovered && root.name !== ""
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
leftInset: Kirigami.Units.smallSpacing
topInset: Kirigami.Units.smallSpacing
rightInset: Kirigami.Units.smallSpacing
bottomInset: Kirigami.Units.smallSpacing
flat: true
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"
contentItem: Kirigami.Heading {
text: root.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
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 : ""
}
}
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
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
}
}
}

View File

@@ -16,7 +16,9 @@ QQC2.Popup {
*/
property NeoChatRoom currentRoom
property bool includeCustom: false
property bool closeOnChosen: true
property bool showQuickReaction: false
signal chosen(string emoji)
@@ -62,15 +64,15 @@ QQC2.Popup {
padding: 2
implicitHeight: Kirigami.Units.gridUnit * 20 + 2 * padding
width: Math.min(contentItem.implicitWidth + 2 * padding, applicationWindow().width)
width: Math.min(contentItem.categoryIconSize * 11 + 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,17 +1,20 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-FileCopyrightText: 2022 Tobias Fella
// 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
readonly property int emojisPerRow: emojis.width / Kirigami.Units.iconSizes.large
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
required property QtObject header
property bool stickers: false
@@ -22,8 +25,6 @@ QQC2.ScrollView {
emojis.forceActiveFocus();
}
width: Kirigami.Units.gridUnit * 24
GridView {
id: emojis
@@ -40,9 +41,7 @@ QQC2.ScrollView {
onModelChanged: currentIndex = -1
cellWidth: emojis.width / root.emojisPerRow
cellHeight: Kirigami.Units.iconSizes.large
model: EmojiModelManager.emojiModel
cellHeight: root.targetIconSize
KeyNavigation.up: root.header
@@ -50,49 +49,49 @@ QQC2.ScrollView {
delegate: EmojiDelegate {
id: emojiDelegate
required property string unicode
required property string identifier
required property int index
text: emojiDelegate.unicode
toolTip: emojiDelegate.identifier
checked: emojis.currentIndex === emojiDelegate.index
checked: emojis.currentIndex === model.index
emoji: !!modelData ? modelData.unicode : model.url
name: !!modelData ? modelData.shortName : model.body
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 (!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
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
}
Kirigami.PlaceholderMessage {
anchors.centerIn: parent
icon.name: root.stickers ? "stickers" : "preferences-desktop-emoticons"
text: root.stickers ? i18nc("@info", "No stickers") : i18nc("@info", "No emojis")
text: root.stickers ? i18n("No stickers") : i18n("No emojis")
visible: emojis.count === 0
}
}
Component {
id: tonesPopupComponent
EmojiTonesPicker {
onChosen: root.chosen(emoji)
}
}
}

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022-2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
@@ -6,7 +6,6 @@ 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
@@ -14,29 +13,86 @@ ColumnLayout {
/**
* @brief The current room that user is viewing.
*/
required property NeoChatRoom currentRoom
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
signal chosen(string emoji)
spacing: 0
onActiveFocusChanged: if (activeFocus) {
searchField.forceActiveFocus();
}
EmojiPickerTypeHeader {
id: emoticonPickerTypeHeader
spacing: 0
Kirigami.NavigationTabBar {
id: types
Layout.fillWidth: true
onSelectedTypeChanged: emoticonPickerCategoryHeader.currentIndex = 0
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
}
]
}
EmojiPickerPackHeader {
id: emoticonPickerCategoryHeader
QQC2.ScrollView {
Layout.fillWidth: true
Layout.preferredHeight: root.categoryIconSize + QQC2.ScrollBar.horizontal.height
QQC2.ScrollBar.horizontal.height: QQC2.ScrollBar.horizontal.visible ? QQC2.ScrollBar.horizontal.implicitHeight : 0
model: UnicodeEmoticonManager.categories
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
}
}
Kirigami.Separator {
@@ -48,34 +104,114 @@ 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: emoticonPickerCategoryHeader
header: categories
Keys.forwardTo: searchField
stickers: emoticonPickerTypeHeader.selectedType === EmojiPickerTypeHeader.EmoticonType.Sticker
stickers: root.selectedType === 1
onStickerChosen: stickerModel.postSticker(emoticonFilterModel.mapToSource(emoticonFilterModel.index(index, 0)).row)
}
Kirigami.Separator {
visible: showQuickReaction
Layout.fillWidth: true
Layout.preferredHeight: 1
}
QuickReaction {
id: quickReaction
onChosen: root.chosen(text)
QQC2.ScrollView {
visible: showQuickReaction
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: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-FileCopyrightText: 2022 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
text: modelData.unicode
toolTip: modelData.shortName
emoji: modelData.unicode
name: modelData.shortName
width: root.categoryIconSize
height: width

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
SPDX-FileCopyrightText: 2024 Emojibase
SPDX-License-Identifier: MIT

1857
src/emojis.h Normal file

File diff suppressed because it is too large Load Diff

9
src/emojitones.cpp Normal file
View File

@@ -0,0 +1,9 @@
// 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"
};

21
src/emojitones.h Normal file
View File

@@ -0,0 +1,21 @@
// 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;
};

1784
src/emojitones_data.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,334 +0,0 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "imagecontentmanager.h"
#include <QDebug>
#include <QFile>
#include <KConfigGroup>
#include <KSharedConfig>
#include "controller.h"
#include "events/imagepackevent.h"
#include "neochatroom.h"
#include <Quotient/connection.h>
#define connection Controller::instance().activeConnection()
using namespace Quotient;
ImageContentManager::ImageContentManager(QObject *parent)
: QObject(parent)
{
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, [this]() {
static Connection *oldActiveConnection = nullptr;
disconnect(oldActiveConnection, nullptr, this, nullptr);
oldActiveConnection = Controller::instance().activeConnection();
setupConnection();
});
loadEmojis();
loadEmojiHistory();
setupConnection();
}
void ImageContentManager::loadEmojis()
{
QFile file(":/data/emojis.json"_ls);
file.open(QFile::ReadOnly);
Q_ASSERT(file.isOpen());
auto data = QJsonDocument::fromJson(file.readAll()).array();
for (const auto &emoji : data) {
// TODO
// m_emojiPacks += ImagePackDescription{
// .description = parts[1],
// .attribution = {},
// .icon = parts[0],
// .type = ImagePackDescription::Emoji,
// .roomId = {},
// .stateKey = parts[2],
// };
m_emojis[u"TODO"_s] += Emoji{
.text = emoji[u"icon"_s].toString(),
.displayName = emoji[u"label"_s].toString(),
.shortName = emoji[u"label"_s].toString(), // TODO
};
}
}
void ImageContentManager::loadEmojiHistory()
{
auto config = KSharedConfig::openStateConfig();
auto group = config->group("RecentEmojis"_ls);
for (const auto &key : group.keyList()) {
m_usages[key] = group.readEntry(key).toInt();
}
}
void ImageContentManager::setupConnection()
{
if (!connection) {
return;
}
connect(Controller::instance().activeConnection(), &Connection::accountDataChanged, this, [this](const QString &type) {
if (type == "im.ponies.user_emotes"_ls) {
loadAccountImages();
}
if (type == "im.ponies.emote_rooms"_ls) {
loadGlobalPacks();
}
});
loadAccountImages();
loadGlobalPacks();
m_roomPacks.clear();
for (const auto &room : connection->allRooms()) {
setupRoom(static_cast<NeoChatRoom *>(room));
}
connect(connection, &Connection::joinedRoom, this, [this](const auto &room) {
setupRoom(static_cast<NeoChatRoom *>(room));
});
connect(connection, &Connection::leftRoom, this, [this](const auto &room) {
cleanupRoom(static_cast<NeoChatRoom *>(room));
});
}
const QVector<ImagePackDescription> &ImageContentManager::emojiPacks() const
{
return m_emojiPacks;
}
const QHash<QString, QVector<Emoji>> &ImageContentManager::emojis() const
{
return m_emojis;
}
void ImageContentManager::loadAccountImages()
{
m_accountImages.clear();
if (connection->hasAccountData("im.ponies.user_emotes"_ls)) {
m_accountImages = ImagePackEventContent(connection->accountData("im.ponies.user_emotes"_ls)->contentJson()).images;
}
Q_EMIT accountImagesChanged();
}
const QVector<ImagePackEventContent::ImagePackImage> &ImageContentManager::accountImages() const
{
return m_accountImages;
}
void ImageContentManager::emojiUsed(const QString &text)
{
if (!m_usages.contains(text)) {
m_usages[text] = 0;
}
m_usages[text]++;
Q_EMIT recentEmojisChanged();
auto config = KSharedConfig::openStateConfig();
auto group = config->group("RecentEmojis"_ls);
for (const auto &key : m_usages.keys()) {
group.writeEntry(key, m_usages[key]);
}
}
Emoji ImageContentManager::emojiForText(const QString &text)
{
for (const auto &category : m_emojis.values()) {
for (const auto &emoji : category) {
if (emoji.text == text) {
return emoji;
}
}
}
const auto &withSelector = QString::fromUtf8(text.toUtf8() + QByteArrayLiteral("\xEF\xB8\x8F"));
for (const auto &category : m_emojis.values()) {
for (const auto &emoji : category) {
if (emoji.text == withSelector) {
return emoji;
}
}
}
return {};
}
const QMap<QString, uint32_t> &ImageContentManager::recentEmojis() const
{
return m_usages;
}
const QMap<QString, QMap<QString, ImagePackDescription>> &ImageContentManager::roomImagePacks() const
{
return m_roomPacks;
}
void ImageContentManager::loadRoomImagePacks(NeoChatRoom *room)
{
const auto &events = room->currentState().eventsOfType("im.ponies.room_emotes"_ls);
m_roomPacks[room->id()].clear();
for (const auto &event : events) {
auto content = ImagePackEventContent(event->contentJson());
auto avatarMxc = event->contentPart<QJsonObject>("pack"_ls)["avatar_url"_ls].toString();
if (avatarMxc.isEmpty()) {
const auto &images = event->contentPart<QJsonObject>("images"_ls);
if (images.size() > 0) {
avatarMxc = images[images.keys()[0]]["url"_ls].toString();
}
}
const auto &avatarUrl = avatarMxc.isEmpty() ? QString() : Controller::instance().activeConnection()->makeMediaUrl(QUrl(avatarMxc)).toString();
ImagePackDescription::Type type = ImagePackDescription::Both;
if (!content.pack || !content.pack->usage || content.pack->usage->isEmpty()
|| (content.pack->usage->contains("emoticon"_ls) && content.pack->usage->contains("sticker"_ls))) {
type = ImagePackDescription::Both;
} else if (content.pack->usage->contains("sticker"_ls)) {
type = ImagePackDescription::Sticker;
} else {
type = ImagePackDescription::CustomEmoji;
}
m_roomPacks[room->id()][event->stateKey()] = ImagePackDescription{
.description = event->contentPart<QJsonObject>("pack"_ls)["display_name"_ls].toString(),
.attribution = {},
.icon = QStringLiteral("<img src=\"%1\" width=\"32\" height=\"32\"/>").arg(avatarUrl),
.type = type,
.roomId = room->id(),
.stateKey = event->stateKey(),
};
m_roomImages[{room->id(), event->stateKey()}] = content.images;
}
Q_EMIT roomImagePacksChanged(room);
}
const RoomImages &ImageContentManager::roomImages() const
{
return m_roomImages;
}
const QVector<std::pair<QString, QString>> &ImageContentManager::globalPacks() const
{
return m_globalPacks;
}
void ImageContentManager::loadGlobalPacks()
{
if (!connection->hasAccountData("im.ponies.emote_rooms"_ls)) {
return;
}
m_globalPacks.clear();
const auto &rooms = Controller::instance().activeConnection()->accountData("im.ponies.emote_rooms"_ls)->contentPart<QJsonObject>("rooms"_ls);
for (const auto &roomId : rooms.keys()) {
for (const auto &stateKey : rooms[roomId].toObject().keys()) {
m_globalPacks += {roomId, stateKey};
}
}
Q_EMIT globalPacksChanged();
}
void ImageContentManager::setupRoom(NeoChatRoom *room)
{
connect(room, &Room::changed, this, [this, room]() {
loadRoomImagePacks(room);
});
loadRoomImagePacks(room);
}
void ImageContentManager::cleanupRoom(NeoChatRoom *room)
{
m_roomPacks.remove(room->id());
Q_EMIT roomImagePacksChanged(room);
}
QString ImageContentManager::mxcForShortCode(const QString &shortcode) const
{
for (const auto &image : m_accountImages) {
if (image.shortcode == shortcode) {
return Controller::instance().activeConnection()->makeMediaUrl(image.url).toString();
}
}
for (const auto &id : m_roomImages.keys()) {
for (const auto &image : m_roomImages[id]) {
if (image.shortcode == shortcode) {
return Controller::instance().activeConnection()->makeMediaUrl(image.url).toString();
}
}
}
return {};
}
QString ImageContentManager::bodyForShortCode(const QString &shortcode) const
{
for (const auto &image : m_accountImages) {
if (image.shortcode == shortcode) {
return image.body.value_or(QString());
}
}
for (const auto &id : m_roomImages.keys()) {
for (const auto &image : m_roomImages[id]) {
if (image.shortcode == shortcode) {
return image.body.value_or(QString());
}
}
}
return {};
}
bool ImageContentManager::isEmojiShortCode(const QString &shortCode) const
{
for (const auto &image : m_accountImages) {
if (image.shortcode == shortCode) {
return !image.usage || image.usage->isEmpty() || image.usage->contains("emoticon"_ls);
}
}
for (const auto &id : m_roomImages.keys()) {
for (const auto &image : m_roomImages[id]) {
if (image.shortcode == shortCode) {
const auto pack = m_roomPacks[id.first][id.second];
return pack.type == ImagePackDescription::Emoji || pack.type == ImagePackDescription::Both;
}
}
}
return true;
}
bool ImageContentManager::isStickerShortCode(const QString &shortCode) const
{
for (const auto &image : m_accountImages) {
if (image.shortcode == shortCode) {
return !image.usage || image.usage->isEmpty() || image.usage->contains("sticker"_ls);
}
}
for (const auto &id : m_roomImages.keys()) {
for (const auto &image : m_roomImages[id]) {
if (image.shortcode == shortCode) {
const auto pack = m_roomPacks[id.first][id.second];
return pack.type == ImagePackDescription::Sticker || pack.type == ImagePackDescription::Both;
}
}
}
return true;
}
QString ImageContentManager::accountImagesAvatar() const
{
if (!connection->hasAccountData("im.ponies.user_emotes"_ls)) {
return {};
}
const auto &event = ImagePackEventContent(connection->accountData("im.ponies.user_emotes"_ls)->contentJson());
QString avatarUrl;
if (event.pack) {
avatarUrl = event.pack->avatarUrl.value_or(QUrl()).toString();
}
if (avatarUrl.isEmpty()) {
//TODO avatarUrl = Controller::instance().activeConnection()->user()->avatarUrl().toString();
}
if (avatarUrl.isEmpty()) {
avatarUrl = event.images[0].url.toString();
}
return QStringLiteral("👤");
}

View File

@@ -1,172 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QHash>
#include <QObject>
#include <QQmlEngine>
#include "events/imagepackevent.h"
#include "neochatroom.h"
#define imageContentManager ImageContentManager::instance()
class ImageContentRole : public QObject
{
Q_OBJECT
public:
enum ImageRoles {
DisplayNameRole = Qt::DisplayRole, /**< The name of the emoji. */
EmojiRole, /**< The unicode character of the emoji. */
ShortCodeRole,
IsCustomRole,
IsStickerRole,
IsEmojiRole,
UsageCountRole,
HasTonesRole,
};
Q_ENUM(ImageRoles);
};
class ImageContentPackRole : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
public:
//! Roles for the various models providing image packs.
enum ImagePackRoles {
DisplayNameRole = Qt::DisplayRole, //! Textual desription of the pack.
IconRole, //! Icon for the pack. For emojis, this is a unicode emoji; For custom emojis and stickers, this is a HTML image.
IdentifierRole, //! An internal, mostly opaque identifier for the model.
IsEmojiRole, //! Whether this pack contains emojis (including custom). For the account pack, this is true if the pack contains any emojis; for room
//! packs, this *only* considers the pack-level usage parameter
IsStickerRole, //! Equivalent to IsEmojiRole, but for stickers.
IsEmptyRole, //! Whether this image pack is empty.
IsGlobalPackRole, //! Whether this pack is enabled globally.
};
Q_ENUM(ImagePackRoles);
};
using RoomImages = QMap<std::pair<QString, QString>, QVector<Quotient::ImagePackEventContent::ImagePackImage>>;
struct Emoji {
Q_GADGET
Q_PROPERTY(QString text MEMBER text)
Q_PROPERTY(QString displayName MEMBER displayName)
Q_PROPERTY(QString shortName MEMBER shortName)
public:
QString text;
QString displayName;
QString shortName;
};
Q_DECLARE_METATYPE(Emoji)
struct ImagePackDescription {
enum Type {
Emoji,
CustomEmoji,
Sticker,
Both,
};
QString description;
QString attribution;
QString icon;
Type type;
// Only relevant for packs coming from rooms
QString roomId;
QString stateKey;
};
/**
* This class manages emojis, custom emojis, and stickers. Because naming things is hard, it has the most generic name possible.
*/
class ImageContentManager : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
public:
// Returns the global instance of ImageContentManager.
static ImageContentManager &instance()
{
static ImageContentManager _instance;
return _instance;
}
//! Returns a list of emoji packs (categories, e.g., food, smileys, etc.)
const QVector<ImagePackDescription> &emojiPacks() const;
//! Returns a map roomId -> stateKey -> description for all image packs that exist in rooms.
const QMap<QString, QMap<QString, ImagePackDescription>> &roomImagePacks() const;
//! Returns an list (roomId, stateKey) for all globally enabled room packs.
//! This is not filtered for rooms or stateKeys that do not exist. This is left to ImagePacksProxyModel
const QVector<std::pair<QString, QString>> &globalPacks() const;
//! Returns a map pack key -> [emoji] for all (normal) emojis.
const QHash<QString, QVector<Emoji>> &emojis() const;
//! Returns a list of all account images.
const QVector<Quotient::ImagePackEventContent::ImagePackImage> &accountImages() const;
//! Returns a map roomId -> stateKey -> [image] of all images part of a room image pack.
const RoomImages &roomImages() const;
//! Returns a map emoji -> usage count to be used as an emoji history.
const QMap<QString, uint32_t> &recentEmojis() const;
//! Returns the emoji object for the given unicode symbol.
Emoji emojiForText(const QString &text);
//! Updates the history when an emoji is used.
Q_INVOKABLE void emojiUsed(const QString &text);
QString mxcForShortCode(const QString &shortcode) const;
QString bodyForShortCode(const QString &shortcode) const;
bool isEmojiShortCode(const QString &shortCode) const;
bool isStickerShortCode(const QString &shortCode) const;
QString accountImagesAvatar() const;
Q_SIGNALS:
void accountImagesChanged();
void recentEmojisChanged();
void roomImagePacksChanged(NeoChatRoom *room);
void globalPacksChanged();
private:
// Packs
QVector<ImagePackDescription> m_emojiPacks;
// [roomId, stateKey]
QVector<std::pair<QString, QString>> m_globalPacks;
// roomId -> stateKey -> description
QMap<QString, QMap<QString, ImagePackDescription>> m_roomPacks;
// Emojis
// pack name -> emojis
QHash<QString, QVector<Emoji>> m_emojis;
QVector<Quotient::ImagePackEventContent::ImagePackImage> m_accountImages;
RoomImages m_roomImages;
// History
// emoji -> usage count
QMap<QString, uint32_t> m_usages;
// Loads both emojis and emoji packs
void loadEmojis();
void loadGlobalPacks();
void loadRoomImagePacks(NeoChatRoom *room);
void loadEmojiHistory();
void loadAccountImages();
void loadRoomImages();
ImageContentManager(QObject *parent = nullptr);
void setupConnection();
void setupRoom(NeoChatRoom *room);
void cleanupRoom(NeoChatRoom *room);
};

View File

@@ -13,7 +13,6 @@ 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,7 +7,6 @@ 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
@@ -91,27 +90,11 @@ Kirigami.Page {
id: loadedAccounts
model: AccountRegistry
delegate: FormCard.FormButtonDelegate {
id: delegate
required property string userId
required property NeoChatConnection connection
text: QmlUtils.escapeString(connection.localUser.displayName)
description: connection.localUser.id
leadingPadding: Kirigami.Units.largeSpacing
text: model.userId
onClicked: {
Controller.activeConnection = delegate.connection;
Controller.activeConnection = model.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

@@ -62,8 +62,6 @@
#include "fakerunner.h"
#endif
#include "imagecontentmanager.h"
#ifdef Q_OS_WINDOWS
#include <Windows.h>
#endif

View File

@@ -0,0 +1,104 @@
// 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

@@ -1,66 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "accountimagepackmodel.h"
#include <KLocalizedString>
#include "imagecontentmanager.h"
QVariant AccountImagePackModel::data(const QModelIndex &index, int role) const
{
Q_UNUSED(index);
if (role == ImageContentPackRole::DisplayNameRole) {
return i18n("Your Emojis");
}
if (role == ImageContentPackRole::IconRole) {
return imageContentManager.accountImagesAvatar();
}
if (role == ImageContentPackRole::IdentifierRole) {
return QStringLiteral("account");
}
if (role == ImageContentPackRole::IsEmojiRole) {
for (const auto &image : imageContentManager.accountImages()) {
if (!image.usage || image.usage->isEmpty() || image.usage->contains(QStringLiteral("emoticon"))) {
return true;
}
}
return false;
}
if (role == ImageContentPackRole::IsStickerRole) {
for (const auto &image : imageContentManager.accountImages()) {
if (!image.usage || image.usage->isEmpty() || image.usage->contains(QStringLiteral("sticker"))) {
return true;
}
}
return false;
}
if (role == ImageContentPackRole::IsEmptyRole) {
return imageContentManager.accountImages().size() == 0;
}
return {};
}
int AccountImagePackModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index);
return ImageContentManager::instance().accountImages().size() > 0 ? 1 : 0;
}
QHash<int, QByteArray> AccountImagePackModel::roleNames() const
{
return {
{ImageContentPackRole::DisplayNameRole, "displayName"},
{ImageContentPackRole::IconRole, "emoji"},
{ImageContentPackRole::IdentifierRole, "identifier"},
};
}
AccountImagePackModel::AccountImagePackModel(QObject *parent)
: QAbstractListModel(parent)
{
connect(&ImageContentManager::instance(), &ImageContentManager::accountImagesChanged, this, [this]() {
beginResetModel();
endResetModel();
});
}

View File

@@ -1,38 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QAbstractListModel>
class AccountImagePackModel : public QAbstractListModel
{
Q_OBJECT
/**
* Note: This model uses the ImagePackRoles from ImageContentManager as roles.
*/
public:
explicit AccountImagePackModel(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;
};

View File

@@ -600,19 +600,14 @@ 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(), {}, replaceId);
room->postHtmlMessage(messageText, originalString.replace(regex, replacement), event->msgtype(), {}, event->id());
} else {
room->postHtmlMessage(messageText,
originalString.replace(originalString.indexOf(regex), regex.size(), replacement),
event->msgtype(),
{},
replaceId);
event->id());
}
return true;
}

View File

@@ -1,56 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "allimagecontentmodel.h"
#include "imagecontentmanager.h"
// TODO custom emojis
AllImageContentModel::AllImageContentModel(QObject *parent)
: QAbstractListModel(parent)
{
// TODO connect to custom emojis changing;
}
QVariant AllImageContentModel::data(const QModelIndex &index, int role) const
{
auto row = index.row();
for (const auto &category : ImageContentManager::instance().emojis()) {
if (row >= category.size()) {
row -= category.size();
continue;
}
if (role == ImageContentRole::DisplayNameRole) {
return category[row].displayName;
}
if (role == ImageContentRole::EmojiRole) {
return category[row].text;
}
if (role == ImageContentRole::IsStickerRole) {
return false;
}
if (role == ImageContentRole::IsEmojiRole) {
return true;
}
}
return {};
}
int AllImageContentModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index);
auto sum = 0;
for (const auto &category : ImageContentManager::instance().emojis()) {
sum += category.size();
}
return sum;
}
QHash<int, QByteArray> AllImageContentModel::roleNames() const
{
return {
{ImageContentRole::DisplayNameRole, "displayName"},
{ImageContentRole::EmojiRole, "text"},
};
}

View File

@@ -1,35 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QAbstractListModel>
class AllImageContentModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit AllImageContentModel(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;
};

View File

@@ -6,7 +6,8 @@
#include "actionsmodel.h"
#include "completionproxymodel.h"
// #include "emojimodel.h"
#include "customemojimodel.h"
#include "emojimodel.h"
#include "neochatroom.h"
#include "roommanager.h"
#include "userlistmodel.h"
@@ -15,13 +16,11 @@ 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);
connect(this, &CompletionModel::roomChanged, this, [this]() {
m_userListModel->setRoom(m_room);
});
// TODO m_emojiModel->addSourceModel(&EmojiModel::instance());
m_emojiModel->addSourceModel(&CustomEmojiModel::instance());
m_emojiModel->addSourceModel(&EmojiModel::instance());
}
QString CompletionModel::text() const
@@ -86,23 +85,29 @@ QVariant CompletionModel::data(const QModelIndex &index, int role) const
return m_filterModel->data(filterIndex, RoomListModel::CanonicalAliasRole);
}
if (role == IconNameRole) {
return m_filterModel->data(filterIndex, RoomListModel::AvatarRole).toString();
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);
}
}
// 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 {};
}
@@ -148,8 +153,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);
// TODO m_filterModel->setSecondaryFilterRole(EmojiModel::DescriptionRole);
m_filterModel->setFilterRole(CustomEmojiModel::Name);
m_filterModel->setSecondaryFilterRole(EmojiModel::DescriptionRole);
m_filterModel->setFullText(m_fullText);
m_filterModel->setFilterText(m_text);
m_filterModel->invalidate();

View File

@@ -0,0 +1,116 @@
// 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,56 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "emojipacksmodel.h"
#include <QDebug>
#include <KLocalizedString>
#include "imagecontentmanager.h"
EmojiPacksModel::EmojiPacksModel(QObject *parent)
: QAbstractListModel(parent)
{
}
QVariant EmojiPacksModel::data(const QModelIndex &index, int role) const
{
const auto row = index.row();
const auto &category = ImageContentManager::instance().emojiPacks()[row];
if (role == ImageContentPackRole::DisplayNameRole) {
return category.description;
}
if (role == ImageContentPackRole::IconRole) {
return category.icon;
}
if (role == ImageContentPackRole::IdentifierRole) {
return category.stateKey;
}
if (role == ImageContentPackRole::IsStickerRole) {
return false;
}
if (role == ImageContentPackRole::IsEmojiRole) {
return true;
}
if (role == ImageContentPackRole::IsEmptyRole) {
return false;
}
return {};
}
int EmojiPacksModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index);
return ImageContentManager::instance().emojiPacks().count();
}
QHash<int, QByteArray> EmojiPacksModel::roleNames() const
{
return {
{ImageContentPackRole::DisplayNameRole, "displayName"},
{ImageContentPackRole::IconRole, "icon"},
{ImageContentPackRole::IdentifierRole, "identifier"},
};
}

View File

@@ -1,35 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QAbstractListModel>
class EmojiPacksModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit EmojiPacksModel(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;
};

View File

@@ -0,0 +1,57 @@
// 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,53 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "historyimagepackmodel.h"
#include <KLocalizedString>
#include "imagecontentmanager.h"
QVariant HistoryImagePackModel::data(const QModelIndex &index, int role) const
{
Q_UNUSED(index);
if (role == ImageContentPackRole::DisplayNameRole) {
return i18n("History");
}
if (role == ImageContentPackRole::IconRole) {
return QStringLiteral("");
}
if (role == ImageContentPackRole::IdentifierRole) {
return QStringLiteral("history");
}
if (role == ImageContentPackRole::IsStickerRole) {
return true;
}
if (role == ImageContentPackRole::IsEmojiRole) {
return true;
}
if (role == ImageContentPackRole::IsEmptyRole) {
//TODO listen?
return imageContentManager.recentEmojis().size() == 0;
}
return {};
}
int HistoryImagePackModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index);
return 1;
}
QHash<int, QByteArray> HistoryImagePackModel::roleNames() const
{
return {
{ImageContentPackRole::DisplayNameRole, "displayName"},
{ImageContentPackRole::IconRole, "emoji"},
{ImageContentPackRole::IdentifierRole, "identifier"},
};
}
HistoryImagePackModel::HistoryImagePackModel(QObject *parent)
: QAbstractListModel(parent)
{
}

View File

@@ -1,35 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QAbstractListModel>
class HistoryImagePackModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit HistoryImagePackModel(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;
};

View File

@@ -1,91 +0,0 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "imagecontentfiltermodel.h"
#include "imagecontentmanager.h"
ImageContentFilterModel::ImageContentFilterModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
updateSourceModel();
}
bool ImageContentFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
Q_UNUSED(sourceParent);
auto index = sourceModel()->index(sourceRow, 0);
return ((index.data(ImageContentRole::IsEmojiRole).toBool() && emojis()) || (index.data(ImageContentRole::IsStickerRole).toBool() && stickers()))
&& sourceModel()->index(sourceRow, 0).data(ImageContentRole::DisplayNameRole).toString().contains(m_searchText, Qt::CaseInsensitive);
}
bool ImageContentFilterModel::stickers() const
{
return m_stickers;
}
void ImageContentFilterModel::setStickers(bool stickers)
{
m_stickers = stickers;
Q_EMIT stickersChanged();
invalidateFilter();
}
bool ImageContentFilterModel::emojis() const
{
return m_emojis;
}
void ImageContentFilterModel::setEmojis(bool emojis)
{
m_emojis = emojis;
Q_EMIT emojisChanged();
invalidateFilter();
}
void ImageContentFilterModel::setCategory(const QString &category)
{
if (category == m_category) {
return;
}
m_category = category;
Q_EMIT categoryChanged();
updateSourceModel();
}
QString ImageContentFilterModel::category() const
{
return m_category;
}
void ImageContentFilterModel::setSearchText(const QString &searchText)
{
if (searchText == m_searchText) {
return;
}
m_searchText = searchText;
Q_EMIT searchTextChanged();
invalidateFilter();
updateSourceModel();
}
QString ImageContentFilterModel::searchText() const
{
return m_searchText;
}
void ImageContentFilterModel::updateSourceModel()
{
if (!m_searchText.isEmpty()) {
if (sourceModel() != &m_allImageContentModel) {
setSourceModel(&m_allImageContentModel);
}
} else if (m_category == QStringLiteral("history")) {
setSourceModel(&m_recentImageContentProxyModel);
} else {
if (sourceModel() != &m_imageContentModel) {
setSourceModel(&m_imageContentModel);
}
m_imageContentModel.setCategory(m_category);
}
}

View File

@@ -1,57 +0,0 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QSortFilterProxyModel>
#include <QQmlEngine>
#include "allimagecontentmodel.h"
#include "imagecontentmodel.h"
#include "recentimagecontentproxymodel.h"
class ImageContentFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(bool stickers READ stickers WRITE setStickers NOTIFY stickersChanged)
Q_PROPERTY(bool emojis READ emojis WRITE setEmojis NOTIFY emojisChanged)
Q_PROPERTY(QString category READ category WRITE setCategory NOTIFY categoryChanged)
Q_PROPERTY(QString searchText READ searchText WRITE setSearchText NOTIFY searchTextChanged)
public:
explicit ImageContentFilterModel(QObject *parent = nullptr);
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
[[nodiscard]] bool stickers() const;
void setStickers(bool stickers);
[[nodiscard]] bool emojis() const;
void setEmojis(bool emojis);
QString category() const;
void setCategory(const QString &category);
QString searchText() const;
void setSearchText(const QString &text);
Q_SIGNALS:
void stickersChanged();
void emojisChanged();
void categoryChanged();
void searchTextChanged();
private:
bool m_stickers = true;
bool m_emojis = true;
QString m_category;
QString m_searchText;
AllImageContentModel m_allImageContentModel;
RecentImageContentProxyModel m_recentImageContentProxyModel;
ImageContentModel m_imageContentModel;
void updateSourceModel();
};

View File

@@ -1,164 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "imagecontentmodel.h"
#include <QDebug>
#include <Quotient/connection.h>
#include "controller.h"
#include "imagecontentmanager.h"
ImageContentModel::ImageContentModel(QObject *parent)
: QAbstractListModel(parent)
{
}
int ImageContentModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
if (m_category == QStringLiteral("account")) {
return imageContentManager.accountImages().size();
}
if (m_category.contains(u'@')) {
return imageContentManager.roomImages()[{m_roomId, m_stateKey}].size();
}
return imageContentManager.emojis()[m_category].count();
}
QVariant ImageContentModel::emojiData(int row, int role) const
{
const auto emoji = imageContentManager.emojis()[m_category][row];
if (role == ImageContentRole::DisplayNameRole) {
return emoji.displayName;
}
if (role == ImageContentRole::EmojiRole) {
return emoji.text;
}
if (role == ImageContentRole::IsCustomRole) {
return false;
}
if (role == ImageContentRole::IsEmojiRole) {
return true;
}
if (role == ImageContentRole::IsStickerRole) {
return false;
}
if (role == ImageContentRole::HasTonesRole) {
return true; // TODO
}
return {};
}
QVariant ImageContentModel::accountData(int row, int role) const
{
const auto &image = imageContentManager.accountImages()[row];
if (role == ImageContentRole::DisplayNameRole) {
return image.shortcode;
}
if (role == ImageContentRole::EmojiRole) {
return QStringLiteral("<img src=\"%1\" height=\"32\" width=\"32\"/>")
.arg(Controller::instance().activeConnection()->makeMediaUrl(image.url).toString());
}
if (role == ImageContentRole::ShortCodeRole) {
return image.shortcode;
}
if (role == ImageContentRole::IsCustomRole) {
return true;
}
if (role == ImageContentRole::IsEmojiRole) {
return !image.usage || image.usage->isEmpty() || image.usage->contains(QStringLiteral("emoticon"));
}
if (role == ImageContentRole::IsStickerRole) {
return !image.usage || image.usage->isEmpty() || image.usage->contains(QStringLiteral("sticker"));
}
return {};
}
QVariant ImageContentModel::roomData(int row, int role) const
{
const auto image = imageContentManager.roomImages()[{m_roomId, m_stateKey}][row];
if (role == ImageContentRole::DisplayNameRole) {
return image.shortcode;
}
if (role == ImageContentRole::EmojiRole) {
return QStringLiteral("<img src=\"%1\" height=\"32\" width=\"32\"/>")
.arg(Controller::instance().activeConnection()->makeMediaUrl(image.url).toString());
}
if (role == ImageContentRole::ShortCodeRole) {
return image.shortcode;
}
if (role == ImageContentRole::IsCustomRole) {
return true;
}
if (role == ImageContentRole::IsEmojiRole) {
return true; // For room image packs, we're ignoring the usage of the individual images.
}
if (role == ImageContentRole::IsStickerRole) {
return true;
}
return {};
}
QVariant ImageContentModel::data(const QModelIndex &index, int role) const
{
const auto &row = index.row();
if (m_category == QStringLiteral("account")) {
return accountData(row, role);
}
if (m_category.contains(u'@')) {
return roomData(row, role);
}
return emojiData(row, role);
}
QHash<int, QByteArray> ImageContentModel::roleNames() const
{
return {
{ImageContentRole::DisplayNameRole, "displayName"},
{ImageContentRole::EmojiRole, "text"},
{ImageContentRole::ShortCodeRole, "shortCode"},
{ImageContentRole::IsCustomRole, "isCustom"},
{ImageContentRole::IsStickerRole, "isSticker"},
{ImageContentRole::IsEmojiRole, "isEmoji"},
{ImageContentRole::HasTonesRole, "hasTones"},
};
}
QString ImageContentModel::category() const
{
return m_category;
}
void ImageContentModel::setCategory(const QString &category)
{
if (category == m_category) {
return;
}
beginResetModel();
m_category = category;
if (m_category.contains(u'@')) {
const auto &split = m_category.split(u'@');
m_roomId = split[0];
m_stateKey = split[1];
} else {
m_roomId = QString();
m_stateKey = QString();
}
endResetModel();
if (m_category == QStringLiteral("account")) {
connect(&ImageContentManager::instance(), &ImageContentManager::accountImagesChanged, this, [this]() {
beginResetModel();
endResetModel();
});
} else {
disconnect(&ImageContentManager::instance(), &ImageContentManager::accountImagesChanged, this, nullptr);
}
Q_EMIT categoryChanged();
}
#include "moc_imagecontentmodel.cpp"

View File

@@ -1,60 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QAbstractListModel>
#include <QObject>
#include <QQmlEngine>
/**
* @class ImageContentModel
*
* This class defines the model for visualising a list of emojis.
*/
class ImageContentModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString category READ category WRITE setCategory NOTIFY categoryChanged)
public:
ImageContentModel(QObject *parent = nullptr);
/**
* @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;
[[nodiscard]] QString category() const;
void setCategory(const QString &category);
QVariant emojiData(int row, int role) const;
QVariant accountData(int row, int role) const;
QVariant roomData(int row, int role) const;
Q_SIGNALS:
void categoryChanged();
private:
QString m_category;
QString m_roomId;
QString m_stateKey;
};

View File

@@ -1,68 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "imagepackroomsmodel.h"
#include <Quotient/connection.h>
#include <Quotient/room.h>
#include "controller.h"
#include "imagecontentmanager.h"
using namespace Quotient;
ImagePackRoomsModel::ImagePackRoomsModel(QObject *parent)
: QAbstractListModel(parent)
{
connect(&imageContentManager, &ImageContentManager::globalPacksChanged, this, [this]() {
beginResetModel();
endResetModel();
});
}
QVariant ImagePackRoomsModel::data(const QModelIndex &index, int role) const
{
const auto &row = index.row();
const auto &packKey = imageContentManager.globalPacks()[row];
if (!imageContentManager.roomImagePacks().contains(packKey.first) || !imageContentManager.roomImagePacks()[packKey.first].contains(packKey.second)) {
return false;
}
const auto &pack = imageContentManager.roomImagePacks()[packKey.first][packKey.second];
if (role == ImageContentPackRole::DisplayNameRole) {
return pack.description;
}
if (role == ImageContentPackRole::IconRole) {
return pack.icon;
}
if (role == ImageContentPackRole::IdentifierRole) {
return QStringLiteral("%1@%2").arg(pack.roomId, pack.stateKey);
}
if (role == ImageContentPackRole::IsStickerRole) {
return pack.type == ImagePackDescription::Sticker;
}
if (role == ImageContentPackRole::IsEmojiRole) {
return pack.type == ImagePackDescription::Emoji || pack.type == ImagePackDescription::CustomEmoji;
}
if (role == ImageContentPackRole::IsEmptyRole) {
return imageContentManager.roomImages()[packKey].size() == 0;
}
if (role == ImageContentPackRole::IsGlobalPackRole) {
return true;
}
return {};
}
int ImagePackRoomsModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index);
return imageContentManager.globalPacks().size();
}
QHash<int, QByteArray> ImagePackRoomsModel::roleNames() const
{
return {
{ImageContentPackRole::DisplayNameRole, "displayName"},
{ImageContentPackRole::IconRole, "emoji"}, // TODO rename
{ImageContentPackRole::IdentifierRole, "identifier"},
};
}

View File

@@ -1,42 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "imagecontentmanager.h"
#include <QAbstractListModel>
/**
* Lists the custom emoji/sticker packs from other rooms as marked in the account data.
* Not to be confused with the packs for this room (-> RoomEmoticonsCategoryModel)
*
* Note: This model uses the ImagePackRoles from ImageContentManager as roles.
*/
class ImagePackRoomsModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ImagePackRoomsModel(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;
};

View File

@@ -1,43 +1,170 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2021 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "imagepacksmodel.h"
#include "neochatroom.h"
#include "models/accountimagepackmodel.h"
#include "models/emojipacksmodel.h"
#include "models/historyimagepackmodel.h"
#include "models/imagepackroomsmodel.h"
#include "models/roomimagepacksmodel.h"
#include <KLocalizedString>
using namespace Quotient;
ImagePacksModel::ImagePacksModel(QObject *parent)
: QConcatenateTablesProxyModel(parent)
: QAbstractListModel(parent)
{
addSourceModel(new HistoryImagePackModel(parent));
addSourceModel(new AccountImagePackModel(parent));
m_roomImagePacksModel = new RoomImagePacksModel(parent);
addSourceModel(m_roomImagePacksModel);
addSourceModel(new ImagePackRoomsModel(parent));
addSourceModel(new EmojiPacksModel(parent));
}
// TODO required?
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 {
{ImageContentPackRole::DisplayNameRole, "displayName"},
{ImageContentPackRole::IconRole, "icon"},
{ImageContentPackRole::IdentifierRole, "identifier"},
{DisplayNameRole, "displayName"},
{AvatarUrlRole, "avatarUrl"},
{AttributionRole, "attribution"},
{IdRole, "id"},
};
}
NeoChatRoom *ImagePacksModel::currentRoom() const
NeoChatRoom *ImagePacksModel::room() const
{
return m_roomImagePacksModel->currentRoom();
return m_room;
}
void ImagePacksModel::setCurrentRoom(NeoChatRoom *currentRoom)
void ImagePacksModel::setRoom(NeoChatRoom *room)
{
m_roomImagePacksModel->setCurrentRoom(currentRoom);
Q_EMIT currentRoomChanged();
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,7 +1,7 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2021-2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include <QConcatenateTablesProxyModel>
#pragma once
#include "events/imagepackevent.h"
#include <QAbstractListModel>
@@ -9,26 +9,95 @@
#include <QPointer>
#include <QQmlEngine>
#include "neochatroom.h"
class NeoChatRoom;
class RoomImagePacksModel;
class ImagePacksModel : public QConcatenateTablesProxyModel
/**
* @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
Q_PROPERTY(NeoChatRoom *currentRoom READ currentRoom WRITE setCurrentRoom NOTIFY currentRoomChanged)
/**
* @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:
ImagePacksModel(QObject *parent = nullptr);
QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] NeoChatRoom *currentRoom() const;
void setCurrentRoom(NeoChatRoom *currentRoom);
/**
* @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 currentRoomChanged();
void roomChanged();
void showStickersChanged();
void showEmoticonsChanged();
void imagesLoaded();
private:
RoomImagePacksModel *m_roomImagePacksModel = nullptr;
QPointer<NeoChatRoom> m_room;
QList<Quotient::ImagePackEventContent> m_events;
bool m_showStickers = true;
bool m_showEmoticons = true;
void reloadImages();
};

View File

@@ -1,67 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "imagepacksproxymodel.h"
#include "imagecontentmanager.h"
#include "imagepacksmodel.h"
#include "neochatroom.h"
ImagePacksProxyModel::ImagePacksProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
setSourceModel(new ImagePacksModel(this));
}
bool ImagePacksProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
Q_UNUSED(sourceParent);
const auto &identifier = sourceModel()->data(sourceModel()->index(sourceRow, 0), ImageContentPackRole::IdentifierRole).toString();
if (identifier.contains(u'@')) {
const auto roomId = identifier.split(u'@')[0];
if (static_cast<ImagePacksModel *>(sourceModel())->currentRoom() && roomId == static_cast<ImagePacksModel *>(sourceModel())->currentRoom()->id()
&& sourceModel()->data(sourceModel()->index(sourceRow, 0), ImageContentPackRole::IsGlobalPackRole).toBool()) {
// Hide this pack, as it's already exposed as a global pack
return false;
}
}
return ((sourceModel()->data(sourceModel()->index(sourceRow, 0), ImageContentPackRole::IsEmojiRole).toBool() && emojis())
|| (sourceModel()->data(sourceModel()->index(sourceRow, 0), ImageContentPackRole::IsStickerRole).toBool() && stickers()));
}
bool ImagePacksProxyModel::stickers() const
{
return m_stickers;
}
void ImagePacksProxyModel::setStickers(bool stickers)
{
m_stickers = stickers;
Q_EMIT stickersChanged();
invalidateFilter();
}
bool ImagePacksProxyModel::emojis() const
{
return m_emojis;
}
void ImagePacksProxyModel::setEmojis(bool emojis)
{
m_emojis = emojis;
Q_EMIT emojisChanged();
invalidateFilter();
}
NeoChatRoom *ImagePacksProxyModel::currentRoom() const
{
return static_cast<ImagePacksModel *>(sourceModel())->currentRoom();
}
void ImagePacksProxyModel::setCurrentRoom(NeoChatRoom *currentRoom)
{
beginResetModel();
static_cast<ImagePacksModel *>(sourceModel())->setCurrentRoom(currentRoom);
endResetModel();
Q_EMIT currentRoomChanged();
}

View File

@@ -1,43 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QSortFilterProxyModel>
#include <QQmlEngine>
class NeoChatRoom;
/**
* Filters image packs on whether they contain stickers or emojis, depending on the respective properties
*/
class ImagePacksProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(bool stickers READ stickers WRITE setStickers NOTIFY stickersChanged)
Q_PROPERTY(bool emojis READ emojis WRITE setEmojis NOTIFY emojisChanged)
Q_PROPERTY(NeoChatRoom *currentRoom READ currentRoom WRITE setCurrentRoom NOTIFY currentRoomChanged)
public:
explicit ImagePacksProxyModel(QObject *parent = nullptr);
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
[[nodiscard]] bool stickers() const;
void setStickers(bool stickers);
[[nodiscard]] bool emojis() const;
void setEmojis(bool emojis);
[[nodiscard]] NeoChatRoom *currentRoom() const;
void setCurrentRoom(NeoChatRoom *currentRoom);
Q_SIGNALS:
void stickersChanged();
void emojisChanged();
void currentRoomChanged();
private:
bool m_stickers = true;
bool m_emojis = true;
};

View File

@@ -588,22 +588,15 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
case MessageComponentType::Video: {
if (!event.first->is<StickerEvent>()) {
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event.first);
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;
}
}
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;
}
}
default:

View File

@@ -1,73 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "recentimagecontentmodel.h"
#include "imagecontentmanager.h"
RecentImageContentModel::RecentImageContentModel(QObject *parent)
: QAbstractListModel(parent)
{
connect(&ImageContentManager::instance(), &ImageContentManager::recentEmojisChanged, this, [this]() {
beginResetModel();
endResetModel();
});
}
QVariant RecentImageContentModel::data(const QModelIndex &index, int role) const
{
const auto &recent = ImageContentManager::instance().recentEmojis();
const auto row = index.row();
const bool isCustom = recent.keys()[row].startsWith(QLatin1Char(':'));
if (role == ImageContentRole::DisplayNameRole) {
if (isCustom) {
return imageContentManager.bodyForShortCode(recent.keys()[row].mid(1).chopped(1));
}
return ImageContentManager::instance().emojiForText(recent.keys()[row]).displayName;
}
if (role == ImageContentRole::EmojiRole) {
if (isCustom) {
return QStringLiteral("<img src=\"%1\" width=\"32\" height=\"32\"/>")
.arg(imageContentManager.mxcForShortCode(recent.keys()[row].mid(1).chopped(1)));
}
return recent.keys()[row];
}
if (role == ImageContentRole::UsageCountRole) {
return recent[recent.keys()[row]];
}
if (role == ImageContentRole::ShortCodeRole) {
return recent.keys()[row].mid(1).chopped(1);
}
if (role == ImageContentRole::IsCustomRole) {
return isCustom;
}
if (role == ImageContentRole::IsEmojiRole) {
if (!isCustom)
return true;
return imageContentManager.isEmojiShortCode(recent.keys()[row].mid(1).chopped(1));
}
if (role == ImageContentRole::IsStickerRole) {
if (!isCustom)
return false;
return imageContentManager.isStickerShortCode(recent.keys()[row].mid(1).chopped(1));
}
return {};
}
int RecentImageContentModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index);
return ImageContentManager::instance().recentEmojis().size();
}
QHash<int, QByteArray> RecentImageContentModel::roleNames() const
{
return {
{ImageContentRole::DisplayNameRole, "displayName"},
{ImageContentRole::EmojiRole, "text"},
{ImageContentRole::UsageCountRole, "usageCount"},
{ImageContentRole::ShortCodeRole, "shortCode"},
{ImageContentRole::IsCustomRole, "isCustom"},
};
}

View File

@@ -1,38 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QAbstractListModel>
/**
* Lists the previously used emojis in no specific order.
*/
class RecentImageContentModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit RecentImageContentModel(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;
};

View File

@@ -1,19 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "recentimagecontentproxymodel.h"
#include "imagecontentmanager.h"
#include "recentimagecontentmodel.h"
RecentImageContentProxyModel::RecentImageContentProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
setSourceModel(new RecentImageContentModel(this));
sort(0);
}
bool RecentImageContentProxyModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const
{
return sourceLeft.data(ImageContentRole::UsageCountRole).toInt() > sourceRight.data(ImageContentRole::UsageCountRole).toInt();
}

View File

@@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QSortFilterProxyModel>
#include <QQmlEngine>
class RecentImageContentProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
QML_ELEMENT
public:
explicit RecentImageContentProxyModel(QObject *parent = nullptr);
bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
};

View File

@@ -1,86 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "roomimagepacksmodel.h"
#include "imagecontentmanager.h"
#include "neochatroom.h"
NeoChatRoom *RoomImagePacksModel::currentRoom() const
{
return m_currentRoom;
}
void RoomImagePacksModel::setCurrentRoom(NeoChatRoom *currentRoom)
{
if (m_currentRoom == currentRoom) {
return;
}
if (m_currentRoom) {
disconnect(m_currentRoom, nullptr, this, nullptr);
}
beginResetModel();
m_currentRoom = currentRoom;
endResetModel();
Q_EMIT currentRoomChanged();
}
QVariant RoomImagePacksModel::data(const QModelIndex &index, int role) const
{
Q_UNUSED(index);
if (!m_currentRoom) {
return {};
}
const auto row = index.row();
const auto &packs = ImageContentManager::instance().roomImagePacks()[m_currentRoom->id()].values();
const auto &pack = packs[row];
if (role == ImageContentPackRole::DisplayNameRole) {
return pack.description;
}
if (role == ImageContentPackRole::IconRole) {
return pack.icon;
}
if (role == ImageContentPackRole::IdentifierRole) {
return QStringLiteral("%1@%2").arg(m_currentRoom->id(), pack.stateKey);
}
if (role == ImageContentPackRole::IsStickerRole) {
return pack.type == ImagePackDescription::Sticker || pack.type == ImagePackDescription::Both;
}
if (role == ImageContentPackRole::IsEmojiRole) {
return pack.type == ImagePackDescription::Emoji || pack.type == ImagePackDescription::CustomEmoji || pack.type == ImagePackDescription::Both;
}
if (role == ImageContentPackRole::IsEmptyRole) {
return imageContentManager.roomImages()[{m_currentRoom->id(), pack.stateKey}].isEmpty();
}
return {};
}
int RoomImagePacksModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index);
if (!m_currentRoom) {
return {};
}
return ImageContentManager::instance().roomImagePacks()[m_currentRoom->id()].size();
}
QHash<int, QByteArray> RoomImagePacksModel::roleNames() const
{
return {
{ImageContentPackRole::DisplayNameRole, "displayName"},
{ImageContentPackRole::IconRole, "emoji"},
{ImageContentPackRole::IdentifierRole, "identifier"},
};
}
RoomImagePacksModel::RoomImagePacksModel(QObject *parent)
: QAbstractListModel(parent)
{
connect(&ImageContentManager::instance(), &ImageContentManager::roomImagePacksChanged, this, [this](NeoChatRoom *room) {
if (room != m_currentRoom) {
return;
}
beginResetModel();
endResetModel();
});
}

View File

@@ -1,50 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QAbstractListModel>
#include <QPointer>
class NeoChatRoom;
/**
* Note: This model uses the ImagePackRoles from ImageContentManager as roles.
*/
class RoomImagePacksModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit RoomImagePacksModel(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 *currentRoom() const;
void setCurrentRoom(NeoChatRoom *currentRoom);
Q_SIGNALS:
void currentRoomChanged();
private:
QPointer<NeoChatRoom> m_currentRoom;
};

View File

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

View File

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

View File

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

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, as a mxc:// URL.
* @brief The avatar image to be used for the room.
*/
Q_PROPERTY(QUrl avatarMediaUrl READ avatarMediaUrl NOTIFY avatarChanged STORED false)
Q_PROPERTY(QString avatarMediaId READ avatarMediaId 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]] QUrl avatarMediaUrl() const;
[[nodiscard]] QString avatarMediaId() const;
NeochatRoomMember *directChatRemoteMember();

View File

@@ -153,6 +153,15 @@ 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,6 +70,7 @@ public:
int hue() const;
qreal hueF() const;
QColor color() const;
QString avatarMediaId() const;
QUrl avatarUrl() const;
Q_SIGNALS:

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