diff --git a/CMakeLists.txt b/CMakeLists.txt index 7295cc54a6578373dbdcadf3d0fb42f62b0f0131..fe686ddffbd7455ecf6fc989e22a02bd7dca5580 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,7 +304,6 @@ set(SRC_FILES src/SideBarActions.cpp src/Splitter.cpp src/TextInputWidget.cpp - src/TopRoomBar.cpp src/TrayIcon.cpp src/UserInfoWidget.cpp src/UserSettingsPage.cpp @@ -341,7 +340,7 @@ if(USE_BUNDLED_MTXCLIENT) FetchContent_Declare( MatrixClient GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git - GIT_TAG d8666a3f1a5b709b78ccea2b545d540a8cb502ca + GIT_TAG ac680e971d437eb2135ef994dcb58c0bbb5bdf61 ) FetchContent_MakeAvailable(MatrixClient) else() @@ -512,7 +511,6 @@ qt5_wrap_cpp(MOC_HEADERS src/SideBarActions.h src/Splitter.h src/TextInputWidget.h - src/TopRoomBar.h src/TrayIcon.h src/UserInfoWidget.h src/UserSettingsPage.h diff --git a/README.md b/README.md index fb0167c8deac7dff6ee139c6d94ab72c3935598f..2d24165c5924de44498d3ba80b1ef19769ce3d9d 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ Nheko can use bundled version for most of those libraries automatically, if the To use them, you can enable the hunter integration by passing `-DHUNTER_ENABLED=ON`. It is probably wise to link those dependencies statically by passing `-DBUILD_SHARED_LIBS=OFF` You can select which bundled dependencies you want to use py passing various `-DUSE_BUNDLED_*` flags. By default all dependencies are bundled *if* you enable hunter. +If you experience build issues and you are trying to link `mtxclient` library without hunter, make sure the library version(commit) as mentioned in the `CMakeList.txt` is used. Sometimes we have to make breaking changes in `mtxclient` and for that period the master branch of both repos may not be compatible. The bundle flags are currently: diff --git a/io.github.NhekoReborn.Nheko.json b/io.github.NhekoReborn.Nheko.json index b11e587c19887dd6ab2e5d64c2bfb28547f8b36a..8ff8263627c241ca06029a745d0b7fc9a7485eca 100644 --- a/io.github.NhekoReborn.Nheko.json +++ b/io.github.NhekoReborn.Nheko.json @@ -146,7 +146,7 @@ "name": "mtxclient", "sources": [ { - "commit": "d8666a3f1a5b709b78ccea2b545d540a8cb502ca", + "commit": "ac680e971d437eb2135ef994dcb58c0bbb5bdf61", "type": "git", "url": "https://github.com/Nheko-Reborn/mtxclient.git" } diff --git a/resources/langs/nheko_cs.ts b/resources/langs/nheko_cs.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab0b22df788255d74a9f7072e0ede81496a4f49c --- /dev/null +++ b/resources/langs/nheko_cs.ts @@ -0,0 +1,1860 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="cs"> +<context> + <name>Cache</name> + <message> + <location filename="../../src/Cache.cpp" line="+1359"/> + <source>You joined this room.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ChatPage</name> + <message> + <location filename="../../src/ChatPage.cpp" line="+229"/> + <source>Failed to invite user: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <location line="+926"/> + <source>Invited user: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-474"/> + <source>Migrating the cache to the current version failed. This can have different reasons. Please open an issue and try to use an older version in the mean time. Alternatively you can try deleting the cache manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+439"/> + <source>Room %1 created.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+30"/> + <source>Failed to invite %1 to %2: %3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+19"/> + <source>Failed to kick %1 to %2: %3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Kicked user: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+14"/> + <source>Failed to ban %1 in %2: %3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Banned user: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+14"/> + <source>Failed to unban %1 in %2: %3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Unbanned user: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-828"/> + <source>Failed to upload media. Please try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+296"/> + <source>Cache migration failed!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> + <source>Incompatible cache version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>The cache on your disk is newer than this version of Nheko supports. Please update or clear your cache.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+111"/> + <source>Failed to restore OLM account. Please login again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Failed to restore save data. Please login again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+156"/> + <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+54"/> + <location line="+252"/> + <source>Please try to login again: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-187"/> + <source>Failed to join room: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You joined the room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Failed to remove invite: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+19"/> + <source>Room creation failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> + <source>Failed to leave room: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CommunitiesListItem</name> + <message> + <location filename="../../src/CommunitiesListItem.cpp" line="+133"/> + <source>All rooms</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Favourite rooms</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Low priority rooms</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Server Notices</source> + <comment>Tag translation for m.server_notice</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <location line="+2"/> + <source> (tag)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source> (community)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditModal</name> + <message> + <location filename="../../src/dialogs/RoomSettings.cpp" line="+72"/> + <source>Apply</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Topic</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EmojiPicker</name> + <message> + <location filename="../qml/emoji/EmojiPicker.qml" line="+117"/> + <location line="+139"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-42"/> + <source>People</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Nature</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Food</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Activity</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Travel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Objects</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Symbols</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EncryptionIndicator</name> + <message> + <location filename="../qml/EncryptionIndicator.qml" line="+36"/> + <source>Encrypted</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>This message is not encrypted!</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InviteeItem</name> + <message> + <location filename="../../src/InviteeItem.cpp" line="+18"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LoginPage</name> + <message> + <location filename="../../src/LoginPage.cpp" line="+90"/> + <source>Matrix ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>e.g @joe:matrix.org</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Your login name. A mxid should start with @ followed by the user id. After the user id you need to include your server name after a :. +You can also put your homeserver address there, if your server doesn't support .well-known lookup. +Example: @user:server.my +If Nheko fails to discover your homeserver, it will show you a field to enter the server manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+21"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Device name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>A name for this device, which will be shown to others, when verifying your devices. If none is provided a default is used.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>The address that can be used to contact you homeservers client API. +Example: https://server.my:8787</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> + <location line="+191"/> + <source>LOGIN</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-100"/> + <source>Autodiscovery failed. Received malformed response.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Autodiscovery failed. Unknown error when requesting .well-known.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+25"/> + <source>The required endpoints were not found. Possibly not a Matrix server.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Received malformed response. Make sure the homeserver domain is valid.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>An unknown error occured. Make sure the homeserver domain is valid.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+55"/> + <source>SSO LOGIN</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+25"/> + <source>Empty password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+52"/> + <source>SSO login failed</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MemberList</name> + <message> + <location filename="../../src/dialogs/MemberList.cpp" line="+90"/> + <source>Room members</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDelegate</name> + <message> + <location filename="../qml/delegates/MessageDelegate.qml" line="+66"/> + <source>redacted</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Encryption enabled</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>room name changed to: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>removed room name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>topic changed to: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>removed topic</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>%1 created and configured room: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>%1 placed a %2 call.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>%1 answered the call.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>%1 ended the call.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Placeholder</name> + <message> + <location filename="../qml/delegates/Placeholder.qml" line="+4"/> + <source>unimplemented event: </source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuickSwitcher</name> + <message> + <location filename="../../src/QuickSwitcher.cpp" line="+74"/> + <source>Search for a room...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RegisterPage</name> + <message> + <location filename="../../src/RegisterPage.cpp" line="+88"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>The username must not be empty, and must contain only the characters a-z, 0-9, ., _, =, -, and /.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Please choose a secure password. The exact requirements for password strength may depend on your server.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Password confirmation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Homeserver</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>A server that allows registration. Since matrix is decentralized, you need to first find a server you can register on or host your own.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> + <source>REGISTER</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+55"/> + <source>No supported registration flows!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+135"/> + <source>Invalid username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Password is not long enough (min 8 chars)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Passwords don't match</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Invalid server name</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RoomInfo</name> + <message> + <location filename="../../src/Cache.cpp" line="+984"/> + <source>no version stored</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RoomInfoListItem</name> + <message> + <location filename="../../src/RoomInfoListItem.cpp" line="+102"/> + <source>Leave room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Tag room as:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+18"/> + <source>Favourite</source> + <comment>Standard matrix tag for favourites</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Low Priority</source> + <comment>Standard matrix tag for low priority rooms</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Server Notice</source> + <comment>Standard matrix tag for server notices</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>Adds or removes the specified tag.</source> + <comment>WhatsThis hint for tag menu actions</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+38"/> + <source>New tag...</source> + <comment>Add a new tag to the room</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>New Tag</source> + <comment>Tag name prompt title</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Tag:</source> + <comment>Tag name prompt</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+173"/> + <source>Accept</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Decline</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SideBarActions</name> + <message> + <location filename="../../src/SideBarActions.cpp" line="+40"/> + <source>User settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Create new room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Join a room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> + <source>Start a new chat</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+15"/> + <source>Room directory</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>StatusIndicator</name> + <message> + <location filename="../qml/StatusIndicator.qml" line="+14"/> + <source>Failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Sent</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Received</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Read</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TextInputWidget</name> + <message> + <location filename="../../src/TextInputWidget.cpp" line="+460"/> + <source>Send a file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> + <location filename="../../src/TextInputWidget.h" line="+145"/> + <source>Write a message...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> + <source>Send a message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Emoji</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+86"/> + <source>Select a file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../../src/TextInputWidget.h" line="-5"/> + <source>Connection lost. Nheko is trying to re-connect...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TimelineModel</name> + <message> + <location filename="../../src/timeline/TimelineModel.cpp" line="+891"/> + <source>-- Decryption Error (failed to communicate with DB) --</source> + <comment>Placeholder, when the message can't be decrypted, because the DB access failed when trying to lookup the session.</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+20"/> + <source>-- Decryption Error (failed to retrieve megolm keys from db) --</source> + <comment>Placeholder, when the message can't be decrypted, because the DB access failed.</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> + <source>-- Decryption Error (%1) --</source> + <comment>Placeholder, when the message can't be decrypted. In this case, the Olm decrytion returned an error, which is passed ad %1.</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+99"/> + <source>Message redaction failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+488"/> + <source>Save image</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Save video</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Save audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Save file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-643"/> + <source>-- Encrypted Event (No keys found for decryption) --</source> + <comment>Placeholder, when the message was not decrypted yet or can't be decrypted.</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+82"/> + <source>-- Encrypted Event (Unknown event type) --</source> + <comment>Placeholder, when the message was decrypted, but we couldn't parse it, because Nheko/mtxclient don't support that event type yet.</comment> + <translation type="unfinished"></translation> + </message> + <message numerus="yes"> + <location line="+693"/> + <source>%1 and %2 are typing.</source> + <comment>Multiple users are typing. First argument is a comma separated list of potentially multiple users. Second argument is the last user of that list. (If only one user is typing, %1 is empty. You should still use it in your string though to silence Qt warnings.)</comment> + <translation type="unfinished"> + <numerusform></numerusform> + <numerusform></numerusform> + <numerusform></numerusform> + </translation> + </message> + <message> + <location line="+68"/> + <source>%1 opened the room to the public.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 made this room require and invitation to join.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> + <source>%1 made the room open to guests.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 has closed the room to guest access.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> + <source>%1 made the room history world readable. Events may be now read by non-joined people.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>%1 set the room history visible to members from this point on.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 set the room history visible to members since they were invited.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 set the room history visible to members since they joined the room.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+22"/> + <source>%1 has changed the room's permissions.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+48"/> + <source>%1 was invited.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> + <source>%1 changed their display name and avatar.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 changed their display name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 changed their avatar.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 changed some profile info.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>%1 joined.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>%1 rejected their invite.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Revoked the invite to %1.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 left the room.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Kicked %1.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Unbanned %1.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+14"/> + <source>%1 was banned.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-11"/> + <source>%1 redacted their knock.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-1281"/> + <source>You joined this room.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1283"/> + <source>Rejected the knock from %1.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 left after having already left!</source> + <comment>This is a leave event after the user already left and shouldn't happen apart from state resets</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+15"/> + <source> Reason: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-5"/> + <source>%1 knocked.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TimelineRow</name> + <message> + <location filename="../qml/TimelineRow.qml" line="+91"/> + <source>React</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> + <source>Reply</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+15"/> + <source>Options</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TimelineView</name> + <message> + <location filename="../qml/TimelineView.qml" line="+54"/> + <source>React</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Reply</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Read receipts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Mark as read</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>View raw message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>View decrypted raw message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Redact message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Save as</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+14"/> + <source>No room open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+271"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TopRoomBar</name> + <message> + <location filename="../../src/TopRoomBar.cpp" line="+86"/> + <source>Room options</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Mentions</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+34"/> + <source>Invite users</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Members</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Leave room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TrayIcon</name> + <message> + <location filename="../../src/TrayIcon.cpp" line="+122"/> + <source>Show</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Quit</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>UserInfoWidget</name> + <message> + <location filename="../../src/UserInfoWidget.cpp" line="+95"/> + <source>Logout</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+20"/> + <source>Set custom status message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Custom status message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Status:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>Set presence automatically</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Online</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Unavailable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Offline</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>UserSettingsPage</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+535"/> + <source>Minimize to tray</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Start in tray</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Group's sidebar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-3"/> + <source>Circular Avatars</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-5"/> + <source>Keep the application running in the background after closing the client window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Start the application in the background without showing the client window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Change the appearance of user avatars in chats. +OFF - square, ON - Circle.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Show a column containing groups and tags next to the room list.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Decrypt messages in sidebar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Decrypt the messages shown in the sidebar. +Only affects messages in encrypted chats.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show buttons in timeline</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show buttons to quickly reply, react or access additional options next to each message.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Limit width of timeline</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set the max width of messages in the timeline (in pixels). This can help readability on wide screen, when Nheko is maximised</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Typing notifications</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show who is typing in a room. +This will also enable or disable sending typing notifications to others.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Sort rooms by unreads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Display rooms with new messages first. +If this is off, the list of rooms will only be sorted by the timestamp of the last message in a room. +If this is on, rooms which have active notifications (the small circle with a number in it) will be sorted on top. Rooms, that you have muted, will still be sorted by timestamp, since you don't seem to consider them as important as the other rooms.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Read receipts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show if your message was read. +Status is displayed next to timestamps.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Send messages as Markdown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Allow using markdown in messages. +When disabled, all messages are sent as a plain text.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Desktop notifications</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Notify about received message when the client is not currently focused.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Alert on notification</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show an alert when a message is received. +This usually causes the application icon in the task bar to animate in some fashion.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Highlight message on hover</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Change the background color of messages when you hover over them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Large Emoji in timeline</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Make font size larger if messages with only a few emojis are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Scale factor</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Change the scale factor of the whole user interface.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Font size</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Font Family</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Theme</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Device ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Device Fingerprint</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-113"/> + <source>Session Keys</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>IMPORT</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>EXPORT</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-25"/> + <source>ENCRYPTION</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-71"/> + <source>GENERAL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+29"/> + <source>INTERFACE</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+166"/> + <source>Emoji Font Family</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+179"/> + <source>Open Sessions File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <location line="+18"/> + <location line="+9"/> + <location line="+2"/> + <location line="+2"/> + <location line="+19"/> + <location line="+11"/> + <location line="+18"/> + <location line="+2"/> + <location line="+2"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-74"/> + <location line="+32"/> + <source>File Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-31"/> + <source>Enter the passphrase to decrypt the file:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <location line="+32"/> + <source>The password cannot be empty</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-8"/> + <source>Enter passphrase to encrypt your session keys:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+15"/> + <source>File to save the exported session keys</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>WelcomePage</name> + <message> + <location filename="../../src/WelcomePage.cpp" line="+47"/> + <source>Welcome to nheko! The desktop client for the Matrix protocol.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Enjoy your stay!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> + <source>REGISTER</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>LOGIN</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>descriptiveTime</name> + <message> + <location filename="../../src/Utils.cpp" line="+147"/> + <source>Yesterday</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::CreateRoom</name> + <message> + <location filename="../../src/dialogs/CreateRoom.cpp" line="+36"/> + <source>Create room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Topic</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Alias</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Room Visibility</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Room Preset</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>Direct Chat</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::FallbackAuth</name> + <message> + <location filename="../../src/dialogs/FallbackAuth.cpp" line="+30"/> + <source>Open Fallback in Browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>Open the fallback, follow the steps and confirm after completing them.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::InviteUsers</name> + <message> + <location filename="../../src/dialogs/InviteUsers.cpp" line="+42"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>User ID to invite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::JoinRoom</name> + <message> + <location filename="../../src/dialogs/JoinRoom.cpp" line="+30"/> + <source>Join</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Room ID or alias</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::LeaveRoom</name> + <message> + <location filename="../../src/dialogs/LeaveRoom.cpp" line="+31"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Are you sure you want to leave?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::Logout</name> + <message> + <location filename="../../src/dialogs/Logout.cpp" line="+47"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Logout. Are you sure?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::PreviewUploadOverlay</name> + <message> + <location filename="../../src/dialogs/PreviewUploadOverlay.cpp" line="+41"/> + <source>Upload</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+84"/> + <source>Media type: %1 +Media size: %2 +</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::ReCaptcha</name> + <message> + <location filename="../../src/dialogs/ReCaptcha.cpp" line="+31"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> + <source>Solve the reCAPTCHA and press the confirm button</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::ReadReceipts</name> + <message> + <location filename="../../src/dialogs/ReadReceipts.cpp" line="+120"/> + <source>Read receipts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::ReceiptItem</name> + <message> + <location line="-46"/> + <source>Today %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Yesterday %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::RoomSettings</name> + <message> + <location filename="../../src/dialogs/RoomSettings.cpp" line="+135"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> + <source>Internal ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Room Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Notifications</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Muted</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Mentions only</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>All messages</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+97"/> + <source>Room access</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Anyone and guests</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Anyone</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Invited users</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+50"/> + <source>Encryption</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>End-to-End Encryption</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Encryption is currently experimental and things might break unexpectedly. <br>Please take note that it can't be disabled afterwards.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+27"/> + <source>Respond to key requests</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Whether or not the client should respond automatically with the session keys + upon request. Use with caution, this is a temporary measure to test the + E2E implementation until device verification is completed.</source> + <translation type="unfinished"></translation> + </message> + <message numerus="yes"> + <location line="+51"/> + <source>%n member(s)</source> + <translation type="unfinished"> + <numerusform></numerusform> + <numerusform></numerusform> + <numerusform></numerusform> + </translation> + </message> + <message> + <location line="+140"/> + <source>Failed to enable encryption: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+147"/> + <source>Select an avatar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+35"/> + <location line="+20"/> + <source>Failed to upload image: %s</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::UserProfile</name> + <message> + <location filename="../../src/dialogs/UserProfile.cpp" line="+63"/> + <source>Ban the user from the room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Ignore messages from this user</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>Kick the user from the room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Start a conversation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+61"/> + <source>Devices</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>emoji::Panel</name> + <message> + <location filename="../../src/emoji/Panel.cpp" line="+122"/> + <source>Smileys & People</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Animals & Nature</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Food & Drink</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Activity</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Travel & Places</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Objects</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Symbols</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>message-description sent:</name> + <message> + <location filename="../../src/Utils.h" line="+103"/> + <source>You sent an audio clip</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent an audio clip</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent an image</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent an image</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent a file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent a file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent a video</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent a video</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent a sticker</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent a sticker</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent a notification</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent a notification</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>You sent an encrypted message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent an encrypted message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You placed a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 placed a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You answered a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 answered a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You ended a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 ended a call</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>popups::UserMentions</name> + <message> + <location filename="../../src/popups/UserMentions.cpp" line="+64"/> + <source>This Room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>All Rooms</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>utils</name> + <message> + <location filename="../../src/Utils.h" line="+4"/> + <source>Unknown Message Type</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/resources/langs/nheko_et.ts b/resources/langs/nheko_et.ts new file mode 100644 index 0000000000000000000000000000000000000000..54ab523ab3f004e5f2be847981459ddf229e6ad1 --- /dev/null +++ b/resources/langs/nheko_et.ts @@ -0,0 +1,1858 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="et"> +<context> + <name>Cache</name> + <message> + <location filename="../../src/Cache.cpp" line="+1359"/> + <source>You joined this room.</source> + <translation>Sa liitusid selle jututoaga.</translation> + </message> +</context> +<context> + <name>ChatPage</name> + <message> + <location filename="../../src/ChatPage.cpp" line="+229"/> + <source>Failed to invite user: %1</source> + <translation>Kutse saatmine kasutajale ei õnnestunud: %1</translation> + </message> + <message> + <location line="+4"/> + <location line="+926"/> + <source>Invited user: %1</source> + <translation>Kutsutud kasutaja: %1</translation> + </message> + <message> + <location line="-474"/> + <source>Migrating the cache to the current version failed. This can have different reasons. Please open an issue and try to use an older version in the mean time. Alternatively you can try deleting the cache manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+439"/> + <source>Room %1 created.</source> + <translation>%1 jututuba on loodud.</translation> + </message> + <message> + <location line="+30"/> + <source>Failed to invite %1 to %2: %3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+19"/> + <source>Failed to kick %1 to %2: %3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Kicked user: %1</source> + <translation>Väljamüksatud kasutaja: %1</translation> + </message> + <message> + <location line="+14"/> + <source>Failed to ban %1 in %2: %3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Banned user: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+14"/> + <source>Failed to unban %1 in %2: %3</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Unbanned user: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-828"/> + <source>Failed to upload media. Please try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+296"/> + <source>Cache migration failed!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+13"/> + <source>Incompatible cache version</source> + <translation>Mitteühilduv puhvri versioon</translation> + </message> + <message> + <location line="+1"/> + <source>The cache on your disk is newer than this version of Nheko supports. Please update or clear your cache.</source> + <translation>Sinu andmekandjale salvestatud puhvri versioon on uuem, kui käesolev Nheko versioon kasutada oskab. Palun tee Nheko uuendus või kustuta puhverdatud andmed.</translation> + </message> + <message> + <location line="+111"/> + <source>Failed to restore OLM account. Please login again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Failed to restore save data. Please login again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+156"/> + <source>Failed to setup encryption keys. Server response: %1 %2. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+54"/> + <location line="+252"/> + <source>Please try to login again: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-187"/> + <source>Failed to join room: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You joined the room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Failed to remove invite: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+19"/> + <source>Room creation failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> + <source>Failed to leave room: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CommunitiesListItem</name> + <message> + <location filename="../../src/CommunitiesListItem.cpp" line="+133"/> + <source>All rooms</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Favourite rooms</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Low priority rooms</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Server Notices</source> + <comment>Tag translation for m.server_notice</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <location line="+2"/> + <source> (tag)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source> (community)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditModal</name> + <message> + <location filename="../../src/dialogs/RoomSettings.cpp" line="+72"/> + <source>Apply</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Topic</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EmojiPicker</name> + <message> + <location filename="../qml/emoji/EmojiPicker.qml" line="+117"/> + <location line="+139"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-42"/> + <source>People</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Nature</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Food</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Activity</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Travel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Objects</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Symbols</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EncryptionIndicator</name> + <message> + <location filename="../qml/EncryptionIndicator.qml" line="+36"/> + <source>Encrypted</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>This message is not encrypted!</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InviteeItem</name> + <message> + <location filename="../../src/InviteeItem.cpp" line="+18"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LoginPage</name> + <message> + <location filename="../../src/LoginPage.cpp" line="+90"/> + <source>Matrix ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>e.g @joe:matrix.org</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Your login name. A mxid should start with @ followed by the user id. After the user id you need to include your server name after a :. +You can also put your homeserver address there, if your server doesn't support .well-known lookup. +Example: @user:server.my +If Nheko fails to discover your homeserver, it will show you a field to enter the server manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+21"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Device name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>A name for this device, which will be shown to others, when verifying your devices. If none is provided a default is used.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>The address that can be used to contact you homeservers client API. +Example: https://server.my:8787</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> + <location line="+191"/> + <source>LOGIN</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-100"/> + <source>Autodiscovery failed. Received malformed response.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Autodiscovery failed. Unknown error when requesting .well-known.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+25"/> + <source>The required endpoints were not found. Possibly not a Matrix server.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Received malformed response. Make sure the homeserver domain is valid.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>An unknown error occured. Make sure the homeserver domain is valid.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+55"/> + <source>SSO LOGIN</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+25"/> + <source>Empty password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+52"/> + <source>SSO login failed</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MemberList</name> + <message> + <location filename="../../src/dialogs/MemberList.cpp" line="+90"/> + <source>Room members</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDelegate</name> + <message> + <location filename="../qml/delegates/MessageDelegate.qml" line="+66"/> + <source>redacted</source> + <translation>muudetud</translation> + </message> + <message> + <location line="+6"/> + <source>Encryption enabled</source> + <translation>Krüptimine on kasutusel</translation> + </message> + <message> + <location line="+6"/> + <source>room name changed to: %1</source> + <translation>jututoa uus nimi on: %1</translation> + </message> + <message> + <location line="+0"/> + <source>removed room name</source> + <translation>eemaldas jututoa nime</translation> + </message> + <message> + <location line="+6"/> + <source>topic changed to: %1</source> + <translation>jututoa uus teema on: %1</translation> + </message> + <message> + <location line="+0"/> + <source>removed topic</source> + <translation>teema on eemaldatud</translation> + </message> + <message> + <location line="+6"/> + <source>%1 created and configured room: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>%1 placed a %2 call.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>%1 answered the call.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>%1 ended the call.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Placeholder</name> + <message> + <location filename="../qml/delegates/Placeholder.qml" line="+4"/> + <source>unimplemented event: </source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuickSwitcher</name> + <message> + <location filename="../../src/QuickSwitcher.cpp" line="+74"/> + <source>Search for a room...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RegisterPage</name> + <message> + <location filename="../../src/RegisterPage.cpp" line="+88"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>The username must not be empty, and must contain only the characters a-z, 0-9, ., _, =, -, and /.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Please choose a secure password. The exact requirements for password strength may depend on your server.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Password confirmation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Homeserver</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>A server that allows registration. Since matrix is decentralized, you need to first find a server you can register on or host your own.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> + <source>REGISTER</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+55"/> + <source>No supported registration flows!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+135"/> + <source>Invalid username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Password is not long enough (min 8 chars)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Passwords don't match</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Invalid server name</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RoomInfo</name> + <message> + <location filename="../../src/Cache.cpp" line="+984"/> + <source>no version stored</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RoomInfoListItem</name> + <message> + <location filename="../../src/RoomInfoListItem.cpp" line="+102"/> + <source>Leave room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Tag room as:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+18"/> + <source>Favourite</source> + <comment>Standard matrix tag for favourites</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Low Priority</source> + <comment>Standard matrix tag for low priority rooms</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Server Notice</source> + <comment>Standard matrix tag for server notices</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>Adds or removes the specified tag.</source> + <comment>WhatsThis hint for tag menu actions</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+38"/> + <source>New tag...</source> + <comment>Add a new tag to the room</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>New Tag</source> + <comment>Tag name prompt title</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Tag:</source> + <comment>Tag name prompt</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+173"/> + <source>Accept</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Decline</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SideBarActions</name> + <message> + <location filename="../../src/SideBarActions.cpp" line="+40"/> + <source>User settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Create new room</source> + <translation>Loo uus jututuba</translation> + </message> + <message> + <location line="+1"/> + <source>Join a room</source> + <translation>Liitu jututoaga</translation> + </message> + <message> + <location line="+16"/> + <source>Start a new chat</source> + <translation>Alusta uut vestlust</translation> + </message> + <message> + <location line="+15"/> + <source>Room directory</source> + <translation>Jututubade loend</translation> + </message> +</context> +<context> + <name>StatusIndicator</name> + <message> + <location filename="../qml/StatusIndicator.qml" line="+14"/> + <source>Failed</source> + <translation>Ebaõnnestus</translation> + </message> + <message> + <location line="+1"/> + <source>Sent</source> + <translation>Saadetud</translation> + </message> + <message> + <location line="+1"/> + <source>Received</source> + <translation>Vastuvõetud</translation> + </message> + <message> + <location line="+1"/> + <source>Read</source> + <translation>Loetud</translation> + </message> +</context> +<context> + <name>TextInputWidget</name> + <message> + <location filename="../../src/TextInputWidget.cpp" line="+460"/> + <source>Send a file</source> + <translation>Saada fail</translation> + </message> + <message> + <location line="+13"/> + <location filename="../../src/TextInputWidget.h" line="+145"/> + <source>Write a message...</source> + <translation>Kirjuta sõnum…</translation> + </message> + <message> + <location line="+31"/> + <source>Send a message</source> + <translation>Saada sõnum</translation> + </message> + <message> + <location line="+8"/> + <source>Emoji</source> + <translation>Emoji</translation> + </message> + <message> + <location line="+86"/> + <source>Select a file</source> + <translation>Vali fail</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation>Kõik failid (*)</translation> + </message> + <message> + <location filename="../../src/TextInputWidget.h" line="-5"/> + <source>Connection lost. Nheko is trying to re-connect...</source> + <translation>Ühendus serveriga on katkenud. Nheko proovib uuesti ühendust luua…</translation> + </message> +</context> +<context> + <name>TimelineModel</name> + <message> + <location filename="../../src/timeline/TimelineModel.cpp" line="+891"/> + <source>-- Decryption Error (failed to communicate with DB) --</source> + <comment>Placeholder, when the message can't be decrypted, because the DB access failed when trying to lookup the session.</comment> + <translation>-- Dekrüptimise viga (ei õnnestu suhelda andmebaasiga) --</translation> + </message> + <message> + <location line="+20"/> + <source>-- Decryption Error (failed to retrieve megolm keys from db) --</source> + <comment>Placeholder, when the message can't be decrypted, because the DB access failed.</comment> + <translation>-- Dekrüptimise viga (megolm'i võtmete laadimine andmebaasist ei õnnestunud) --</translation> + </message> + <message> + <location line="+13"/> + <source>-- Decryption Error (%1) --</source> + <comment>Placeholder, when the message can't be decrypted. In this case, the Olm decrytion returned an error, which is passed ad %1.</comment> + <translation>-- Dekrüptimise viga (%1) --</translation> + </message> + <message> + <location line="+99"/> + <source>Message redaction failed: %1</source> + <translation>Sõnumi ümbersõnastamine ebaõnnestus: %1</translation> + </message> + <message> + <location line="+488"/> + <source>Save image</source> + <translation>Salvesta pilt</translation> + </message> + <message> + <location line="+2"/> + <source>Save video</source> + <translation>Salvesta video</translation> + </message> + <message> + <location line="+2"/> + <source>Save audio</source> + <translation>Salvesta helifail</translation> + </message> + <message> + <location line="+2"/> + <source>Save file</source> + <translation>Salvesta fail</translation> + </message> + <message> + <location line="-643"/> + <source>-- Encrypted Event (No keys found for decryption) --</source> + <comment>Placeholder, when the message was not decrypted yet or can't be decrypted.</comment> + <translation>-- Krüptitud sündmus (Dekrüptimisvõtmeid ei leidunud) --</translation> + </message> + <message> + <location line="+82"/> + <source>-- Encrypted Event (Unknown event type) --</source> + <comment>Placeholder, when the message was decrypted, but we couldn't parse it, because Nheko/mtxclient don't support that event type yet.</comment> + <translation>-- Krüptitud sündmus (Tundmatu sündmuse tüüp) --</translation> + </message> + <message numerus="yes"> + <location line="+693"/> + <source>%1 and %2 are typing.</source> + <comment>Multiple users are typing. First argument is a comma separated list of potentially multiple users. Second argument is the last user of that list. (If only one user is typing, %1 is empty. You should still use it in your string though to silence Qt warnings.)</comment> + <translation> + <numerusform>%1%2 kirjutab.</numerusform> + <numerusform>%1 and %2 kirjutavad.</numerusform> + </translation> + </message> + <message> + <location line="+68"/> + <source>%1 opened the room to the public.</source> + <translation>%1 tegi jututoa avalikuks.</translation> + </message> + <message> + <location line="+2"/> + <source>%1 made this room require and invitation to join.</source> + <translation>%1 seadistas, et selle jututoaga liitumine eeldab kutset.</translation> + </message> + <message> + <location line="+23"/> + <source>%1 made the room open to guests.</source> + <translation>%1 muutis selle jututoa külalistele ligipääsetavaks.</translation> + </message> + <message> + <location line="+2"/> + <source>%1 has closed the room to guest access.</source> + <translation>%1 eemaldas sellest jututoast külaliste ligipääsu.</translation> + </message> + <message> + <location line="+23"/> + <source>%1 made the room history world readable. Events may be now read by non-joined people.</source> + <translation>%1 muutis, et kogu maailm saab selle jututoa ajalugu lugeda. Kõiki sündmusi saavad lugeda ka need, kes ei ole liitunud jututoaga.</translation> + </message> + <message> + <location line="+4"/> + <source>%1 set the room history visible to members from this point on.</source> + <translation>%1 muutis, et selle jututoa ajalugu saavad lugeda kõik liikmed alates praegusest ajahetkest.</translation> + </message> + <message> + <location line="+3"/> + <source>%1 set the room history visible to members since they were invited.</source> + <translation>%1 muutis, et selle jututoa ajalugu saavad lugeda kõik liikmed alates oma kutse saatmisest.</translation> + </message> + <message> + <location line="+3"/> + <source>%1 set the room history visible to members since they joined the room.</source> + <translation>%1 muutis, et selle jututoa ajalugu saavad lugeda kõik liikmed alates jututoaga liitumise hetkest.</translation> + </message> + <message> + <location line="+22"/> + <source>%1 has changed the room's permissions.</source> + <translation>%1 muutis selle jututoa õigusi.</translation> + </message> + <message> + <location line="+48"/> + <source>%1 was invited.</source> + <translation>%1 sai kutse.</translation> + </message> + <message> + <location line="+11"/> + <source>%1 changed their display name and avatar.</source> + <translation>%1 muutis oma kuvatavat nime ja tunnuspilti.</translation> + </message> + <message> + <location line="+2"/> + <source>%1 changed their display name.</source> + <translation>%1 muutis oma kuvatavat nime.</translation> + </message> + <message> + <location line="+2"/> + <source>%1 changed their avatar.</source> + <translation>%1 muutis oma tunnuspilti.</translation> + </message> + <message> + <location line="+2"/> + <source>%1 changed some profile info.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>%1 joined.</source> + <translation>%1 liitus jututoaga.</translation> + </message> + <message> + <location line="+9"/> + <source>%1 rejected their invite.</source> + <translation>%1 lükkas liitumiskutse tagasi.</translation> + </message> + <message> + <location line="+2"/> + <source>Revoked the invite to %1.</source> + <translation>Tühistas %1 kutse.</translation> + </message> + <message> + <location line="+3"/> + <source>%1 left the room.</source> + <translation>%1 lahkus jututoast.</translation> + </message> + <message> + <location line="+2"/> + <source>Kicked %1.</source> + <translation>Müksas kasutaja %1 välja.</translation> + </message> + <message> + <location line="+2"/> + <source>Unbanned %1.</source> + <translation>Eemaldas kasutaja %1 suhtluskeelu.</translation> + </message> + <message> + <location line="+14"/> + <source>%1 was banned.</source> + <translation>Kasutaja %1 sai suhtluskeelu.</translation> + </message> + <message> + <location line="-11"/> + <source>%1 redacted their knock.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-1281"/> + <source>You joined this room.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1283"/> + <source>Rejected the knock from %1.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>%1 left after having already left!</source> + <comment>This is a leave event after the user already left and shouldn't happen apart from state resets</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+15"/> + <source> Reason: %1</source> + <translation>Põhjus: %1</translation> + </message> + <message> + <location line="-5"/> + <source>%1 knocked.</source> + <translation>%1 müksati välja.</translation> + </message> +</context> +<context> + <name>TimelineRow</name> + <message> + <location filename="../qml/TimelineRow.qml" line="+91"/> + <source>React</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> + <source>Reply</source> + <translation>Vasta</translation> + </message> + <message> + <location line="+15"/> + <source>Options</source> + <translation>Valikud</translation> + </message> +</context> +<context> + <name>TimelineView</name> + <message> + <location filename="../qml/TimelineView.qml" line="+54"/> + <source>React</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Reply</source> + <translation>Vasta</translation> + </message> + <message> + <location line="+4"/> + <source>Read receipts</source> + <translation>Lugemisteatised</translation> + </message> + <message> + <location line="+4"/> + <source>Mark as read</source> + <translation>Märgi loetuks</translation> + </message> + <message> + <location line="+3"/> + <source>View raw message</source> + <translation>Näita sõnumi lähtekoodi</translation> + </message> + <message> + <location line="+6"/> + <source>View decrypted raw message</source> + <translation>Näita sõnumi dekrüptitud lähtekoodi</translation> + </message> + <message> + <location line="+4"/> + <source>Redact message</source> + <translation>Muuda sõnumit</translation> + </message> + <message> + <location line="+6"/> + <source>Save as</source> + <translation>Salvesta kui</translation> + </message> + <message> + <location line="+14"/> + <source>No room open</source> + <translation>Ühtegi jututuba pole avatud</translation> + </message> + <message> + <location line="+271"/> + <source>Close</source> + <translation>Sulge</translation> + </message> +</context> +<context> + <name>TopRoomBar</name> + <message> + <location filename="../../src/TopRoomBar.cpp" line="+86"/> + <source>Room options</source> + <translation>Jututoa valikud</translation> + </message> + <message> + <location line="+5"/> + <source>Mentions</source> + <translation>Mainimised</translation> + </message> + <message> + <location line="+34"/> + <source>Invite users</source> + <translation>Kutsu kasutajaid</translation> + </message> + <message> + <location line="+6"/> + <source>Members</source> + <translation>Liikmed</translation> + </message> + <message> + <location line="+5"/> + <source>Leave room</source> + <translation>Lahku jututoast</translation> + </message> + <message> + <location line="+5"/> + <source>Settings</source> + <translation>Seadistused</translation> + </message> +</context> +<context> + <name>TrayIcon</name> + <message> + <location filename="../../src/TrayIcon.cpp" line="+122"/> + <source>Show</source> + <translation>Näita</translation> + </message> + <message> + <location line="+1"/> + <source>Quit</source> + <translation>Lõpeta töö</translation> + </message> +</context> +<context> + <name>UserInfoWidget</name> + <message> + <location filename="../../src/UserInfoWidget.cpp" line="+95"/> + <source>Logout</source> + <translation>Logi välja</translation> + </message> + <message> + <location line="+20"/> + <source>Set custom status message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Custom status message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Status:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>Set presence automatically</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Online</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Unavailable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Offline</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>UserSettingsPage</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+535"/> + <source>Minimize to tray</source> + <translation>Vähenda tegumiribale</translation> + </message> + <message> + <location line="+3"/> + <source>Start in tray</source> + <translation>Käivita tegumiribalt</translation> + </message> + <message> + <location line="+7"/> + <source>Group's sidebar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-3"/> + <source>Circular Avatars</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-5"/> + <source>Keep the application running in the background after closing the client window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Start the application in the background without showing the client window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Change the appearance of user avatars in chats. +OFF - square, ON - Circle.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Show a column containing groups and tags next to the room list.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Decrypt messages in sidebar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Decrypt the messages shown in the sidebar. +Only affects messages in encrypted chats.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show buttons in timeline</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show buttons to quickly reply, react or access additional options next to each message.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Limit width of timeline</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set the max width of messages in the timeline (in pixels). This can help readability on wide screen, when Nheko is maximised</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Typing notifications</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show who is typing in a room. +This will also enable or disable sending typing notifications to others.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Sort rooms by unreads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Display rooms with new messages first. +If this is off, the list of rooms will only be sorted by the timestamp of the last message in a room. +If this is on, rooms which have active notifications (the small circle with a number in it) will be sorted on top. Rooms, that you have muted, will still be sorted by timestamp, since you don't seem to consider them as important as the other rooms.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Read receipts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show if your message was read. +Status is displayed next to timestamps.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Send messages as Markdown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Allow using markdown in messages. +When disabled, all messages are sent as a plain text.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Desktop notifications</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Notify about received message when the client is not currently focused.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Alert on notification</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Show an alert when a message is received. +This usually causes the application icon in the task bar to animate in some fashion.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Highlight message on hover</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Change the background color of messages when you hover over them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Large Emoji in timeline</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Make font size larger if messages with only a few emojis are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Scale factor</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Change the scale factor of the whole user interface.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Font size</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Font Family</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Theme</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Device ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Device Fingerprint</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-113"/> + <source>Session Keys</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>IMPORT</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>EXPORT</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-25"/> + <source>ENCRYPTION</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-71"/> + <source>GENERAL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+29"/> + <source>INTERFACE</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+166"/> + <source>Emoji Font Family</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+179"/> + <source>Open Sessions File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <location line="+18"/> + <location line="+9"/> + <location line="+2"/> + <location line="+2"/> + <location line="+19"/> + <location line="+11"/> + <location line="+18"/> + <location line="+2"/> + <location line="+2"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-74"/> + <location line="+32"/> + <source>File Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-31"/> + <source>Enter the passphrase to decrypt the file:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <location line="+32"/> + <source>The password cannot be empty</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-8"/> + <source>Enter passphrase to encrypt your session keys:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+15"/> + <source>File to save the exported session keys</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>WelcomePage</name> + <message> + <location filename="../../src/WelcomePage.cpp" line="+47"/> + <source>Welcome to nheko! The desktop client for the Matrix protocol.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Enjoy your stay!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> + <source>REGISTER</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>LOGIN</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>descriptiveTime</name> + <message> + <location filename="../../src/Utils.cpp" line="+147"/> + <source>Yesterday</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::CreateRoom</name> + <message> + <location filename="../../src/dialogs/CreateRoom.cpp" line="+36"/> + <source>Create room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Topic</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Alias</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Room Visibility</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Room Preset</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>Direct Chat</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::FallbackAuth</name> + <message> + <location filename="../../src/dialogs/FallbackAuth.cpp" line="+30"/> + <source>Open Fallback in Browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>Open the fallback, follow the steps and confirm after completing them.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::InviteUsers</name> + <message> + <location filename="../../src/dialogs/InviteUsers.cpp" line="+42"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>User ID to invite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::JoinRoom</name> + <message> + <location filename="../../src/dialogs/JoinRoom.cpp" line="+30"/> + <source>Join</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Room ID or alias</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::LeaveRoom</name> + <message> + <location filename="../../src/dialogs/LeaveRoom.cpp" line="+31"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Are you sure you want to leave?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::Logout</name> + <message> + <location filename="../../src/dialogs/Logout.cpp" line="+47"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Logout. Are you sure?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::PreviewUploadOverlay</name> + <message> + <location filename="../../src/dialogs/PreviewUploadOverlay.cpp" line="+41"/> + <source>Upload</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+84"/> + <source>Media type: %1 +Media size: %2 +</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::ReCaptcha</name> + <message> + <location filename="../../src/dialogs/ReCaptcha.cpp" line="+31"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> + <source>Solve the reCAPTCHA and press the confirm button</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::ReadReceipts</name> + <message> + <location filename="../../src/dialogs/ReadReceipts.cpp" line="+120"/> + <source>Read receipts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::ReceiptItem</name> + <message> + <location line="-46"/> + <source>Today %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Yesterday %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::RoomSettings</name> + <message> + <location filename="../../src/dialogs/RoomSettings.cpp" line="+135"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> + <source>Internal ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Room Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Notifications</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Muted</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Mentions only</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>All messages</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+97"/> + <source>Room access</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Anyone and guests</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Anyone</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Invited users</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+50"/> + <source>Encryption</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>End-to-End Encryption</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Encryption is currently experimental and things might break unexpectedly. <br>Please take note that it can't be disabled afterwards.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+27"/> + <source>Respond to key requests</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Whether or not the client should respond automatically with the session keys + upon request. Use with caution, this is a temporary measure to test the + E2E implementation until device verification is completed.</source> + <translation type="unfinished"></translation> + </message> + <message numerus="yes"> + <location line="+51"/> + <source>%n member(s)</source> + <translation type="unfinished"> + <numerusform></numerusform> + <numerusform></numerusform> + </translation> + </message> + <message> + <location line="+140"/> + <source>Failed to enable encryption: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+147"/> + <source>Select an avatar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+35"/> + <location line="+20"/> + <source>Failed to upload image: %s</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>dialogs::UserProfile</name> + <message> + <location filename="../../src/dialogs/UserProfile.cpp" line="+63"/> + <source>Ban the user from the room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Ignore messages from this user</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>Kick the user from the room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Start a conversation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+61"/> + <source>Devices</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>emoji::Panel</name> + <message> + <location filename="../../src/emoji/Panel.cpp" line="+122"/> + <source>Smileys & People</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Animals & Nature</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Food & Drink</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Activity</source> + <translation>Tegevused</translation> + </message> + <message> + <location line="+4"/> + <source>Travel & Places</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Objects</source> + <translation>Esemed</translation> + </message> + <message> + <location line="+3"/> + <source>Symbols</source> + <translation>Sümbolid</translation> + </message> + <message> + <location line="+3"/> + <source>Flags</source> + <translation>Lipud</translation> + </message> +</context> +<context> + <name>message-description sent:</name> + <message> + <location filename="../../src/Utils.h" line="+103"/> + <source>You sent an audio clip</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent an audio clip</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent an image</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent an image</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent a file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent a file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent a video</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent a video</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent a sticker</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent a sticker</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You sent a notification</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent a notification</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>You sent an encrypted message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 sent an encrypted message</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You placed a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 placed a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You answered a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 answered a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>You ended a call</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>%1 ended a call</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>popups::UserMentions</name> + <message> + <location filename="../../src/popups/UserMentions.cpp" line="+64"/> + <source>This Room</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>All Rooms</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>utils</name> + <message> + <location filename="../../src/Utils.h" line="+4"/> + <source>Unknown Message Type</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/resources/langs/nheko_si.ts b/resources/langs/nheko_si.ts index 2f405ca2dae2dfba8fd2c1c7a886c4f641f46e95..f2b58d331401236e69c27efb5c132a02dd15c154 100644 --- a/resources/langs/nheko_si.ts +++ b/resources/langs/nheko_si.ts @@ -237,11 +237,6 @@ If Nheko fails to discover your homeserver, it will show you a field to enter th <source>Device name</source> <translation type="unfinished"></translation> </message> - <message> - <location line="+2"/> - <source>A name for this device, which will be shown to others, when verifying your devices. If none is provided, a random string is used for privacy purposes.</source> - <translation type="unfinished"></translation> - </message> <message> <location line="+6"/> <source>The address that can be used to contact you homeservers client API. @@ -486,11 +481,6 @@ Example: https://server.my:8787</source> <comment>Tag name prompt title</comment> <translation type="unfinished"></translation> </message> - <message> - <location line="+0"/> - <source>Tag:</source> - <translation type="unfinished"></translation> - </message> <message> <location line="+173"/> <source>Accept</source> diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml index f934e2f6bd3f5fa78f7fde578258dcbd0412580f..a3943806074b466a79cbf167071718b80387db6b 100644 --- a/resources/qml/Avatar.qml +++ b/resources/qml/Avatar.qml @@ -14,7 +14,7 @@ Rectangle { Label { anchors.fill: parent - text: chat.model.escapeEmoji(String.fromCodePoint(displayName.codePointAt(0))) + text: timelineManager.escapeEmoji(String.fromCodePoint(displayName.codePointAt(0))) textFormat: Text.RichText font.pixelSize: avatar.height/2 verticalAlignment: Text.AlignVCenter @@ -50,6 +50,8 @@ Rectangle { anchors.bottom: avatar.bottom anchors.right: avatar.right + visible: !!userid + height: avatar.height / 6 width: height radius: settings.avatarCircles ? height / 2 : height / 4 diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 1c16ddc6b7ca9c1480aea987af8ade7261209739..71a287bbc400303303e01d5e6a849f14e878a1a3 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -115,6 +115,130 @@ Page { z: 3 } + ColumnLayout { + anchors.fill: parent + Rectangle { + id: topBar + + Layout.fillWidth: true + implicitHeight: topLayout.height + 16 + z: 3 + + color: colors.base + + MouseArea { + anchors.fill: parent + onClicked: timelineManager.openRoomSettings(); + } + + GridLayout { + id: topLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 8 + anchors.verticalCenter: parent.verticalCenter + + //Layout.margins: 8 + + ImageButton { + id: backToRoomsButton + + Layout.column: 0 + Layout.row: 0 + Layout.rowSpan: 2 + Layout.alignment: Qt.AlignVCenter + + visible: timelineManager.isNarrowView + + image: ":/icons/icons/ui/angle-pointing-to-left.png" + + ToolTip.visible: hovered + ToolTip.text: qsTr("Back to room list") + + onClicked: timelineManager.backToRooms() + } + + Avatar { + Layout.column: 1 + Layout.row: 0 + Layout.rowSpan: 2 + Layout.alignment: Qt.AlignVCenter + + width: avatarSize + height: avatarSize + + url: chat.model ? chat.model.roomAvatarUrl.replace("mxc://", "image://MxcImage/") : "" + displayName: chat.model ? chat.model.roomName : qsTr("No room selected") + + MouseArea { + anchors.fill: parent + onClicked: timelineManager.openRoomSettings(); + } + } + + Label { + Layout.fillWidth: true + Layout.column: 2 + Layout.row: 0 + + font.pointSize: fontMetrics.font.pointSize * 1.1 + + text: chat.model ? chat.model.roomName : qsTr("No room selected") + + MouseArea { + anchors.fill: parent + onClicked: timelineManager.openRoomSettings(); + } + } + MatrixText { + Layout.fillWidth: true + Layout.column: 2 + Layout.row: 1 + Layout.maximumHeight: fontMetrics.lineSpacing * 2 // show 2 lines + clip: true + + text: chat.model ? chat.model.roomTopic : "" + } + + ImageButton { + id: roomOptionsButton + + Layout.column: 3 + Layout.row: 0 + Layout.rowSpan: 2 + Layout.alignment: Qt.AlignVCenter + + image: ":/icons/icons/ui/vertical-ellipsis.png" + + ToolTip.visible: hovered + ToolTip.text: qsTr("Room options") + + onClicked: roomOptionsMenu.popup(roomOptionsButton) + + Menu { + id: roomOptionsMenu + MenuItem { + text: qsTr("Invite users") + onTriggered: timelineManager.openInviteUsersDialog(); + } + MenuItem { + text: qsTr("Members") + onTriggered: timelineManager.openMemberListDialog(); + } + MenuItem { + text: qsTr("Leave room") + onTriggered: timelineManager.openLeaveRoomDialog(); + } + MenuItem { + text: qsTr("Settings") + onTriggered: timelineManager.openRoomSettings(); + } + } + } + } + } + ListView { id: chat @@ -122,13 +246,8 @@ Page { cacheBuffer: 400 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.bottom: chatFooter.top - width: parent.width - - anchors.leftMargin: 4 - anchors.rightMargin: scrollbar.width + Layout.fillWidth: true + Layout.fillHeight: true model: timelineManager.timeline @@ -167,10 +286,6 @@ Page { ScrollBar.vertical: ScrollBar { id: scrollbar - parent: chat.parent - anchors.top: chat.top - anchors.right: chat.right - anchors.bottom: chat.bottom } spacing: 4 @@ -178,9 +293,9 @@ Page { onCountChanged: if (atYEnd) model.currentIndex = 0 // Mark last event as read, since we are at the bottom - property int delegateMaxWidth: (settings.timelineMaxWidth > 100 && (parent.width - settings.timelineMaxWidth) > 32) ? settings.timelineMaxWidth : (parent.width - 32) + property int delegateMaxWidth: (settings.timelineMaxWidth > 100 && (parent.width - settings.timelineMaxWidth) > scrollbar.width*2) ? settings.timelineMaxWidth : (parent.width - scrollbar.width*2) - delegate: Rectangle { + delegate: Item { // This would normally be previousSection, but our model's order is inverted. property bool sectionBoundary: (ListView.nextSection != "" && ListView.nextSection !== ListView.section) || model.index === chat.count - 1 @@ -189,7 +304,6 @@ Page { anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined width: chat.delegateMaxWidth height: section ? section.height + timelinerow.height : timelinerow.height - color: "transparent" TimelineRow { id: timelinerow @@ -276,7 +390,7 @@ Page { Label { id: userName - text: chat.model.escapeEmoji(modelData.userName) + text: timelineManager.escapeEmoji(modelData.userName) color: timelineManager.userColor(modelData.userId, colors.window) textFormat: Text.RichText @@ -309,17 +423,13 @@ Page { } } - Rectangle { + Item { id: chatFooter - height: Math.max(fontMetrics.height * 1.2, footerContent.height) - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom + implicitHeight: Math.max(fontMetrics.height * 1.2, footerContent.height) + Layout.fillWidth: true z: 3 - color: "transparent" - Column { id: footerContent anchors.left: parent.left @@ -397,4 +507,5 @@ Page { } } } + } } diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml index 56b8040ee481ab00af05d6eb32d2ca6286fa1fc5..90e524422b0cbbdea30c4ecd2d34656de0d5f8a0 100644 --- a/resources/qml/delegates/MessageDelegate.qml +++ b/resources/qml/delegates/MessageDelegate.qml @@ -36,7 +36,7 @@ Item { DelegateChoice { roleValue: MtxEvent.EmoteMessage NoticeMessage { - formatted: chat.model.escapeEmoji(modelData.userName) + " " + model.data.formattedBody + formatted: timelineManager.escapeEmoji(modelData.userName) + " " + model.data.formattedBody color: timelineManager.userColor(modelData.userId, colors.window) } } diff --git a/resources/qml/delegates/Reply.qml b/resources/qml/delegates/Reply.qml index f9fd3f111b34d26e421aa0f37cd21e1ddfdbac62..36a6d373c991ac3e912c88132ac7bec7f2cf6dbc 100644 --- a/resources/qml/delegates/Reply.qml +++ b/resources/qml/delegates/Reply.qml @@ -37,7 +37,7 @@ Item { Text { id: userName - text: chat.model ? chat.model.escapeEmoji(reply.modelData.userName) : "" + text: timelineManager.escapeEmoji(reply.modelData.userName) color: replyComponent.userColor textFormat: Text.RichText diff --git a/src/AvatarProvider.cpp b/src/AvatarProvider.cpp index 603bb71abafaae6bf979eca3672b2abb541153ed..b1751c33d1a05a636283a988bbc1b85aad9ef512 100644 --- a/src/AvatarProvider.cpp +++ b/src/AvatarProvider.cpp @@ -34,10 +34,12 @@ resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback ca { const auto cacheKey = QString("%1_size_%2").arg(avatarUrl).arg(size); - if (avatarUrl.isEmpty()) + QPixmap pixmap; + if (avatarUrl.isEmpty()) { + callback(pixmap); return; + } - QPixmap pixmap; if (avatar_cache.find(cacheKey, &pixmap)) { callback(pixmap); return; @@ -75,11 +77,10 @@ resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback ca opts.mxc_url, mtx::errors::to_string(err->matrix_error.errcode), err->matrix_error.error); - return; + } else { + cache::saveImage(cacheKey.toStdString(), res); } - cache::saveImage(cacheKey.toStdString(), res); - emit proxy->avatarDownloaded(QByteArray(res.data(), res.size())); }); } diff --git a/src/Cache.cpp b/src/Cache.cpp index 91cde9e7ea37a2f735142234eac48c42f1bcd469..98fe64c007a8d1a04e72f4a2378d0712935f4d6e 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -94,8 +94,10 @@ namespace { std::unique_ptr<Cache> instance_ = nullptr; } -static bool -isHiddenEvent(mtx::events::collections::TimelineEvents e, const std::string &room_id) +bool +Cache::isHiddenEvent(lmdb::txn &txn, + mtx::events::collections::TimelineEvents e, + const std::string &room_id) { using namespace mtx::events; if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) { @@ -109,13 +111,27 @@ isHiddenEvent(mtx::events::collections::TimelineEvents e, const std::string &roo e = result.event.value(); } - static constexpr std::initializer_list<EventType> hiddenEvents = { + mtx::events::account_data::nheko_extensions::HiddenEvents hiddenEvents; + hiddenEvents.hidden_event_types = { EventType::Reaction, EventType::CallCandidates, EventType::Unsupported}; + if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, "")) + hiddenEvents = std::move( + std::get< + mtx::events::Event<mtx::events::account_data::nheko_extensions::HiddenEvents>>( + *temp) + .content); + if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, room_id)) + hiddenEvents = std::move( + std::get< + mtx::events::Event<mtx::events::account_data::nheko_extensions::HiddenEvents>>( + *temp) + .content); + return std::visit( - [](const auto &ev) { - return std::any_of(hiddenEvents.begin(), - hiddenEvents.end(), + [hiddenEvents](const auto &ev) { + return std::any_of(hiddenEvents.hidden_event_types.begin(), + hiddenEvents.hidden_event_types.end(), [ev](EventType type) { return type == ev.type; }); }, e); @@ -624,6 +640,7 @@ Cache::removeRoom(lmdb::txn &txn, const std::string &roomid) { lmdb::dbi_del(txn, roomsDb_, lmdb::val(roomid), nullptr); lmdb::dbi_drop(txn, getStatesDb(txn, roomid), true); + lmdb::dbi_drop(txn, getAccountDataDb(txn, roomid), true); lmdb::dbi_drop(txn, getMembersDb(txn, roomid), true); } @@ -982,6 +999,19 @@ Cache::saveState(const mtx::responses::Sync &res) setNextBatchToken(txn, res.next_batch); + if (!res.account_data.events.empty()) { + auto accountDataDb = getAccountDataDb(txn, ""); + for (const auto &ev : res.account_data.events) + std::visit( + [&txn, &accountDataDb](const auto &event) { + lmdb::dbi_put(txn, + accountDataDb, + lmdb::val(to_string(event.type)), + lmdb::val(json(event).dump())); + }, + ev); + } + // Save joined rooms for (const auto &room : res.rooms.join) { auto statesdb = getStatesDb(txn, room.first); @@ -1001,30 +1031,43 @@ Cache::saveState(const mtx::responses::Sync &res) updatedInfo.version = getRoomVersion(txn, statesdb).toStdString(); // Process the account_data associated with this room - bool has_new_tags = false; - for (const auto &evt : room.second.account_data.events) { - // for now only fetch tag events - if (std::holds_alternative<Event<account_data::Tags>>(evt)) { - auto tags_evt = std::get<Event<account_data::Tags>>(evt); - has_new_tags = true; - for (const auto &tag : tags_evt.content.tags) { - updatedInfo.tags.push_back(tag.first); + if (!room.second.account_data.events.empty()) { + auto accountDataDb = getAccountDataDb(txn, room.first); + + bool has_new_tags = false; + for (const auto &evt : room.second.account_data.events) { + std::visit( + [&txn, &accountDataDb](const auto &event) { + lmdb::dbi_put(txn, + accountDataDb, + lmdb::val(to_string(event.type)), + lmdb::val(json(event).dump())); + }, + evt); + + // for tag events + if (std::holds_alternative<Event<account_data::Tags>>(evt)) { + auto tags_evt = std::get<Event<account_data::Tags>>(evt); + has_new_tags = true; + for (const auto &tag : tags_evt.content.tags) { + updatedInfo.tags.push_back(tag.first); + } } } - } - if (!has_new_tags) { - // retrieve the old tags, they haven't changed - lmdb::val data; - if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room.first), data)) { - try { - RoomInfo tmp = - json::parse(std::string_view(data.data(), data.size())); - updatedInfo.tags = tmp.tags; - } catch (const json::exception &e) { - nhlog::db()->warn( - "failed to parse room info: room_id ({}), {}", - room.first, - std::string(data.data(), data.size())); + if (!has_new_tags) { + // retrieve the old tags, they haven't changed + lmdb::val data; + if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room.first), data)) { + try { + RoomInfo tmp = json::parse( + std::string_view(data.data(), data.size())); + updatedInfo.tags = tmp.tags; + } catch (const json::exception &e) { + nhlog::db()->warn( + "failed to parse room info: room_id ({}), {}", + room.first, + std::string(data.data(), data.size())); + } } } } @@ -2439,7 +2482,7 @@ Cache::saveTimelineMessages(lmdb::txn &txn, lmdb::dbi_put(txn, evToOrderDb, event_id, lmdb::val(&index, sizeof(index))); // TODO(Nico): Allow blacklisting more event types in UI - if (!isHiddenEvent(e, room_id)) { + if (!isHiddenEvent(txn, e, room_id)) { ++msgIndex; lmdb::cursor_put(msgCursor.handle(), lmdb::val(&msgIndex, sizeof(msgIndex)), @@ -2522,7 +2565,7 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message lmdb::dbi_put(txn, evToOrderDb, event_id, lmdb::val(&index, sizeof(index))); // TODO(Nico): Allow blacklisting more event types in UI - if (!isHiddenEvent(e, room_id)) { + if (!isHiddenEvent(txn, e, room_id)) { --msgIndex; lmdb::dbi_put( txn, order2msgDb, lmdb::val(&msgIndex, sizeof(msgIndex)), event_id); @@ -2840,6 +2883,24 @@ Cache::deleteOldData() noexcept } } +std::optional<mtx::events::collections::RoomAccountDataEvents> +Cache::getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::string &room_id) +{ + try { + auto db = getAccountDataDb(txn, room_id); + + lmdb::val data; + if (lmdb::dbi_get(txn, db, lmdb::val(to_string(type)), data)) { + mtx::responses::utils::RoomAccountDataEvents events; + mtx::responses::utils::parse_room_account_data_events( + std::string_view(data.data(), data.size()), events); + return events.front(); + } + } catch (...) { + } + return std::nullopt; +} + bool Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes, const std::string &room_id, diff --git a/src/Cache_p.h b/src/Cache_p.h index d3ec6ee036e359eefce35ca2389014edf897802a..c57995a23a63d7fa7d5cce682e07e1b499646e36 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -289,6 +289,14 @@ private: const std::string &room_id, const mtx::responses::Timeline &res); + //! retrieve a specific event from account data + //! pass empty room_id for global account data + std::optional<mtx::events::collections::RoomAccountDataEvents> + getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::string &room_id); + bool isHiddenEvent(lmdb::txn &txn, + mtx::events::collections::TimelineEvents e, + const std::string &room_id); + //! Remove a room from the cache. // void removeLeftRoom(lmdb::txn &txn, const std::string &room_id); template<class T> @@ -498,6 +506,12 @@ private: return lmdb::dbi::open(txn, std::string(room_id + "/state").c_str(), MDB_CREATE); } + lmdb::dbi getAccountDataDb(lmdb::txn &txn, const std::string &room_id) + { + return lmdb::dbi::open( + txn, std::string(room_id + "/account_data").c_str(), MDB_CREATE); + } + lmdb::dbi getMembersDb(lmdb::txn &txn, const std::string &room_id) { return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), MDB_CREATE); diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index e55b3ecabffbeb201cf22f540dc03050486dc04c..6008846a72c0f0a778823e97418eba24c40b4a31 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -37,7 +37,6 @@ #include "SideBarActions.h" #include "Splitter.h" #include "TextInputWidget.h" -#include "TopRoomBar.h" #include "UserInfoWidget.h" #include "UserSettingsPage.h" #include "Utils.h" @@ -126,10 +125,8 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) contentLayout_->setSpacing(0); contentLayout_->setMargin(0); - top_bar_ = new TopRoomBar(this); view_manager_ = new TimelineViewManager(userSettings_, &callManager_, this); - contentLayout_->addWidget(top_bar_); contentLayout_->addWidget(view_manager_->getWidget()); activeCallBar_ = new ActiveCallBar(this); @@ -181,30 +178,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) room_list_->previousRoom(); }); - connect(top_bar_, &TopRoomBar::mentionsClicked, this, [this](const QPoint &mentionsPos) { - if (user_mentions_popup_->isVisible()) { - user_mentions_popup_->hide(); - } else { - showNotificationsDialog(mentionsPos); - http::client()->notifications( - 1000, - "", - "highlight", - [this, mentionsPos](const mtx::responses::Notifications &res, - mtx::http::RequestErr err) { - if (err) { - nhlog::net()->warn( - "failed to retrieve notifications: {} ({})", - err->matrix_error.error, - static_cast<int>(err->status_code)); - return; - } - - emit highlightedNotifsRetrieved(std::move(res), mentionsPos); - }); - } - }); - connectivityTimer_.setInterval(CHECK_CONNECTIVITY_INTERVAL); connect(&connectivityTimer_, &QTimer::timeout, this, [=]() { if (http::client()->access_token().empty()) { @@ -226,8 +199,9 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) connect(this, &ChatPage::loggedOut, this, &ChatPage::logout); - connect(top_bar_, &TopRoomBar::showRoomList, splitter, &Splitter::showFullRoomList); - connect(top_bar_, &TopRoomBar::inviteUsers, this, [this](QStringList users) { + connect( + view_manager_, &TimelineViewManager::showRoomList, splitter, &Splitter::showFullRoomList); + connect(view_manager_, &TimelineViewManager::inviteUsers, this, [this](QStringList users) { const auto room_id = current_room_.toStdString(); for (int ii = 0; ii < users.size(); ++ii) { @@ -251,8 +225,10 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) } }); + connect(room_list_, &RoomList::roomChanged, this, [this](QString room_id) { + this->current_room_ = room_id; + }); connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::stopTyping); - connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo); connect(room_list_, &RoomList::roomChanged, splitter, &Splitter::showChatView); connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::focusLineEdit); connect( @@ -487,8 +463,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) } }); - connect(room_list_, &RoomList::roomAvatarChanged, this, &ChatPage::updateTopBarAvatar); - connect( this, &ChatPage::updateGroupsInfo, communitiesList_, &CommunitiesList::setCommunities); @@ -588,11 +562,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) }); connect(this, &ChatPage::syncRoomlist, room_list_, &RoomList::sync); connect(this, &ChatPage::syncTags, communitiesList_, &CommunitiesList::syncTags); - connect( - this, &ChatPage::syncTopBar, this, [this](const std::map<QString, RoomInfo> &updates) { - if (updates.find(currentRoom()) != updates.end()) - changeTopRoomInfo(currentRoom()); - }); // Callbacks to update the user info (top left corner of the page). connect(this, &ChatPage::setUserAvatar, user_info_widget_, &UserInfoWidget::setAvatar); @@ -657,7 +626,6 @@ void ChatPage::resetUI() { room_list_->clear(); - top_bar_->reset(); user_info_widget_->reset(); view_manager_->clearAll(); @@ -786,46 +754,6 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token) tryInitialSync(); } -void -ChatPage::updateTopBarAvatar(const QString &roomid, const QString &img) -{ - if (current_room_ != roomid) - return; - - top_bar_->updateRoomAvatar(img); -} - -void -ChatPage::changeTopRoomInfo(const QString &room_id) -{ - if (room_id.isEmpty()) { - nhlog::ui()->warn("cannot switch to empty room_id"); - return; - } - - try { - auto room_info = cache::getRoomInfo({room_id.toStdString()}); - - if (room_info.find(room_id) == room_info.end()) - return; - - const auto name = QString::fromStdString(room_info[room_id].name); - const auto avatar_url = QString::fromStdString(room_info[room_id].avatar_url); - - top_bar_->updateRoomName(name); - top_bar_->updateRoomTopic(QString::fromStdString(room_info[room_id].topic)); - - top_bar_->updateRoomAvatarFromName(name); - if (!avatar_url.isEmpty()) - top_bar_->updateRoomAvatar(avatar_url); - - } catch (const lmdb::error &e) { - nhlog::ui()->error("failed to change top bar room info: {}", e.what()); - } - - current_room_ = room_id; -} - void ChatPage::showUnreadMessageNotification(int count) { @@ -967,14 +895,22 @@ ChatPage::sendNotifications(const mtx::responses::Notifications &res) } if (userSettings_->hasDesktopNotifications()) { - notificationsManager.postNotification( - room_id, - QString::fromStdString(event_id), - QString::fromStdString( - cache::singleRoomInfo(item.room_id).name), - cache::displayName(room_id, user_id), - utils::event_body(item.event), - cache::getRoomAvatar(room_id)); + auto info = cache::singleRoomInfo(item.room_id); + + AvatarProvider::resolve( + QString::fromStdString(info.avatar_url), + 96, + this, + [this, room_id, event_id, item, user_id, info]( + QPixmap image) { + notificationsManager.postNotification( + room_id, + QString::fromStdString(event_id), + QString::fromStdString(info.name), + cache::displayName(room_id, user_id), + utils::event_body(item.event), + image.toImage()); + }); } } } catch (const lmdb::error &e) { @@ -1070,7 +1006,6 @@ ChatPage::handleSyncResponse(mtx::responses::Sync res) auto updates = cache::roomUpdates(res); - emit syncTopBar(updates); emit syncRoomlist(updates); emit syncUI(res.rooms); @@ -1481,9 +1416,12 @@ ChatPage::getProfileInfo() void ChatPage::hideSideBars() { - communitiesList_->hide(); - sideBar_->hide(); - top_bar_->enableBackButton(); + // Don't hide side bar, if we are currently only showing the side bar! + if (view_manager_->getWidget()->isVisible()) { + communitiesList_->hide(); + sideBar_->hide(); + } + view_manager_->enableBackButton(); } void @@ -1493,23 +1431,19 @@ ChatPage::showSideBars() communitiesList_->show(); sideBar_->show(); - top_bar_->disableBackButton(); + view_manager_->disableBackButton(); + content_->show(); } uint64_t ChatPage::timelineWidth() { - int sidebarWidth = sideBar_->size().width(); - sidebarWidth += communitiesList_->size().width(); + int sidebarWidth = sideBar_->minimumSize().width(); + sidebarWidth += communitiesList_->minimumSize().width(); + nhlog::ui()->info("timelineWidth: {}", size().width() - sidebarWidth); return size().width() - sidebarWidth; } -bool -ChatPage::isSideBarExpanded() -{ - const auto sz = splitter::calculateSidebarSizes(QFont{}); - return sideBar_->size().width() > sz.normal; -} void ChatPage::initiateLogout() diff --git a/src/ChatPage.h b/src/ChatPage.h index ba1c56d1ec789359abda55067323cb3cd8b2d289..a139b5fd768d77f16d81eba8a3251ea7eb03faf8 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -49,7 +49,6 @@ class SideBarActions; class Splitter; class TextInputWidget; class TimelineViewManager; -class TopRoomBar; class UserInfoWidget; class UserSettings; @@ -82,7 +81,6 @@ public: //! Calculate the width of the message timeline. uint64_t timelineWidth(); - bool isSideBarExpanded(); //! Hide the room & group list (if it was visible). void hideSideBars(); //! Show the room/group list (if it was visible). @@ -150,7 +148,6 @@ signals: void syncUI(const mtx::responses::Rooms &rooms); void syncRoomlist(const std::map<QString, RoomInfo> &updates); void syncTags(const std::map<QString, RoomInfo> &updates); - void syncTopBar(const std::map<QString, RoomInfo> &updates); void dropToLoginPageCb(const QString &msg); void notifyMessage(const QString &roomid, @@ -167,8 +164,6 @@ signals: private slots: void showUnreadMessageNotification(int count); - void updateTopBarAvatar(const QString &roomid, const QString &img); - void changeTopRoomInfo(const QString &room_id); void logout(); void removeRoom(const QString &room_id); void dropToLoginPage(const QString &msg); @@ -239,7 +234,6 @@ private: TimelineViewManager *view_manager_; SideBarActions *sidebarActions_; - TopRoomBar *top_bar_; TextInputWidget *text_input_; ActiveCallBar *activeCallBar_; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 4dab3d26f1640ac075eed37f4d2dd5ee03c2d2e5..29abed864b6d3650304736de54e92798c2f83b73 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -200,7 +200,8 @@ MainWindow::adjustSideBars() const uint64_t timelineWidth = chat_page_->timelineWidth(); const uint64_t minAvailableWidth = sz.collapsePoint + sz.groups; - if (timelineWidth < minAvailableWidth && !chat_page_->isSideBarExpanded()) { + nhlog::ui()->info("timelineWidth: {}, min {}", timelineWidth, minAvailableWidth); + if (timelineWidth < minAvailableWidth) { chat_page_->hideSideBars(); } else { chat_page_->showSideBars(); @@ -339,9 +340,7 @@ MainWindow::openUserProfile(const QString &user_id, const QString &room_id) void MainWindow::openRoomSettings(const QString &room_id) { - const auto roomToSearch = room_id.isEmpty() ? chat_page_->currentRoom() : ""; - - auto dialog = new dialogs::RoomSettings(roomToSearch, this); + auto dialog = new dialogs::RoomSettings(room_id, this); showDialog(dialog); } @@ -349,8 +348,7 @@ MainWindow::openRoomSettings(const QString &room_id) void MainWindow::openMemberListDialog(const QString &room_id) { - const auto roomToSearch = room_id.isEmpty() ? chat_page_->currentRoom() : ""; - auto dialog = new dialogs::MemberList(roomToSearch, this); + auto dialog = new dialogs::MemberList(room_id, this); showDialog(dialog); } @@ -358,11 +356,9 @@ MainWindow::openMemberListDialog(const QString &room_id) void MainWindow::openLeaveRoomDialog(const QString &room_id) { - auto roomToLeave = room_id.isEmpty() ? chat_page_->currentRoom() : room_id; - auto dialog = new dialogs::LeaveRoom(this); - connect(dialog, &dialogs::LeaveRoom::leaving, this, [this, roomToLeave]() { - chat_page_->leaveRoom(roomToLeave); + connect(dialog, &dialogs::LeaveRoom::leaving, this, [this, room_id]() { + chat_page_->leaveRoom(room_id); }); showDialog(dialog); diff --git a/src/MainWindow.h b/src/MainWindow.h index e3e046981756794cd52b800b75fade489e35d81d..4f54a195dc9a9b54d1308cd047e84be35b94b38b 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -68,14 +68,14 @@ public: static MainWindow *instance() { return instance_; }; void saveCurrentWindowSize(); - void openLeaveRoomDialog(const QString &room_id = ""); + void openLeaveRoomDialog(const QString &room_id); void openInviteUsersDialog(std::function<void(const QStringList &invitees)> callback); void openCreateRoomDialog( std::function<void(const mtx::requests::CreateRoom &request)> callback); void openJoinRoomDialog(std::function<void(const QString &room_id)> callback); void openLogoutDialog(); - void openRoomSettings(const QString &room_id = ""); - void openMemberListDialog(const QString &room_id = ""); + void openRoomSettings(const QString &room_id); + void openMemberListDialog(const QString &room_id); void openUserProfile(const QString &user_id, const QString &room_id); void openReadReceiptsDialog(const QString &event_id); diff --git a/src/MxcImageProvider.cpp b/src/MxcImageProvider.cpp index a197e4aa3f124d4acf53b1903a42efd24d51514f..b59fdff8a96c2bcd6485505afb33c8357fc77901 100644 --- a/src/MxcImageProvider.cpp +++ b/src/MxcImageProvider.cpp @@ -17,13 +17,16 @@ MxcImageResponse::run() auto data = cache::image(fileName); if (!data.isNull()) { m_image = utils::readImage(&data); - m_image = m_image.scaled( - m_requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); - m_image.setText("mxc url", "mxc://" + m_id); if (!m_image.isNull()) { - emit finished(); - return; + m_image = m_image.scaled( + m_requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + m_image.setText("mxc url", "mxc://" + m_id); + + if (!m_image.isNull()) { + emit finished(); + return; + } } } @@ -34,7 +37,7 @@ MxcImageResponse::run() opts.method = "crop"; http::client()->get_thumbnail( opts, [this, fileName](const std::string &res, mtx::http::RequestErr err) { - if (err) { + if (err || res.empty()) { nhlog::net()->error("Failed to download image {}", m_id.toStdString()); m_error = "Failed download"; @@ -46,6 +49,10 @@ MxcImageResponse::run() auto data = QByteArray(res.data(), res.size()); cache::saveImage(fileName, data); m_image = utils::readImage(&data); + if (!m_image.isNull()) { + m_image = m_image.scaled( + m_requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } m_image.setText("mxc url", "mxc://" + m_id); emit finished(); diff --git a/src/TopRoomBar.cpp b/src/TopRoomBar.cpp deleted file mode 100644 index a45a751e75b5ed1ab15a1e153e963e973c1da2d6..0000000000000000000000000000000000000000 --- a/src/TopRoomBar.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <QAction> -#include <QIcon> -#include <QLabel> -#include <QPaintEvent> -#include <QPainter> -#include <QPen> -#include <QPoint> -#include <QStyle> -#include <QStyleOption> -#include <QVBoxLayout> - -#include "Config.h" -#include "MainWindow.h" -#include "TopRoomBar.h" -#include "Utils.h" -#include "ui/Avatar.h" -#include "ui/FlatButton.h" -#include "ui/Menu.h" -#include "ui/OverlayModal.h" -#include "ui/TextLabel.h" - -TopRoomBar::TopRoomBar(QWidget *parent) - : QWidget(parent) - , buttonSize_{32} -{ - QFont f; - f.setPointSizeF(f.pointSizeF()); - - const int fontHeight = QFontMetrics(f).height(); - const int widgetMargin = fontHeight / 3; - const int contentHeight = fontHeight * 3; - - setFixedHeight(contentHeight + widgetMargin); - - topLayout_ = new QHBoxLayout(this); - topLayout_->setSpacing(widgetMargin); - topLayout_->setContentsMargins( - 2 * widgetMargin, widgetMargin, 2 * widgetMargin, widgetMargin); - - avatar_ = new Avatar(this, fontHeight * 2); - avatar_->setLetter(""); - - textLayout_ = new QVBoxLayout(); - textLayout_->setSpacing(0); - textLayout_->setMargin(0); - - QFont roomFont; - roomFont.setPointSizeF(roomFont.pointSizeF() * 1.1); - roomFont.setWeight(QFont::Medium); - - nameLabel_ = new QLabel(this); - nameLabel_->setFont(roomFont); - nameLabel_->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - - QFont descriptionFont; - - topicLabel_ = new TextLabel(this); - topicLabel_->setLineWrapMode(QTextEdit::NoWrap); - topicLabel_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - topicLabel_->setFont(descriptionFont); - topicLabel_->setTextInteractionFlags(Qt::TextBrowserInteraction); - topicLabel_->setOpenExternalLinks(true); - topicLabel_->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - - textLayout_->addWidget(nameLabel_); - textLayout_->addWidget(topicLabel_); - - settingsBtn_ = new FlatButton(this); - settingsBtn_->setToolTip(tr("Room options")); - settingsBtn_->setFixedSize(buttonSize_, buttonSize_); - settingsBtn_->setCornerRadius(buttonSize_ / 2); - - mentionsBtn_ = new FlatButton(this); - mentionsBtn_->setToolTip(tr("Mentions")); - mentionsBtn_->setFixedSize(buttonSize_, buttonSize_); - mentionsBtn_->setCornerRadius(buttonSize_ / 2); - - QIcon settings_icon; - settings_icon.addFile(":/icons/icons/ui/vertical-ellipsis.png"); - settingsBtn_->setIcon(settings_icon); - settingsBtn_->setIconSize(QSize(buttonSize_ / 2, buttonSize_ / 2)); - - QIcon mentions_icon; - mentions_icon.addFile(":/icons/icons/ui/at-solid.svg"); - mentionsBtn_->setIcon(mentions_icon); - mentionsBtn_->setIconSize(QSize(buttonSize_ / 2, buttonSize_ / 2)); - - backBtn_ = new FlatButton(this); - backBtn_->setFixedSize(buttonSize_, buttonSize_); - backBtn_->setCornerRadius(buttonSize_ / 2); - - QIcon backIcon; - backIcon.addFile(":/icons/icons/ui/angle-pointing-to-left.png"); - backBtn_->setIcon(backIcon); - backBtn_->setIconSize(QSize(buttonSize_ / 2, buttonSize_ / 2)); - backBtn_->hide(); - - connect(backBtn_, &QPushButton::clicked, this, &TopRoomBar::showRoomList); - - topLayout_->addWidget(avatar_); - topLayout_->addWidget(backBtn_); - topLayout_->addLayout(textLayout_, 1); - topLayout_->addWidget(mentionsBtn_, 0, Qt::AlignRight); - topLayout_->addWidget(settingsBtn_, 0, Qt::AlignRight); - - menu_ = new Menu(this); - - inviteUsers_ = new QAction(tr("Invite users"), this); - connect(inviteUsers_, &QAction::triggered, this, [this]() { - MainWindow::instance()->openInviteUsersDialog( - [this](const QStringList &invitees) { emit inviteUsers(invitees); }); - }); - - roomMembers_ = new QAction(tr("Members"), this); - connect(roomMembers_, &QAction::triggered, this, []() { - MainWindow::instance()->openMemberListDialog(); - }); - - leaveRoom_ = new QAction(tr("Leave room"), this); - connect(leaveRoom_, &QAction::triggered, this, []() { - MainWindow::instance()->openLeaveRoomDialog(); - }); - - roomSettings_ = new QAction(tr("Settings"), this); - connect(roomSettings_, &QAction::triggered, this, []() { - MainWindow::instance()->openRoomSettings(); - }); - - menu_->addAction(inviteUsers_); - menu_->addAction(roomMembers_); - menu_->addAction(leaveRoom_); - menu_->addAction(roomSettings_); - - connect(settingsBtn_, &QPushButton::clicked, this, [this]() { - auto pos = mapToGlobal(settingsBtn_->pos()); - menu_->popup( - QPoint(pos.x() + buttonSize_ - menu_->sizeHint().width(), pos.y() + buttonSize_)); - }); - - connect(mentionsBtn_, &QPushButton::clicked, this, [this]() { - auto pos = mapToGlobal(mentionsBtn_->pos()); - emit mentionsClicked(pos); - }); -} - -void -TopRoomBar::enableBackButton() -{ - avatar_->hide(); - backBtn_->show(); -} - -void -TopRoomBar::disableBackButton() -{ - avatar_->show(); - backBtn_->hide(); -} - -void -TopRoomBar::updateRoomAvatarFromName(const QString &name) -{ - avatar_->setLetter(utils::firstChar(name)); - update(); -} - -void -TopRoomBar::reset() -{ - nameLabel_->setText(""); - topicLabel_->setText(""); - avatar_->setLetter(""); -} - -void -TopRoomBar::updateRoomAvatar(const QString &avatar_image) -{ - avatar_->setImage(avatar_image); - update(); -} - -void -TopRoomBar::updateRoomName(const QString &name) -{ - nameLabel_->setText(name); - update(); -} - -void -TopRoomBar::updateRoomTopic(QString topic) -{ - topic.replace(conf::strings::url_regex, conf::strings::url_html); - topicLabel_->clearLinks(); - topicLabel_->setHtml(topic); - update(); -} - -void -TopRoomBar::mousePressEvent(QMouseEvent *) -{ - if (roomSettings_ != nullptr) - roomSettings_->trigger(); -} - -void -TopRoomBar::paintEvent(QPaintEvent *) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/TopRoomBar.h b/src/TopRoomBar.h deleted file mode 100644 index 0c33c1e0d1fff1f72824de9cf252818530904a04..0000000000000000000000000000000000000000 --- a/src/TopRoomBar.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include <QColor> -#include <QStringList> -#include <QWidget> - -class Avatar; -class FlatButton; -class Menu; -class TextLabel; -class OverlayModal; - -class QLabel; -class QHBoxLayout; -class QVBoxLayout; - -class TopRoomBar : public QWidget -{ - Q_OBJECT - - Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor) - -public: - TopRoomBar(QWidget *parent = nullptr); - - void updateRoomAvatar(const QString &avatar_image); - void updateRoomName(const QString &name); - void updateRoomTopic(QString topic); - void updateRoomAvatarFromName(const QString &name); - - void reset(); - - QColor borderColor() const { return borderColor_; } - void setBorderColor(QColor &color) { borderColor_ = color; } - -public slots: - //! Add a "back-arrow" button that can switch to roomlist only view. - void enableBackButton(); - //! Replace the "back-arrow" button with the avatar of the room. - void disableBackButton(); - -signals: - void inviteUsers(QStringList users); - void showRoomList(); - void mentionsClicked(const QPoint &pos); - -protected: - void mousePressEvent(QMouseEvent *) override; - void paintEvent(QPaintEvent *) override; - -private: - QHBoxLayout *topLayout_ = nullptr; - QVBoxLayout *textLayout_ = nullptr; - - QLabel *nameLabel_ = nullptr; - TextLabel *topicLabel_ = nullptr; - - Menu *menu_; - QAction *leaveRoom_ = nullptr; - QAction *roomMembers_ = nullptr; - QAction *roomSettings_ = nullptr; - QAction *inviteUsers_ = nullptr; - - FlatButton *settingsBtn_; - FlatButton *mentionsBtn_; - FlatButton *backBtn_; - - Avatar *avatar_; - - int buttonSize_; - - QColor borderColor_; -}; diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index ab5658a40ae07bb999fc89890b7613200d9804f7..f1542ec5e021da3ccb1705d51fdf90b46aa93ba6 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -513,9 +513,6 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge callsLabel->setFont(font); useStunServer_ = new Toggle{this}; - defaultAudioSourceValue_ = new QLabel(this); - defaultAudioSourceValue_->setFont(font); - auto encryptionLabel_ = new QLabel{tr("ENCRYPTION"), this}; encryptionLabel_->setFixedHeight(encryptionLabel_->minimumHeight() + LayoutTopMargin); encryptionLabel_->setAlignment(Qt::AlignBottom); @@ -652,7 +649,6 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge boxWrap(tr("Allow fallback call assist server"), useStunServer_, tr("Will use turn.matrix.org as assist when your home server does not offer one.")); - boxWrap(tr("Default audio source device"), defaultAudioSourceValue_); formLayout_->addRow(encryptionLabel_); formLayout_->addRow(new HorizontalLine{this}); @@ -813,7 +809,6 @@ UserSettingsPage::showEvent(QShowEvent *) deviceIdValue_->setText(QString::fromStdString(http::client()->device_id())); timelineMaxWidthSpin_->setValue(settings_->timelineMaxWidth()); useStunServer_->setState(!settings_->useStunServer()); - defaultAudioSourceValue_->setText(settings_->defaultAudioSource()); deviceFingerprintValue_->setText( utils::humanReadableFingerprint(olm::client()->identity_keys().ed25519)); diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h index 52ff9466a0a9fb42f7486daf70651d3340b3a01f..e947bfaec29dd8170cb2e9d08e09dc46e1854764 100644 --- a/src/UserSettingsPage.h +++ b/src/UserSettingsPage.h @@ -250,7 +250,6 @@ private: Toggle *decryptSidebar_; QLabel *deviceFingerprintValue_; QLabel *deviceIdValue_; - QLabel *defaultAudioSourceValue_; QComboBox *themeCombo_; QComboBox *scaleFactorCombo_; diff --git a/src/WebRTCSession.cpp b/src/WebRTCSession.cpp index 1c1d008de57a0b4b2948b671e966e5aaeea3ca12..a3900b482602127627e96c58c7341f5515b76c19 100644 --- a/src/WebRTCSession.cpp +++ b/src/WebRTCSession.cpp @@ -426,8 +426,12 @@ WebRTCSession::acceptICECandidates( for (const auto &c : candidates) { nhlog::ui()->debug( "WebRTC: remote candidate: (m-line:{}):{}", c.sdpMLineIndex, c.candidate); - g_signal_emit_by_name( - webrtc_, "add-ice-candidate", c.sdpMLineIndex, c.candidate.c_str()); + if (!c.candidate.empty()) { + g_signal_emit_by_name(webrtc_, + "add-ice-candidate", + c.sdpMLineIndex, + c.candidate.c_str()); + } } } } @@ -491,7 +495,7 @@ WebRTCSession::startPipeline(int opusPayloadType) } GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipe_)); - gst_bus_add_watch(bus, newBusMessage, this); + busWatchId_ = gst_bus_add_watch(bus, newBusMessage, this); gst_object_unref(bus); emit stateChanged(State::INITIATED); return true; @@ -597,6 +601,8 @@ WebRTCSession::end() gst_element_set_state(pipe_, GST_STATE_NULL); gst_object_unref(pipe_); pipe_ = nullptr; + g_source_remove(busWatchId_); + busWatchId_ = 0; } webrtc_ = nullptr; if (state_ != State::DISCONNECTED) diff --git a/src/WebRTCSession.h b/src/WebRTCSession.h index 56d76fa83b0d81d629eb2cf9b5c1a4b2dac3895f..8e78812f1004a6c1d23577844b801ff35753e5d2 100644 --- a/src/WebRTCSession.h +++ b/src/WebRTCSession.h @@ -64,10 +64,11 @@ private slots: private: WebRTCSession(); - bool initialised_ = false; - State state_ = State::DISCONNECTED; - GstElement *pipe_ = nullptr; - GstElement *webrtc_ = nullptr; + bool initialised_ = false; + State state_ = State::DISCONNECTED; + GstElement *pipe_ = nullptr; + GstElement *webrtc_ = nullptr; + unsigned int busWatchId_ = 0; std::string stunServer_; std::vector<std::string> turnServers_; GList *audioSources_ = nullptr; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index b6c2d4bb346463eca7b1e5c6aefd5e536904a6ae..32e9f92c0fb6367b1fef50f3845d9ebcd1b56d57 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -517,6 +517,25 @@ TimelineModel::fetchMore(const QModelIndex &) events.fetchMore(); } +void +TimelineModel::syncState(const mtx::responses::State &s) +{ + using namespace mtx::events; + + for (const auto &e : s.events) { + if (std::holds_alternative<StateEvent<state::Avatar>>(e)) + emit roomAvatarUrlChanged(); + else if (std::holds_alternative<StateEvent<state::Name>>(e)) + emit roomNameChanged(); + else if (std::holds_alternative<StateEvent<state::Topic>>(e)) + emit roomTopicChanged(); + else if (std::holds_alternative<StateEvent<state::Member>>(e)) { + emit roomAvatarUrlChanged(); + emit roomNameChanged(); + } + } +} + void TimelineModel::addEvents(const mtx::responses::Timeline &timeline) { @@ -526,6 +545,7 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline) events.handleSync(timeline); using namespace mtx::events; + for (auto e : timeline.events) { if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) { MegolmSessionIndex index; @@ -549,6 +569,16 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline) emit newCallEvent(event); }, e); + else if (std::holds_alternative<StateEvent<state::Avatar>>(e)) + emit roomAvatarUrlChanged(); + else if (std::holds_alternative<StateEvent<state::Name>>(e)) + emit roomNameChanged(); + else if (std::holds_alternative<StateEvent<state::Topic>>(e)) + emit roomTopicChanged(); + else if (std::holds_alternative<StateEvent<state::Member>>(e)) { + emit roomAvatarUrlChanged(); + emit roomNameChanged(); + } } updateLastMessage(); } @@ -689,12 +719,6 @@ TimelineModel::formatDateSeparator(QDate date) const return date.toString(fmt); } -QString -TimelineModel::escapeEmoji(QString str) const -{ - return utils::replaceEmoji(str); -} - void TimelineModel::viewRawMessage(QString id) const { @@ -1359,7 +1383,7 @@ TimelineModel::formatTypingUsers(const std::vector<QString> &users, QColor bg) QStringList uidWithoutLast; auto formatUser = [this, bg](const QString &user_id) -> QString { - auto uncoloredUsername = escapeEmoji(displayName(user_id)); + auto uncoloredUsername = utils::replaceEmoji(displayName(user_id)); QString prefix = QString("<font color=\"%1\">").arg(manager_->userColor(user_id, bg).name()); @@ -1409,7 +1433,7 @@ TimelineModel::formatJoinRuleEvent(QString id) return ""; QString user = QString::fromStdString(event->sender); - QString name = escapeEmoji(displayName(user)); + QString name = utils::replaceEmoji(displayName(user)); switch (event->content.join_rule) { case mtx::events::state::JoinRule::Public: @@ -1434,7 +1458,7 @@ TimelineModel::formatGuestAccessEvent(QString id) return ""; QString user = QString::fromStdString(event->sender); - QString name = escapeEmoji(displayName(user)); + QString name = utils::replaceEmoji(displayName(user)); switch (event->content.guest_access) { case mtx::events::state::AccessState::CanJoin: @@ -1459,7 +1483,7 @@ TimelineModel::formatHistoryVisibilityEvent(QString id) return ""; QString user = QString::fromStdString(event->sender); - QString name = escapeEmoji(displayName(user)); + QString name = utils::replaceEmoji(displayName(user)); switch (event->content.history_visibility) { case mtx::events::state::Visibility::WorldReadable: @@ -1492,7 +1516,7 @@ TimelineModel::formatPowerLevelEvent(QString id) return ""; QString user = QString::fromStdString(event->sender); - QString name = escapeEmoji(displayName(user)); + QString name = utils::replaceEmoji(displayName(user)); // TODO: power levels rendering is actually a bit complex. work on this later. return tr("%1 has changed the room's permissions.").arg(name); @@ -1521,7 +1545,7 @@ TimelineModel::formatMemberEvent(QString id) } QString user = QString::fromStdString(event->state_key); - QString name = escapeEmoji(displayName(user)); + QString name = utils::replaceEmoji(displayName(user)); QString rendered; // see table https://matrix.org/docs/spec/client_server/latest#m-room-member @@ -1594,3 +1618,37 @@ TimelineModel::formatMemberEvent(QString id) return rendered; } + +QString +TimelineModel::roomName() const +{ + auto info = cache::getRoomInfo({room_id_.toStdString()}); + + if (!info.count(room_id_)) + return ""; + else + return QString::fromStdString(info[room_id_].name); +} + +QString +TimelineModel::roomAvatarUrl() const +{ + auto info = cache::getRoomInfo({room_id_.toStdString()}); + + if (!info.count(room_id_)) + return ""; + else + return QString::fromStdString(info[room_id_].avatar_url); +} + +QString +TimelineModel::roomTopic() const +{ + auto info = cache::getRoomInfo({room_id_.toStdString()}); + + if (!info.count(room_id_)) + return ""; + else + return utils::replaceEmoji(utils::linkifyMessage( + utils::escapeBlacklistedHtml(QString::fromStdString(info[room_id_].topic)))); +} diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 156606e699d6fa197cdf4a9da70db161bb4b13b3..6daaac1b79817dd90cd7cded58c1d9abde3b95d5 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -137,6 +137,9 @@ class TimelineModel : public QAbstractListModel Q_PROPERTY(QString reply READ reply WRITE setReply NOTIFY replyChanged RESET resetReply) Q_PROPERTY( bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged) + Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) + Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged) + Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged) public: explicit TimelineModel(TimelineViewManager *manager, @@ -194,7 +197,6 @@ public: Q_INVOKABLE QString formatGuestAccessEvent(QString id); Q_INVOKABLE QString formatPowerLevelEvent(QString id); - Q_INVOKABLE QString escapeEmoji(QString str) const; Q_INVOKABLE void viewRawMessage(QString id) const; Q_INVOKABLE void viewDecryptedRawMessage(QString id) const; Q_INVOKABLE void openUserProfile(QString userid) const; @@ -217,6 +219,7 @@ public: void updateLastMessage(); void addEvents(const mtx::responses::Timeline &events); + void syncState(const mtx::responses::State &state); template<class T> void sendMessageEvent(const T &content, mtx::events::EventType eventType); RelatedInfo relatedInfo(QString id); @@ -253,6 +256,11 @@ public slots: void setDecryptDescription(bool decrypt) { decryptDescription = decrypt; } void clearTimeline() { events.clearTimeline(); } + QString roomName() const; + QString roomTopic() const; + QString roomAvatarUrl() const; + QString roomId() const { return room_id_; } + private slots: void addPendingMessage(mtx::events::collections::TimelineEvents event); @@ -270,6 +278,10 @@ signals: void newMessageToSend(mtx::events::collections::TimelineEvents event); void addPendingMessageToStore(mtx::events::collections::TimelineEvents event); + void roomNameChanged(); + void roomTopicChanged(); + void roomAvatarUrlChanged(); + private: void sendEncryptedMessageEvent(const std::string &txn_id, nlohmann::json content, diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 466c3cee472d9c7ba2ed4a873340732e7136bf1f..abb807b317ca8b7abea8def3ddfd69d817f07d4f 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -12,6 +12,7 @@ #include "ColorImageProvider.h" #include "DelegateChooser.h" #include "Logging.h" +#include "MainWindow.h" #include "MatrixClient.h" #include "MxcImageProvider.h" #include "UserSettingsPage.h" @@ -76,7 +77,7 @@ TimelineViewManager::userStatus(QString id) const TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettings, CallManager *callManager, - QWidget *parent) + ChatPage *parent) : imgProvider(new MxcImageProvider()) , colorImgProvider(new ColorImageProvider()) , blurhashProvider(new BlurhashProvider()) @@ -131,15 +132,12 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin view->engine()->addImageProvider("blurhash", blurhashProvider); view->setSource(QUrl("qrc:///qml/TimelineView.qml")); - connect(dynamic_cast<ChatPage *>(parent), - &ChatPage::themeChanged, - this, - &TimelineViewManager::updateColorPalette); - connect(dynamic_cast<ChatPage *>(parent), + connect(parent, &ChatPage::themeChanged, this, &TimelineViewManager::updateColorPalette); + connect(parent, &ChatPage::decryptSidebarChanged, this, &TimelineViewManager::updateEncryptedDescriptions); - connect(dynamic_cast<ChatPage *>(parent), &ChatPage::loggedOut, this, [this]() { + connect(parent, &ChatPage::loggedOut, this, [this]() { isInitialSync_ = true; emit initialSyncChanged(true); }); @@ -157,6 +155,7 @@ TimelineViewManager::sync(const mtx::responses::Rooms &rooms) &TimelineModel::newCallEvent, callManager_, &CallManager::syncEvent); + room_model->syncState(room.state); room_model->addEvents(room.timeline); if (!isInitialSync_) disconnect(room_model.data(), @@ -207,6 +206,12 @@ TimelineViewManager::setHistoryView(const QString &room_id) } } +QString +TimelineViewManager::escapeEmoji(QString str) const +{ + return utils::replaceEmoji(str); +} + void TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId) const { @@ -245,6 +250,28 @@ TimelineViewManager::openLink(QString link) const QDesktopServices::openUrl(link); } +void +TimelineViewManager::openInviteUsersDialog() +{ + MainWindow::instance()->openInviteUsersDialog( + [this](const QStringList &invitees) { emit inviteUsers(invitees); }); +} +void +TimelineViewManager::openMemberListDialog() const +{ + MainWindow::instance()->openMemberListDialog(timeline_->roomId()); +} +void +TimelineViewManager::openLeaveRoomDialog() const +{ + MainWindow::instance()->openLeaveRoomDialog(timeline_->roomId()); +} +void +TimelineViewManager::openRoomSettings() const +{ + MainWindow::instance()->openRoomSettings(timeline_->roomId()); +} + void TimelineViewManager::updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids) diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index ea6d1743fe0fc9cee357050d2628742dbff7a6f7..1a98f64db25bd317f3328b97ea61a52de5a057fc 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -21,6 +21,7 @@ class BlurhashProvider; class CallManager; class ColorImageProvider; class UserSettings; +class ChatPage; class TimelineViewManager : public QObject { @@ -30,11 +31,13 @@ class TimelineViewManager : public QObject TimelineModel *timeline MEMBER timeline_ READ activeTimeline NOTIFY activeTimelineChanged) Q_PROPERTY( bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged) + Q_PROPERTY( + bool isNarrowView MEMBER isNarrowView_ READ isNarrowView NOTIFY narrowViewChanged) public: TimelineViewManager(QSharedPointer<UserSettings> userSettings, CallManager *callManager, - QWidget *parent = nullptr); + ChatPage *parent = nullptr); QWidget *getWidget() const { return container; } void sync(const mtx::responses::Rooms &rooms); @@ -44,14 +47,21 @@ public: Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; } Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; } + bool isNarrowView() const { return isNarrowView_; } Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId) const; Q_INVOKABLE QColor userColor(QString id, QColor background); + Q_INVOKABLE QString escapeEmoji(QString str) const; Q_INVOKABLE QString userPresence(QString id) const; Q_INVOKABLE QString userStatus(QString id) const; Q_INVOKABLE void openLink(QString link) const; + Q_INVOKABLE void openInviteUsersDialog(); + Q_INVOKABLE void openMemberListDialog() const; + Q_INVOKABLE void openLeaveRoomDialog() const; + Q_INVOKABLE void openRoomSettings() const; + signals: void clearRoomMessageCount(QString roomid); void updateRoomsLastMessage(QString roomid, const DescInfo &info); @@ -59,6 +69,9 @@ signals: void initialSyncChanged(bool isInitialSync); void replyingEventChanged(QString replyingEvent); void replyClosed(); + void inviteUsers(QStringList users); + void showRoomList(); + void narrowViewChanged(); public slots: void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids); @@ -108,6 +121,23 @@ public slots: timeline_->clearTimeline(); } + void enableBackButton() + { + if (isNarrowView_) + return; + isNarrowView_ = true; + emit narrowViewChanged(); + } + void disableBackButton() + { + if (!isNarrowView_) + return; + isNarrowView_ = false; + emit narrowViewChanged(); + } + + void backToRooms() { emit showRoomList(); } + private: #ifdef USE_QUICK_VIEW QQuickView *view; @@ -125,6 +155,7 @@ private: CallManager *callManager_ = nullptr; bool isInitialSync_ = true; + bool isNarrowView_ = false; QSharedPointer<UserSettings> settings; QHash<QString, QColor> userColors; diff --git a/third_party/blurhash/blurhash.cpp b/third_party/blurhash/blurhash.cpp index cd0a18a46b23b97d7505a0c9767d495dfab17df9..a4adf89f7acf616e7bf6cc6c08d8bfff2de4e48c 100644 --- a/third_party/blurhash/blurhash.cpp +++ b/third_party/blurhash/blurhash.cpp @@ -260,6 +260,7 @@ decode(std::string_view blurhash, size_t width, size_t height, size_t bytesPerPi Components components{}; std::vector<Color> values; + values.reserve(blurhash.size() / 2); try { components = unpackComponents(decode83(blurhash.substr(0, 1))); @@ -277,7 +278,7 @@ decode(std::string_view blurhash, size_t width, size_t height, size_t bytesPerPi return {}; } - i.image.reserve(height * width * 3); + i.image.reserve(height * width * bytesPerPixel); for (size_t y = 0; y < height; y++) { for (size_t x = 0; x < width; x++) { @@ -344,7 +345,7 @@ encode(unsigned char *image, size_t width, size_t height, int components_x, int } int quantisedMaximumValue = encodeMaxAC(actualMaximumValue); - maximumValue = ((float)quantisedMaximumValue + 1) / 166; + maximumValue = ((float)quantisedMaximumValue + 1) / 166; h += leftPad(encode83(quantisedMaximumValue), 1); } else { maximumValue = 1; @@ -406,7 +407,7 @@ TEST_CASE("AC") { auto h = "00%#MwS|WCWEM{R*bbWBbH"sv; for (size_t i = 0; i < h.size(); i += 2) { - auto s = h.substr(i, 2); + auto s = h.substr(i, 2); const auto maxAC = 0.289157f; CHECK(leftPad(encode83(encodeAC(decodeAC(decode83(s), maxAC), maxAC)), 2) == s); }