diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e41ebc8b83b68d1a9ef7678f9abed2e0d0802f5..828509471bc6f6b9902173f675d588f1a8c5e6ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,6 +280,7 @@ set(SRC_FILES src/ui/InfoMessage.cpp src/ui/Label.cpp src/ui/LoadingIndicator.cpp + src/ui/NhekoCursorShape.cpp src/ui/NhekoDropArea.cpp src/ui/OverlayModal.cpp src/ui/OverlayWidget.cpp @@ -298,6 +299,7 @@ set(SRC_FILES src/AvatarProvider.cpp src/BlurhashProvider.cpp src/Cache.cpp + src/CallDevices.cpp src/CallManager.cpp src/ChatPage.cpp src/ColorImageProvider.cpp @@ -355,7 +357,7 @@ if(USE_BUNDLED_MTXCLIENT) FetchContent_Declare( MatrixClient GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git - GIT_TAG v0.4.1 + GIT_TAG fee5298f068394958c2de935836a2c145f273906 ) set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "") set(BUILD_LIB_TESTS OFF CACHE INTERNAL "") @@ -493,6 +495,7 @@ qt5_wrap_cpp(MOC_HEADERS src/ui/Label.h src/ui/FloatingButton.h src/ui/Menu.h + src/ui/NhekoCursorShape.h src/ui/NhekoDropArea.h src/ui/OverlayWidget.h src/ui/SnackBar.h @@ -512,6 +515,7 @@ qt5_wrap_cpp(MOC_HEADERS src/AvatarProvider.h src/BlurhashProvider.h src/Cache_p.h + src/CallDevices.h src/CallManager.h src/ChatPage.h src/CommunitiesList.h @@ -645,7 +649,7 @@ if(QML_DEBUGGING) endif() -if(NOT MSVC) +if(NOT MSVC AND NOT HAIKU) if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug" OR CI_BUILD) target_compile_options(nheko PRIVATE "-Werror") endif() diff --git a/README.md b/README.md index be7d076f29bb9fee7b0ef8298d6e4cb4365f5d8e..b9690fc54fa3c9967d599d77173ae5214125ce6e 100644 --- a/README.md +++ b/README.md @@ -116,9 +116,7 @@ brew install --cask nheko ### Build Requirements -- Qt5 (5.10 or greater). Qt 5.7 adds support for color font rendering with - Freetype, which is essential to properly support emoji, 5.8 adds some features - to make interopability with Qml easier, 5.10 makes sliders actually visible with different palettes. +- Qt5 (5.12 or greater). Required for overlapping hover handlers in Qml. - CMake 3.15 or greater. (Lower version may work, but may break boost linking) - [mtxclient](https://github.com/Nheko-Reborn/mtxclient) - [LMDB](https://symas.com/lightning-memory-mapped-database/) @@ -205,7 +203,7 @@ and mtxclient (needs to be build separately). ```bash sudo apt install cmake gcc make automake liblmdb-dev \ qt5-default libssl-dev libqt5multimedia5-plugins libqt5multimediagsttools5 libqt5multimediaquick5 libqt5svg5-dev \ - qml-module-qtgstreamer qtmultimedia5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools \ + qml-module-qtgstreamer qtmultimedia5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools qtdeclarative5-dev \ qml-module-qtgraphicaleffects qml-module-qtmultimedia qml-module-qtquick-controls2 qml-module-qtquick-layouts \ qt5keychain-dev ``` diff --git a/io.github.NhekoReborn.Nheko.json b/io.github.NhekoReborn.Nheko.json index e6eeb12333f6ff76c4767846f08608733d03945d..453d6c8a7a5fc4c72a39106bd50394fe8744c150 100644 --- a/io.github.NhekoReborn.Nheko.json +++ b/io.github.NhekoReborn.Nheko.json @@ -220,8 +220,7 @@ "name": "mtxclient", "sources": [ { - "commit": "4951190c938740defa0988d98d5e861038622936", - "tag": "v0.4.1", + "commit": "fee5298f068394958c2de935836a2c145f273906", "type": "git", "url": "https://github.com/Nheko-Reborn/mtxclient.git" } diff --git a/resources/langs/nheko_cs.ts b/resources/langs/nheko_cs.ts index 22bbd88bb7af3d4379b0ac760d6213c3a067e3a7..8ab0dd25c1fe23f5746f684d1a79770e89bea389 100644 --- a/resources/langs/nheko_cs.ts +++ b/resources/langs/nheko_cs.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation type="unfinished"></translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation type="unfinished"></translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -797,12 +797,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -999,15 +999,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation type="unfinished"></translation> </message> @@ -1149,7 +1154,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation type="unfinished"></translation> </message> @@ -1300,12 +1305,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1329,7 +1334,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1347,7 +1362,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1356,6 +1371,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1480,7 +1500,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1503,7 +1528,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1522,11 +1547,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <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> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation type="unfinished"></translation> </message> @@ -1546,12 +1600,17 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1604,6 +1663,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1714,7 +1796,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1724,7 +1806,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation type="unfinished"></translation> </message> @@ -1799,7 +1881,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation type="unfinished"></translation> </message> @@ -1819,17 +1901,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation type="unfinished"></translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1899,7 +1981,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation type="unfinished"></translation> </message> @@ -1995,7 +2077,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation type="unfinished"></translation> </message> diff --git a/resources/langs/nheko_de.ts b/resources/langs/nheko_de.ts index 9b827a91140a64f651a40f1de34af94f2832f4eb..18327ea351dcfe40eedaebbe7680b8b2cea7dea8 100644 --- a/resources/langs/nheko_de.ts +++ b/resources/langs/nheko_de.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Du bist dem Raum beigetreten.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Nutzer konnte nicht eingeladen werden: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>Eingeladener Benutzer: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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>-- Verschlüsseltes Event (keine Schlüssel zur Entschlüsselung gefunden) --</translation> @@ -568,7 +568,7 @@ <translation>Alle Dateien (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation>Medienupload fehlgeschlagen. Bitte versuche es erneut.</translation> </message> @@ -801,12 +801,12 @@ Beispiel: https://mein.server:8787</translation> <translation>Schreibe eine Nachricht…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation>Emoji</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation>Senden</translation> </message> @@ -1003,15 +1003,20 @@ Beispiel: https://mein.server:8787</translation> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Schließen</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>keine Version gespeichert</translation> </message> @@ -1153,7 +1158,7 @@ Beispiel: https://mein.server:8787</translation> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Nachricht zurückziehen fehlgeschlagen: %1</translation> </message> @@ -1303,12 +1308,12 @@ Beispiel: https://mein.server:8787</translation> <translation>%1 hat das Anklopfen zurückgezogen.</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>Du bist dem Raum beigetreten.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>Hat das Anklopfen von %1 abgewiesen.</translation> </message> @@ -1332,7 +1337,17 @@ Beispiel: https://mein.server:8787</translation> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation>Reaktion senden</translation> </message> @@ -1350,7 +1365,7 @@ Beispiel: https://mein.server:8787</translation> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation>Reaktion senden</translation> </message> @@ -1359,6 +1374,11 @@ Beispiel: https://mein.server:8787</translation> <source>Reply</source> <translation>Antworten</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1483,7 +1503,12 @@ Beispiel: https://mein.server:8787</translation> <translation>Status:</translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation>Setze Präsenz automatisch</translation> </message> @@ -1506,7 +1531,7 @@ Beispiel: https://mein.server:8787</translation> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation>Verifizieren</translation> </message> @@ -1525,11 +1550,40 @@ Beispiel: https://mein.server:8787</translation> <source>Kick the user</source> <translation>Kicke den Nutzer</translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation type="unfinished">Wähle einen Avatar</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished">Alle Dateien (*)</translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation type="unfinished">Die ausgewählte Datei ist kein Bild</translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation type="unfinished">Fehler beim Lesen der DateI: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Ins Benachrichtigungsfeld minimieren</translation> </message> @@ -1549,12 +1603,17 @@ Beispiel: https://mein.server:8787</translation> <translation>Runde Profilbilder</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation>Profil: %1</translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation>TELEFONATE</translation> </message> @@ -1609,6 +1668,29 @@ Betrifft nur Nachrichten in verschlüsselten Chats.</translation> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation>Zeige Buttons in der Historie</translation> </message> @@ -1725,7 +1807,7 @@ Normalerweise animiert das den Taskbaricon oder färbt das Fenster orange ein.</ <translation>Teile Schlüssel mit verifizierten Nutzern und Geräten</translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation>IM CACHE</translation> </message> @@ -1735,7 +1817,7 @@ Normalerweise animiert das den Taskbaricon oder färbt das Fenster orange ein.</ <translation>NICHT IM CACHE</translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>Skalierungsfaktor</translation> </message> @@ -1810,7 +1892,7 @@ Normalerweise animiert das den Taskbaricon oder färbt das Fenster orange ein.</ <translation>Gerätefingerabdruck</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Sitzungsschlüssel</translation> </message> @@ -1830,17 +1912,17 @@ Normalerweise animiert das den Taskbaricon oder färbt das Fenster orange ein.</ <translation>VERSCHLÃœSSELUNG</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>ALLGEMEINES</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation>OBERFLÄCHE</translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation>Touchscreenmodus</translation> </message> @@ -1910,7 +1992,7 @@ Normalerweise animiert das den Taskbaricon oder färbt das Fenster orange ein.</ <translation>Alle Dateien (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>Öffne Sessions Datei</translation> </message> @@ -2006,7 +2088,7 @@ Normalerweise animiert das den Taskbaricon oder färbt das Fenster orange ein.</ <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>Gestern</translation> </message> diff --git a/resources/langs/nheko_el.ts b/resources/langs/nheko_el.ts index e24539ce24066a62ad2b9c70982f59c7795ee429..f86dfcabc9a45a39a6d64351a47298e369c09e2a 100644 --- a/resources/langs/nheko_el.ts +++ b/resources/langs/nheko_el.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation type="unfinished"></translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation type="unfinished"></translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation type="unfinished">Όλα τα αÏχεία (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -797,12 +797,12 @@ Example: https://server.my:8787</source> <translation type="unfinished">ΓÏάψε Îνα μήνυμα...</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -999,15 +999,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation type="unfinished"></translation> </message> @@ -1149,7 +1154,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation type="unfinished"></translation> </message> @@ -1299,12 +1304,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1328,7 +1333,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1346,7 +1361,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1355,6 +1370,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1479,7 +1499,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1502,7 +1527,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1521,11 +1546,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <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> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Ελαχιστοποίηση</translation> </message> @@ -1545,12 +1599,17 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1603,6 +1662,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1713,7 +1795,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1723,7 +1805,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation type="unfinished"></translation> </message> @@ -1798,7 +1880,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation type="unfinished"></translation> </message> @@ -1818,17 +1900,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>ΓΕÎΙΚΑ</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1898,7 +1980,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished">Όλα τα αÏχεία (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation type="unfinished"></translation> </message> @@ -1994,7 +2076,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation type="unfinished"></translation> </message> diff --git a/resources/langs/nheko_en.ts b/resources/langs/nheko_en.ts index 9919e89e4aa1ac43830f4d0a8190de59a5f112d3..35c70c0b17fd172e2ab09e39a2056b5e781d19c4 100644 --- a/resources/langs/nheko_en.ts +++ b/resources/langs/nheko_en.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>You joined this room.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Failed to invite user: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>Invited user: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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>-- Encrypted Event (No keys found for decryption) --</translation> @@ -568,7 +568,7 @@ <translation>All Files (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation>Failed to upload media. Please try again.</translation> </message> @@ -801,12 +801,12 @@ Example: https://server.my:8787</translation> <translation>Write a message…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation>Emoji</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation>Send</translation> </message> @@ -1003,15 +1003,20 @@ Example: https://server.my:8787</translation> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Close</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation>Cancel edit</translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>no version stored</translation> </message> @@ -1153,7 +1158,7 @@ Example: https://server.my:8787</translation> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Message redaction failed: %1</translation> </message> @@ -1303,12 +1308,12 @@ Example: https://server.my:8787</translation> <translation>%1 redacted their knock.</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>You joined this room.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>Rejected the knock from %1.</translation> </message> @@ -1332,7 +1337,17 @@ Example: https://server.my:8787</translation> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation>Edit</translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation>Edited</translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation>React</translation> </message> @@ -1350,7 +1365,7 @@ Example: https://server.my:8787</translation> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation>React</translation> </message> @@ -1359,6 +1374,11 @@ Example: https://server.my:8787</translation> <source>Reply</source> <translation>Reply</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation>Edit</translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1483,7 +1503,12 @@ Example: https://server.my:8787</translation> <translation>Status:</translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation>User Profile Settings</translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation>Set presence automatically</translation> </message> @@ -1506,7 +1531,7 @@ Example: https://server.my:8787</translation> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation>Verify</translation> </message> @@ -1525,11 +1550,40 @@ Example: https://server.my:8787</translation> <source>Kick the user</source> <translation>Kick the user</translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation>Select an avatar</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation>All Files (*)</translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation>The selected file is not an image</translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation>Error while reading file: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation>Default</translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Minimize to tray</translation> </message> @@ -1549,12 +1603,17 @@ Example: https://server.my:8787</translation> <translation>Circular Avatars</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation>profile: %1</translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation>Default</translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation>CALLS</translation> </message> @@ -1609,6 +1668,32 @@ Only affects messages in encrypted chats.</translation> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation>Privacy Screen</translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation>When the window loses focus, the timeline will +be blurred.</translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation>Privacy screen timeout (in seconds [0 - 3600])</translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation>Show buttons in timeline</translation> </message> @@ -1725,7 +1810,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>Share keys with verified users and devices</translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation>CACHED</translation> </message> @@ -1735,7 +1820,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>NOT CACHED</translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>Scale factor</translation> </message> @@ -1810,7 +1895,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>Device Fingerprint</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Session Keys</translation> </message> @@ -1830,17 +1915,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation>ENCRYPTION</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>GENERAL</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation>INTERFACE</translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation>Touchscreen mode</translation> </message> @@ -1910,7 +1995,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>All Files (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>Open Sessions File</translation> </message> @@ -2006,7 +2091,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>Yesterday</translation> </message> diff --git a/resources/langs/nheko_eo.ts b/resources/langs/nheko_eo.ts index b09d824051889040814b7a64990d0e951002e50a..5f0eade70bd0ae4f8aa5db91d5a9f4b644e0f461 100644 --- a/resources/langs/nheko_eo.ts +++ b/resources/langs/nheko_eo.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Vi aliÄis ĉi tiun ĉambron.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation type="unfinished"></translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation type="unfinished"></translation> </message> @@ -480,7 +480,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -569,7 +569,7 @@ <translation type="unfinished">Ĉiuj dosieroj (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -802,12 +802,12 @@ Ekzemplo: https://servisto.mia:8787</translation> <translation type="unfinished">Skribu mesaÄon...</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation>Sendu</translation> </message> @@ -1004,15 +1004,20 @@ Ekzemplo: https://servisto.mia:8787</translation> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation type="unfinished"></translation> </message> @@ -1156,7 +1161,7 @@ Ekzemplo: https://servisto.mia:8787</translation> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation type="unfinished"></translation> </message> @@ -1308,12 +1313,12 @@ Ekzemplo: https://servisto.mia:8787</translation> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>Vi aliÄis ĉi tiun ĉambron.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1337,7 +1342,17 @@ Ekzemplo: https://servisto.mia:8787</translation> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation>Reagu</translation> </message> @@ -1355,7 +1370,7 @@ Ekzemplo: https://servisto.mia:8787</translation> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation>Reagu</translation> </message> @@ -1364,6 +1379,11 @@ Ekzemplo: https://servisto.mia:8787</translation> <source>Reply</source> <translation>Respondu</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1488,7 +1508,12 @@ Ekzemplo: https://servisto.mia:8787</translation> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1511,7 +1536,7 @@ Ekzemplo: https://servisto.mia:8787</translation> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1530,11 +1555,40 @@ Ekzemplo: https://servisto.mia:8787</translation> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished">Ĉiuj dosieroj (*)</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> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation type="unfinished"></translation> </message> @@ -1554,12 +1608,17 @@ Ekzemplo: https://servisto.mia:8787</translation> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1612,6 +1671,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1722,7 +1804,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1732,7 +1814,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation type="unfinished"></translation> </message> @@ -1807,7 +1889,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation type="unfinished"></translation> </message> @@ -1827,17 +1909,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation type="unfinished"></translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1907,7 +1989,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished">Ĉiuj dosieroj (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation type="unfinished"></translation> </message> @@ -2004,7 +2086,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>HieraÅ</translation> </message> diff --git a/resources/langs/nheko_et.ts b/resources/langs/nheko_et.ts index e3b46f954361ea6a25a13a93cddbc4389e21b1ec..7b73e0e528741a6df760aa4a247a1e7e0198b374 100644 --- a/resources/langs/nheko_et.ts +++ b/resources/langs/nheko_et.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Sa liitusid selle jututoaga.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Kutse saatmine kasutajale ei õnnestunud: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>Kutsutud kasutaja: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation>Kõik failid (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation>Meediafailide üleslaadimine ei õnnestunud. Palun proovi uuesti.</translation> </message> @@ -801,12 +801,12 @@ Näiteks: https://server.minu:8787</translation> <translation>Kirjuta sõnum…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation>Emoji</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation>Saada</translation> </message> @@ -1003,15 +1003,20 @@ Näiteks: https://server.minu:8787</translation> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Sulge</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation>Tühista muudatused</translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>salvestatud versiooni ei leidu</translation> </message> @@ -1153,7 +1158,7 @@ Näiteks: https://server.minu:8787</translation> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Sõnumi ümbersõnastamine ebaõnnestus: %1</translation> </message> @@ -1303,12 +1308,12 @@ Näiteks: https://server.minu:8787</translation> <translation>%1 muutis oma koputust jututoa uksele.</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>Sa liitusid jututoaga.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>Lükkas tagasi %1 koputuse jututoa uksele.</translation> </message> @@ -1332,7 +1337,17 @@ Näiteks: https://server.minu:8787</translation> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation>Muuda</translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation>Muudetud</translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation>Reageeri</translation> </message> @@ -1350,7 +1365,7 @@ Näiteks: https://server.minu:8787</translation> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation>Reageeri</translation> </message> @@ -1359,6 +1374,11 @@ Näiteks: https://server.minu:8787</translation> <source>Reply</source> <translation>Vasta</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation>Muuda</translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1483,7 +1503,12 @@ Näiteks: https://server.minu:8787</translation> <translation>Olek:</translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation>Kasutajaprofiili seadistused</translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation>Määra oma võrguolek automaatselt</translation> </message> @@ -1506,7 +1531,7 @@ Näiteks: https://server.minu:8787</translation> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation>Verifitseeri</translation> </message> @@ -1525,11 +1550,40 @@ Näiteks: https://server.minu:8787</translation> <source>Kick the user</source> <translation>Müksa kasutaja välja</translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation>Vali tunnuspilt</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation>Kõik failid (*)</translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation>Valitud fail ei ole pildifail</translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation>Viga faili lugemisel: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation>Vaikimisi</translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Vähenda tegumiribale</translation> </message> @@ -1549,12 +1603,17 @@ Näiteks: https://server.minu:8787</translation> <translation>Ãœmmargused tunnuspildid</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation>Profiil: %1</translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation>Vaikimisi</translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation>KÕNED</translation> </message> @@ -1609,6 +1668,32 @@ Kehtib vaid läbivalt krüptitud vestluste puhul.</translation> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation>Privaatsust tagav sirm</translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation>Kui aken kaotab fookuse, +siis ajajoone vaade hägustub.</translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation>Viivitus privaatsussirmi sisselülitamisel (sekundites [0 - 3600])</translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation>Seadista aeg sekundites, mille möödumisel +peale akna fookuse kadumist ajajoone vaade hägustub. +0 hägustab vaate koheselt. Pikim viivitus saab olla 1 tund (3600 sekundit)</translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation>Näita ajajoonel nuppe</translation> </message> @@ -1725,7 +1810,7 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim <translation>Jaga võtmeid verifitseeritud kasutajate ja seadmetega</translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation>PUHVERDATUD</translation> </message> @@ -1735,7 +1820,7 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim <translation>PUHVERDAMATA</translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>Mastaabitegur</translation> </message> @@ -1810,7 +1895,7 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim <translation>Seadme sõrmejälg</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Sessioonivõtmed</translation> </message> @@ -1830,17 +1915,17 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim <translation>KRÃœPTIMINE</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>ÃœLDISED SEADISTUSED</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation>LIIDES</translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation>Puuteekraani režiim</translation> </message> @@ -1910,7 +1995,7 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim <translation>Kõik failid (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>Ava sessioonide fail</translation> </message> @@ -2006,7 +2091,7 @@ See tavaliselt tähendab, et rakenduse ikoon tegumiribal annab mingit sorti anim <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>Eile</translation> </message> diff --git a/resources/langs/nheko_fi.ts b/resources/langs/nheko_fi.ts index f4a518e5334b7011417c8db26846658f4f41da53..4dbe14caf9df25b5a652130e08eaec8ca5962213 100644 --- a/resources/langs/nheko_fi.ts +++ b/resources/langs/nheko_fi.ts @@ -6,13 +6,13 @@ <message> <location filename="../qml/voip/ActiveCallBar.qml" line="+66"/> <source>Calling...</source> - <translation type="unfinished"></translation> + <translation>Soitetaan...</translation> </message> <message> <location line="+10"/> <location line="+10"/> <source>Connecting...</source> - <translation type="unfinished"></translation> + <translation>Yhdistetään...</translation> </message> <message> <location line="+76"/> @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> @@ -89,7 +89,7 @@ <message> <location line="+16"/> <source>Devices</source> - <translation type="unfinished">Laitteet</translation> + <translation>Laitteet</translation> </message> <message> <location line="+11"/> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation type="unfinished"></translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation type="unfinished"></translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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>-- Salattu viesti (salauksen purkuavaimia ei löydetty) --</translation> @@ -560,7 +560,7 @@ <message> <location filename="../../src/timeline/InputBar.cpp" line="+227"/> <source>Select a file</source> - <translation type="unfinished">Valitse tiedosto</translation> + <translation>Valitse tiedosto</translation> </message> <message> <location line="+0"/> @@ -568,7 +568,7 @@ <translation>Kaikki Tiedostot (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -789,7 +789,7 @@ Example: https://server.my:8787</source> <message> <location line="+26"/> <source>Send a file</source> - <translation type="unfinished">Lähetä tiedosto</translation> + <translation>Lähetä tiedosto</translation> </message> <message> <location line="+60"/> @@ -797,12 +797,12 @@ Example: https://server.my:8787</source> <translation>Kirjoita viesti…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> - <translation type="unfinished">Emoji</translation> + <translation>Emoji</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -999,15 +999,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Sulje</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>ei tallennettua versiota</translation> </message> @@ -1149,7 +1154,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Viestin muokkaus epäonnistui: %1</translation> </message> @@ -1299,12 +1304,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1328,7 +1333,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1346,7 +1361,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1355,6 +1370,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1479,7 +1499,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1502,7 +1527,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1521,11 +1546,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation>Valitse profiilikuva</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation>Kaikki Tiedostot (*)</translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation>Valittu tiedosto ei ole kuva</translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation>Virhe lukiessa tiedostoa: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Pienennä ilmoitusalueelle</translation> </message> @@ -1545,12 +1599,17 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1603,6 +1662,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1713,7 +1795,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1723,7 +1805,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>Mittakerroin</translation> </message> @@ -1798,7 +1880,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>Laitteen sormenjälki</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Istunnon avaimet</translation> </message> @@ -1818,17 +1900,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation>SALAUS</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>YLEISET ASETUKSET</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1890,7 +1972,7 @@ This usually causes the application icon in the task bar to animate in some fash <message> <location line="+54"/> <source>Select a file</source> - <translation type="unfinished">Valitse tiedosto</translation> + <translation>Valitse tiedosto</translation> </message> <message> <location line="+0"/> @@ -1898,7 +1980,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>Kaikki Tiedostot (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>Avaa Istuntoavaintiedosto</translation> </message> @@ -1994,7 +2076,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>Eilen</translation> </message> diff --git a/resources/langs/nheko_fr.ts b/resources/langs/nheko_fr.ts index 130bc0040ac14adf48ebdc3b842ae5506cbf94dc..090e2d1b1392a3c052930a13e1d6589b054b6a27 100644 --- a/resources/langs/nheko_fr.ts +++ b/resources/langs/nheko_fr.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Vous avez rejoint ce salon.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Échec lors de l'invitation de %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>%1 a été invité(e)</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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>-- Évènement chiffré (pas de clé trouvée pour le déchiffrement) --</translation> @@ -568,7 +568,7 @@ <translation>Tous les types de fichiers (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation>Échec de l'envoi du média. Veuillez réessayer.</translation> </message> @@ -801,12 +801,12 @@ Exemple : https ://monserveur.example.com :8787</translation> <translation>Écrivez un message…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation>Émoji</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation>Envoyer</translation> </message> @@ -1003,15 +1003,20 @@ Exemple : https ://monserveur.example.com :8787</translation> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Fermer</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>pas de version enregistrée</translation> </message> @@ -1153,7 +1158,7 @@ Exemple : https ://monserveur.example.com :8787</translation> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Échec de la suppression du message : %1</translation> </message> @@ -1303,12 +1308,12 @@ Exemple : https ://monserveur.example.com :8787</translation> <translation>%1 ne frappe plus au salon.</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>Vous avez rejoint ce salon.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>%1 a été rejeté après avoir frappé au salon.</translation> </message> @@ -1332,7 +1337,17 @@ Exemple : https ://monserveur.example.com :8787</translation> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation>Réagir</translation> </message> @@ -1350,7 +1365,7 @@ Exemple : https ://monserveur.example.com :8787</translation> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation>Réagir</translation> </message> @@ -1359,6 +1374,11 @@ Exemple : https ://monserveur.example.com :8787</translation> <source>Reply</source> <translation>Réponse</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1483,7 +1503,12 @@ Exemple : https ://monserveur.example.com :8787</translation> <translation>Statut :</translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation>Changer la présence automatiquement</translation> </message> @@ -1506,7 +1531,7 @@ Exemple : https ://monserveur.example.com :8787</translation> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation>Vérifier</translation> </message> @@ -1525,11 +1550,40 @@ Exemple : https ://monserveur.example.com :8787</translation> <source>Kick the user</source> <translation>Expulser l'utilisateur</translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation type="unfinished">Sélectionner un avatar</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished">Tous les types de fichiers (*)</translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation type="unfinished">Le fichier sélectionné n'est pas une image</translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation type="unfinished">Erreur lors de la lecture du fichier  : %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Réduire à la barre des tâches</translation> </message> @@ -1549,12 +1603,17 @@ Exemple : https ://monserveur.example.com :8787</translation> <translation>Avatars circulaires</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation>profil : %1</translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation>APPELS</translation> </message> @@ -1609,6 +1668,29 @@ Cela n'affecte que les messages des salons chiffrés.</translation> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation>Montrer les boutons dans la discussion</translation> </message> @@ -1726,7 +1808,7 @@ Cela met l'application en évidence dans la barre des tâches.</translation <translation>Partager vos clés avec les utilisateurs et appareils que vous avez vérifiés</translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation>EN CACHE</translation> </message> @@ -1736,7 +1818,7 @@ Cela met l'application en évidence dans la barre des tâches.</translation <translation>PAS DANS LE CACHE</translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>Facteur d'échelle</translation> </message> @@ -1811,7 +1893,7 @@ Cela met l'application en évidence dans la barre des tâches.</translation <translation>Empreinte de l'appareil</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Clés de session</translation> </message> @@ -1831,17 +1913,17 @@ Cela met l'application en évidence dans la barre des tâches.</translation <translation>CHIFFREMENT</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>GÉNÉRAL</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation>INTERFACE</translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation>Mode écran tactile</translation> </message> @@ -1911,7 +1993,7 @@ Cela met l'application en évidence dans la barre des tâches.</translation <translation>Tous les types de fichiers (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>Ouvrir fichier de sessions</translation> </message> @@ -2007,7 +2089,7 @@ Cela met l'application en évidence dans la barre des tâches.</translation <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>Hier</translation> </message> diff --git a/resources/langs/nheko_hu.ts b/resources/langs/nheko_hu.ts index acf5865f5a53f600e9aa94671170d228c94c1ba9..fc9eaef1d79ef178a87e4ae3e6ae5615ca64d849 100644 --- a/resources/langs/nheko_hu.ts +++ b/resources/langs/nheko_hu.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Csatlakoztál ehhez a szobához.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Nem sikerült meghÃvni a felhasználót: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>A felhasználó meg lett hÃvva: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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>-- TitkosÃtott esemény (Nem találhatók kulcsok a titkosÃtás feloldásához) --</translation> @@ -568,7 +568,7 @@ <translation>Minden fájl (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation>Nem sikerült feltölteni a médiafájlt. Kérlek, próbáld újra!</translation> </message> @@ -801,12 +801,12 @@ Példa: https://szerver.em:8787</translation> <translation>Ãrj egy üzenetet…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation>Hangulatjelek</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation>Küldés</translation> </message> @@ -1003,15 +1003,20 @@ Példa: https://szerver.em:8787</translation> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Bezárás</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation>Szerkesztés megszakÃtása</translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>nincs tárolva verzió</translation> </message> @@ -1153,7 +1158,7 @@ Példa: https://szerver.em:8787</translation> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Az üzenet visszavonása nem sikerült: %1</translation> </message> @@ -1302,12 +1307,12 @@ Példa: https://szerver.em:8787</translation> <translation>%1 visszavonta a kopogását.</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>Csatlakoztál ehhez a szobához.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>Kopogás elutasÃtva tÅ‘le: %1.</translation> </message> @@ -1331,7 +1336,17 @@ Példa: https://szerver.em:8787</translation> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation>Szerkesztés</translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation>Szerkesztve</translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation>Reakció</translation> </message> @@ -1349,7 +1364,7 @@ Példa: https://szerver.em:8787</translation> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation>Reakció</translation> </message> @@ -1358,6 +1373,11 @@ Példa: https://szerver.em:8787</translation> <source>Reply</source> <translation>Válasz</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation>Szerkesztés</translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1482,7 +1502,12 @@ Példa: https://szerver.em:8787</translation> <translation>Ãllapot:</translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation>Felhasználói profil beállÃtásai</translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation>ElérhetÅ‘ség megadása automatikusan</translation> </message> @@ -1505,7 +1530,7 @@ Példa: https://szerver.em:8787</translation> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation>HitelesÃtés</translation> </message> @@ -1524,11 +1549,40 @@ Példa: https://szerver.em:8787</translation> <source>Kick the user</source> <translation>A felhasználó kirúgása</translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation>Profilkép kiválasztása</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation>Minden fájl (*)</translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation>A kiválasztott fájl nem egy kép</translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation>Hiba a fájl olvasása közben: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation>Alapértelmezett</translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>KicsinyÃtés a tálcára</translation> </message> @@ -1548,12 +1602,17 @@ Példa: https://szerver.em:8787</translation> <translation>KerekÃtett profilképek</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation>profil: %1</translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation>Alapértelmezett</translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation>HÃVÃSOK</translation> </message> @@ -1608,6 +1667,33 @@ Csak a titkosÃtott csevegések üzeneteire vonatkozik.</translation> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation>IdÅ‘vonal automatikus kitakarása</translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation>Amikor az ablak elveszÃti a fókuszt, +az idÅ‘vonal homályosÃtva lesz.</translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation>IdÅ‘vonal kitakarása ennyi idÅ‘ után (másodpercben, 0 és 3600 között)</translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation>Add meg, hány másodperc elteltével homályosuljon el az idÅ‘vonal, +miután az ablak elveszÃti a fókuszt! +Ha azonnal el legyen homályosÃtva fókuszvesztéskor, állÃtsd +0-ra! A maximális érték 1 óra (3600 másodperc).</translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation>Gombok mutatása az idÅ‘vonalban</translation> </message> @@ -1724,7 +1810,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <translation>Kulcsok megosztása hitelesÃtett felhasználókkal és eszközökkel</translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation>GYORSÃTÓTÃRAZVA</translation> </message> @@ -1734,7 +1820,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <translation>NINCS GYORSÃTÓTÃRAZVA</translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>NagyÃtási tényezÅ‘</translation> </message> @@ -1809,7 +1895,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <translation>Eszközujjlenyomat</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Munkamenetkulcsok</translation> </message> @@ -1829,17 +1915,17 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <translation>TITKOSÃTÃS</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>ÃLTALÃNOS</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation>FELÃœLET</translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation>ÉrintÅ‘ képernyÅ‘s mód</translation> </message> @@ -1881,22 +1967,22 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location line="+3"/> <source>Self signing key</source> - <translation type="unfinished"></translation> + <translation>ÖnaláÃrókulcs</translation> </message> <message> <location line="+2"/> <source>The key to verify your own devices. If it is cached, verifying one of your devices will mark it verified for all your other devices and for users, that have verified you.</source> - <translation type="unfinished"></translation> + <translation>A kulcs, amellyel hitelesÃtheted a saját eszközeidet. Ha gyorsÃtótárazva van, egy eszköz hitelesÃtése azt hitelesÃtettnek fogja megjelölni az összes többi eszközeidnek és azoknak a felhasználóidnak, akik már hitelesÃtettek téged.</translation> </message> <message> <location line="+3"/> <source>Backup key</source> - <translation type="unfinished"></translation> + <translation>Biztonsági mentési kulcs</translation> </message> <message> <location line="+2"/> <source>The key to decrypt online key backups. If it is cached, you can enable online key backup to store encryption keys securely encrypted on the server.</source> - <translation type="unfinished"></translation> + <translation>A kulcs, amellyel hozzáférhetsz a kulcsok online biztonsági mentéseihez. Ha gyorsÃtótárazva van, lehetÅ‘séged van biztonsági másolatként, titkosÃtva a szerveren tárolni a titkosÃtási kulcsokat.</translation> </message> <message> <location line="+54"/> @@ -1909,9 +1995,9 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <translation>Minden fájl (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> - <translation type="unfinished"></translation> + <translation>Munkameneti fájl megnyitása</translation> </message> <message> <location line="+4"/> @@ -1921,34 +2007,34 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <location line="+11"/> <location line="+18"/> <source>Error</source> - <translation type="unfinished"></translation> + <translation>Hiba</translation> </message> <message> <location line="-66"/> <location line="+28"/> <source>File Password</source> - <translation type="unfinished"></translation> + <translation>Fájljelszó</translation> </message> <message> <location line="-27"/> <source>Enter the passphrase to decrypt the file:</source> - <translation type="unfinished"></translation> + <translation>Ãrd be a jelmondatot a fájl titkosÃtásának feloldásához:</translation> </message> <message> <location line="+8"/> <location line="+28"/> <source>The password cannot be empty</source> - <translation type="unfinished"></translation> + <translation>A jelszó nem lehet üres</translation> </message> <message> <location line="-8"/> <source>Enter passphrase to encrypt your session keys:</source> - <translation type="unfinished"></translation> + <translation>Ãrd be a jelmondatot a munkameneti kulcsok titkosÃtásához:</translation> </message> <message> <location line="+15"/> <source>File to save the exported session keys</source> - <translation type="unfinished"></translation> + <translation>Exportált munkameneti kulcsok mentése fájlba</translation> </message> </context> <context> @@ -1956,17 +2042,17 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location filename="../qml/device-verification/Waiting.qml" line="+7"/> <source>Waiting for other party…</source> - <translation type="unfinished"></translation> + <translation>Várakozás a másik félre…</translation> </message> <message> <location line="+15"/> <source>Waiting for other side to accept the verification request.</source> - <translation type="unfinished"></translation> + <translation>Várakozás a másik oldalra, hogy elfogadja a hitelesÃtési kérelmet.</translation> </message> <message> <location line="+2"/> <source>Waiting for other side to continue the verification process.</source> - <translation type="unfinished"></translation> + <translation>Várakozás a másik oldalra a hitelesÃtés folytatásához.</translation> </message> <message> <location line="+2"/> @@ -1984,12 +2070,12 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location filename="../../src/WelcomePage.cpp" line="+46"/> <source>Welcome to nheko! The desktop client for the Matrix protocol.</source> - <translation type="unfinished"></translation> + <translation>Ãœdvözöl a Nheko, egy asztali kliens a Matrix protokollhoz!</translation> </message> <message> <location line="+1"/> <source>Enjoy your stay!</source> - <translation type="unfinished"></translation> + <translation>Érezd jól magad nálunk!</translation> </message> <message> <location line="+23"/> @@ -2005,9 +2091,9 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> - <translation type="unfinished"></translation> + <translation>Tegnap</translation> </message> </context> <context> @@ -2015,7 +2101,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location filename="../../src/dialogs/CreateRoom.cpp" line="+36"/> <source>Create room</source> - <translation type="unfinished"></translation> + <translation>Szoba létrehozása</translation> </message> <message> <location line="+2"/> @@ -2035,22 +2121,22 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location line="+3"/> <source>Alias</source> - <translation type="unfinished"></translation> + <translation>Ãlnév</translation> </message> <message> <location line="+8"/> <source>Room Visibility</source> - <translation type="unfinished"></translation> + <translation>Szoba láthatósága</translation> </message> <message> <location line="+8"/> <source>Room Preset</source> - <translation type="unfinished"></translation> + <translation>Szoba jellege</translation> </message> <message> <location line="+9"/> <source>Direct Chat</source> - <translation type="unfinished"></translation> + <translation>Közvetlen csevegés</translation> </message> </context> <context> @@ -2058,7 +2144,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location filename="../../src/dialogs/FallbackAuth.cpp" line="+30"/> <source>Open Fallback in Browser</source> - <translation type="unfinished"></translation> + <translation>Fallback megnyitása böngészÅ‘ben</translation> </message> <message> <location line="+1"/> @@ -2068,12 +2154,12 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location line="+1"/> <source>Confirm</source> - <translation type="unfinished"></translation> + <translation>MegerÅ‘sÃtés</translation> </message> <message> <location line="+12"/> <source>Open the fallback, follow the steps and confirm after completing them.</source> - <translation type="unfinished"></translation> + <translation>Nyisd meg a fallback-ket, kövesd az utasÃtásokat, és erÅ‘sÃtsd meg, ha végeztél velük!</translation> </message> </context> <context> @@ -2086,7 +2172,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location line="+8"/> <source>User ID to invite</source> - <translation type="unfinished"></translation> + <translation>MeghÃvandó felhasználó azonosÃtója</translation> </message> </context> <context> @@ -2094,7 +2180,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location filename="../../src/dialogs/JoinRoom.cpp" line="+30"/> <source>Join</source> - <translation type="unfinished"></translation> + <translation>Csatlakozás</translation> </message> <message> <location line="+2"/> @@ -2104,7 +2190,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location line="+7"/> <source>Room ID or alias</source> - <translation type="unfinished"></translation> + <translation>Szoba azonosÃtója vagy álneve</translation> </message> </context> <context> @@ -2117,7 +2203,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location line="+8"/> <source>Are you sure you want to leave?</source> - <translation type="unfinished"></translation> + <translation>Biztosan távozni akarsz?</translation> </message> </context> <context> @@ -2130,7 +2216,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location line="+8"/> <source>Logout. Are you sure?</source> - <translation type="unfinished"></translation> + <translation>Biztosan kijelentkezel?</translation> </message> </context> <context> @@ -2138,7 +2224,7 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <message> <location filename="../../src/dialogs/PreviewUploadOverlay.cpp" line="+41"/> <source>Upload</source> - <translation type="unfinished"></translation> + <translation>Feltöltés</translation> </message> <message> <location line="+1"/> @@ -2150,7 +2236,9 @@ EttÅ‘l általában animálttá válik az alkalmazásablakok listáján szereplÅ‘ <source>Media type: %1 Media size: %2 </source> - <translation type="unfinished"></translation> + <translation>Média tÃpusa: %1 +Média mérete: %2 +</translation> </message> </context> <context> @@ -2163,12 +2251,12 @@ Media size: %2 <message> <location line="+1"/> <source>Confirm</source> - <translation type="unfinished"></translation> + <translation>MegerÅ‘sÃtés</translation> </message> <message> <location line="+11"/> <source>Solve the reCAPTCHA and press the confirm button</source> - <translation type="unfinished"></translation> + <translation>Oldd meg a reCAPTCHA feladványát, és nyomd meg a „MegerÅ‘sÃtés†gombot</translation> </message> </context> <context> @@ -2189,12 +2277,12 @@ Media size: %2 <message> <location line="-46"/> <source>Today %1</source> - <translation type="unfinished"></translation> + <translation>Ma %1</translation> </message> <message> <location line="+3"/> <source>Yesterday %1</source> - <translation type="unfinished"></translation> + <translation>Tegnap %1</translation> </message> </context> <context> @@ -2207,101 +2295,102 @@ Media size: %2 <message> <location line="+3"/> <source>Info</source> - <translation type="unfinished"></translation> + <translation>Infó</translation> </message> <message> <location line="+11"/> <source>Internal ID</source> - <translation type="unfinished"></translation> + <translation>BelsÅ‘ azonosÃtó</translation> </message> <message> <location line="+10"/> <source>Room Version</source> - <translation type="unfinished"></translation> + <translation>Szoba verziója</translation> </message> <message> <location line="+4"/> <source>Notifications</source> - <translation type="unfinished"></translation> + <translation>ÉrtesÃtések</translation> </message> <message> <location line="+2"/> <source>Muted</source> - <translation type="unfinished"></translation> + <translation>NémÃtva</translation> </message> <message> <location line="+2"/> <source>Mentions only</source> - <translation type="unfinished"></translation> + <translation>Csak megemlÃtéskor</translation> </message> <message> <location line="+1"/> <source>All messages</source> - <translation type="unfinished"></translation> + <translation>Mindegyik üzenetnél</translation> </message> <message> <location line="+97"/> <source>Room access</source> - <translation type="unfinished"></translation> + <translation>Szoba hozzáférhetÅ‘sége</translation> </message> <message> <location line="+2"/> <source>Anyone and guests</source> - <translation type="unfinished"></translation> + <translation>Bárkinek és vendégeknek</translation> </message> <message> <location line="+1"/> <source>Anyone</source> - <translation type="unfinished"></translation> + <translation>Bárkinek, aki ismeri a szoba linkjét (vendégek nem)</translation> </message> <message> <location line="+1"/> <source>Invited users</source> - <translation type="unfinished"></translation> + <translation>MeghÃvott felhasználók</translation> </message> <message> <location line="+50"/> <source>Encryption</source> - <translation type="unfinished"></translation> + <translation>TitkosÃtás</translation> </message> <message> <location line="+11"/> <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> + <translation>Válaszoljon-e kérés esetén a kliens munkamenetkulcsokkal automatikusan. Óvatosan használandó, mivel ez csak egy átmeneti megoldás a végponttól végpontig (E2E) titkosÃtás teszteléséhez, amÃg be nincs fejezve az eszközhitelesÃtés.</translation> </message> <message> <location line="+20"/> <source>End-to-End Encryption</source> - <translation type="unfinished"></translation> + <translation>Végponttól végpontig titkosÃtás</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> + <translation>A titkosÃtás jelenleg kÃsérleti stádiumú és váratlan furcsaságok történhetnek. <br# Kérlek, vedd vigyelembe, hogy ha egyszer aktiváltad, nem lehet utána kikapcsolni.</translation> </message> <message> <location line="-24"/> <source>Respond to key requests</source> - <translation type="unfinished"></translation> + <translation>Válasz kulcskérelmekre</translation> </message> <message numerus="yes"> <location line="+83"/> <source>%n member(s)</source> - <translation type="unfinished"> - <numerusform></numerusform> + <translation> + <numerusform>%n tag</numerusform> + <numerusform>%n tag</numerusform> </translation> </message> <message> <location line="+142"/> <source>Failed to enable encryption: %1</source> - <translation type="unfinished"></translation> + <translation>Nem sikerült a titkosÃtás aktiválása: %1</translation> </message> <message> <location line="+147"/> <source>Select an avatar</source> - <translation type="unfinished"></translation> + <translation>Profilkép kiválasztása</translation> </message> <message> <location line="+0"/> @@ -2311,18 +2400,18 @@ Media size: %2 <message> <location line="+12"/> <source>The selected file is not an image</source> - <translation type="unfinished"></translation> + <translation>A kiválasztott fájl nem egy kép</translation> </message> <message> <location line="+5"/> <source>Error while reading file: %1</source> - <translation type="unfinished"></translation> + <translation>Hiba a fájl olvasása közben: %1</translation> </message> <message> <location line="+35"/> <location line="+20"/> <source>Failed to upload image: %s</source> - <translation type="unfinished"></translation> + <translation>Nem sikerült a kép feltöltése: %s</translation> </message> </context> <context> diff --git a/resources/langs/nheko_it.ts b/resources/langs/nheko_it.ts index e05cea700333d2f4a19b2968dc9ee74c233433b1..2c01a1bbf1dc46db082bbd9eba75d8d2d72024ca 100644 --- a/resources/langs/nheko_it.ts +++ b/resources/langs/nheko_it.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Sei entrato in questa stanza.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Impossibile invitare l'utente: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>Invitato utente: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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">-- Evento Criptato (Chiavi per la decriptazione non trovate) --</translation> @@ -568,7 +568,7 @@ <translation type="unfinished">Tutti i File (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished">Impossibile inviare il file multimediale. Per favore riprova.</translation> </message> @@ -801,12 +801,12 @@ Esempio: https://server.mio:8787</translation> <translation type="unfinished">Scrivi un messaggio…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished">Emoji</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -1003,15 +1003,20 @@ Esempio: https://server.mio:8787</translation> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Chiudi</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>nessuna versione memorizzata</translation> </message> @@ -1153,7 +1158,7 @@ Esempio: https://server.mio:8787</translation> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Oscuramento del messaggio fallito: %1</translation> </message> @@ -1303,12 +1308,12 @@ Esempio: https://server.mio:8787</translation> <translation>%1 ha oscurato la sua bussata.</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>Sei entrato in questa stanza.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>Rifiutata la bussata di %1.</translation> </message> @@ -1332,7 +1337,17 @@ Esempio: https://server.mio:8787</translation> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1350,7 +1365,7 @@ Esempio: https://server.mio:8787</translation> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1359,6 +1374,11 @@ Esempio: https://server.mio:8787</translation> <source>Reply</source> <translation>Risposta</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1483,7 +1503,12 @@ Esempio: https://server.mio:8787</translation> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1506,7 +1531,7 @@ Esempio: https://server.mio:8787</translation> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1525,11 +1550,40 @@ Esempio: https://server.mio:8787</translation> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation type="unfinished">Scegli un avatar</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished">Tutti i File (*)</translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation type="unfinished">Il file selezionato non è un'immagine</translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation type="unfinished">Errore durante la lettura del file: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Minimizza nella tray</translation> </message> @@ -1549,12 +1603,17 @@ Esempio: https://server.mio:8787</translation> <translation>Avatar Circolari</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1607,6 +1666,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation>Mostra pulsanti nella timeline</translation> </message> @@ -1717,7 +1799,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1727,7 +1809,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>Fattore di scala</translation> </message> @@ -1802,7 +1884,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>Impronta digitale del dispositivo</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Chiavi di Sessione</translation> </message> @@ -1822,17 +1904,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation>CRITTOGRAFIA</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>GENERALE</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation>INTERFACCIA</translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1902,7 +1984,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished">Tutti i File (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>Apri File delle Sessioni</translation> </message> @@ -1998,7 +2080,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>Ieri</translation> </message> diff --git a/resources/langs/nheko_ja.ts b/resources/langs/nheko_ja.ts index 47cb27b81398a0ef9b99168942302b0f25e1f999..18e18c207832317746ce5f6dd8976a9aae04d5e3 100644 --- a/resources/langs/nheko_ja.ts +++ b/resources/langs/nheko_ja.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>ユーザーを招待ã§ãã¾ã›ã‚“ã§ã—ãŸ: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>招待ã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation type="unfinished">å…¨ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ« (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished">メディアをアップãƒãƒ¼ãƒ‰ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã‚„ã‚Šç›´ã—ã¦ä¸‹ã•ã„。</translation> </message> @@ -797,12 +797,12 @@ Example: https://server.my:8787</source> <translation type="unfinished">メッセージを書ã...</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished">絵文å—</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -999,15 +999,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished">é–‰ã˜ã‚‹</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒä¿å˜ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation> </message> @@ -1149,7 +1154,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>メッセージを編集ã§ãã¾ã›ã‚“ã§ã—ãŸ: %1</translation> </message> @@ -1298,12 +1303,12 @@ Example: https://server.my:8787</source> <translation>%1ãŒãƒŽãƒƒã‚¯ã‚’編集ã—ã¾ã—ãŸã€‚</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>%1ã‹ã‚‰ã®ãƒŽãƒƒã‚¯ã‚’æ‹’å¦ã—ã¾ã—ãŸã€‚</translation> </message> @@ -1327,7 +1332,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1345,7 +1360,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1354,6 +1369,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished">返信</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1478,7 +1498,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1501,7 +1526,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1520,11 +1545,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <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">ファイルã®èªã¿è¾¼ã¿æ™‚ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>トレイã¸æœ€å°åŒ–</translation> </message> @@ -1544,12 +1598,17 @@ Example: https://server.my:8787</source> <translation>円形アãƒã‚¿ãƒ¼</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1602,6 +1661,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1712,7 +1794,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1722,7 +1804,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>尺度係数</translation> </message> @@ -1797,7 +1879,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>デãƒã‚¤ã‚¹ã®æŒ‡ç´‹</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>セッションéµ</translation> </message> @@ -1817,17 +1899,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation>æš—å·åŒ–</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>全般</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1897,7 +1979,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished">å…¨ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ« (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>セッションファイルを開ã</translation> </message> @@ -1993,7 +2075,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>昨日</translation> </message> diff --git a/resources/langs/nheko_ml.ts b/resources/langs/nheko_ml.ts index fcceacab6b64ec2c7a488824d0e85b79320fd407..9905ff35c2a97600569e336b9f97626fba84db72 100644 --- a/resources/langs/nheko_ml.ts +++ b/resources/langs/nheko_ml.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>നിങàµà´™àµ¾ à´ˆ à´®àµà´±à´¿à´¯à´¿àµ½ ചേർനàµà´¨àµ.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>ഉപയോകàµà´¤à´¾à´µà´¿à´¨àµ† à´•àµà´·à´£à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿àµ½ പരാജയപàµà´ªàµ†à´Ÿàµà´Ÿàµ: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>à´•àµà´·à´£à´¿à´šàµà´š ഉപയോകàµà´¤à´¾à´µàµ:% 1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -797,12 +797,12 @@ Example: https://server.my:8787</source> <translation>ഒരൠസനàµà´¦àµ‡à´¶à´‚ à´Žà´´àµà´¤àµà´•â€¦.</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation>ഇമോജി</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation>അയകàµà´•àµà´•</translation> </message> @@ -999,15 +999,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished">à´…à´Ÿà´¯àµâ€Œà´•àµà´•àµà´•</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation type="unfinished"></translation> </message> @@ -1149,7 +1154,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation type="unfinished"></translation> </message> @@ -1299,12 +1304,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished">നിങàµà´™àµ¾ à´ˆ à´®àµà´±à´¿à´¯à´¿àµ½ ചേർനàµà´¨àµ.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1328,7 +1333,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1346,7 +1361,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1355,6 +1370,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1479,7 +1499,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1502,7 +1527,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1521,11 +1546,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <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> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation type="unfinished"></translation> </message> @@ -1545,12 +1599,17 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1603,6 +1662,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1713,7 +1795,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1723,7 +1805,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation type="unfinished"></translation> </message> @@ -1798,7 +1880,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation type="unfinished"></translation> </message> @@ -1818,17 +1900,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation type="unfinished"></translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1898,7 +1980,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation type="unfinished"></translation> </message> @@ -1994,7 +2076,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation type="unfinished"></translation> </message> diff --git a/resources/langs/nheko_nl.ts b/resources/langs/nheko_nl.ts index d4f6e5f06e0c55f240a1b3fb182f30def5fb5daa..520f0f170d2dcdb7aabb34c81f026691d9b9b0d5 100644 --- a/resources/langs/nheko_nl.ts +++ b/resources/langs/nheko_nl.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Je bent lid geworden van deze kamer.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Gebruiker uitnodigen mislukt: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>Gebruiker uitgenodigd: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation type="unfinished">Alle bestanden (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -797,12 +797,12 @@ Example: https://server.my:8787</source> <translation type="unfinished">Typ een bericht...</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -999,15 +999,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation type="unfinished"></translation> </message> @@ -1149,7 +1154,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation type="unfinished"></translation> </message> @@ -1299,12 +1304,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished">Je bent lid geworden van deze kamer.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1328,7 +1333,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1346,7 +1361,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1355,6 +1370,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1479,7 +1499,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1502,7 +1527,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1521,11 +1546,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished">Alle bestanden (*)</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> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Minimaliseren naar systeemvak</translation> </message> @@ -1545,12 +1599,17 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1603,6 +1662,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1713,7 +1795,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1723,7 +1805,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation type="unfinished"></translation> </message> @@ -1798,7 +1880,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation type="unfinished"></translation> </message> @@ -1818,17 +1900,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>ALGEMEEN</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1898,7 +1980,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished">Alle bestanden (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation type="unfinished"></translation> </message> @@ -1994,7 +2076,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation type="unfinished"></translation> </message> diff --git a/resources/langs/nheko_pl.ts b/resources/langs/nheko_pl.ts index b0f83014f0660951ff30b364734c700c449bc9db..534689035cfc48fe399f7bad64fbcd0a0ebef798 100644 --- a/resources/langs/nheko_pl.ts +++ b/resources/langs/nheko_pl.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>DoÅ‚Ä…czyÅ‚eÅ›(-Å‚aÅ›) do tego pokoju.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Nie udaÅ‚o siÄ™ zaprosić użytkownika: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation type="unfinished"></translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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>-- Zdarzenie szyfrowania (Nie znaleziono kluczy deszyfrujÄ…cych)</translation> @@ -568,7 +568,7 @@ <translation type="unfinished">Wszystkie pliki (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -799,12 +799,12 @@ Example: https://server.my:8787</source> <translation type="unfinished">Napisz wiadomość…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished">Emoji</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -1001,15 +1001,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Zamknij</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation type="unfinished"></translation> </message> @@ -1151,7 +1156,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation type="unfinished">Redagowanie wiadomoÅ›ci nie powiodÅ‚o siÄ™: %1</translation> </message> @@ -1302,12 +1307,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished">DoÅ‚Ä…czyÅ‚eÅ›(-Å‚aÅ›) do tego pokoju.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1331,7 +1336,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1349,7 +1364,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1358,6 +1373,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1482,7 +1502,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1505,7 +1530,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1524,11 +1549,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation type="unfinished">Wybierz awatar</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished">Wszystkie pliki (*)</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> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Zminimalizuj do paska zadaÅ„</translation> </message> @@ -1548,12 +1602,17 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1606,6 +1665,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1716,7 +1798,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1726,7 +1808,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation type="unfinished"></translation> </message> @@ -1801,7 +1883,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>Odcisk palca urzÄ…dzenia</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation type="unfinished"></translation> </message> @@ -1821,17 +1903,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation>SZYFROWANIE</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>OGÓLNE</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1901,7 +1983,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished">Wszystkie pliki (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation type="unfinished"></translation> </message> @@ -1997,7 +2079,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation type="unfinished"></translation> </message> diff --git a/resources/langs/nheko_pt_PT.ts b/resources/langs/nheko_pt_PT.ts index 31be9ea9321287849563de0aa046bc1605f52b6f..caa970b5e99ce6567622f612ac708e65951f213f 100644 --- a/resources/langs/nheko_pt_PT.ts +++ b/resources/langs/nheko_pt_PT.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation type="unfinished"></translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation type="unfinished"></translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -797,12 +797,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -999,15 +999,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation type="unfinished"></translation> </message> @@ -1149,7 +1154,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation type="unfinished"></translation> </message> @@ -1299,12 +1304,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1328,7 +1333,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1346,7 +1361,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1355,6 +1370,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1479,7 +1499,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1502,7 +1527,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1521,11 +1546,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <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> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation type="unfinished"></translation> </message> @@ -1545,12 +1599,17 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1603,6 +1662,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1713,7 +1795,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1723,7 +1805,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation type="unfinished"></translation> </message> @@ -1798,7 +1880,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation type="unfinished"></translation> </message> @@ -1818,17 +1900,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation type="unfinished"></translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1898,7 +1980,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation type="unfinished"></translation> </message> @@ -1994,7 +2076,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation type="unfinished"></translation> </message> diff --git a/resources/langs/nheko_ro.ts b/resources/langs/nheko_ro.ts index 7b36ea59e791fc95958ba060cfed12eda2b698ad..662377f5f17ac97cecaad2272dfb75aaa0857041 100644 --- a/resources/langs/nheko_ro.ts +++ b/resources/langs/nheko_ro.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Te-ai alăturat camerei.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Nu s-a putut invita utilizatorul: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>Utilizator invitat: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation type="unfinished">Toate fiÈ™ierele (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -801,12 +801,12 @@ Exemplu: https://serverul.meu:8787</translation> <translation type="unfinished"></translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -1003,15 +1003,20 @@ Exemplu: https://serverul.meu:8787</translation> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished">ÃŽnchide</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>nicio versiune stocată</translation> </message> @@ -1153,7 +1158,7 @@ Exemplu: https://serverul.meu:8787</translation> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Redactare mesaj eÈ™uată: %1</translation> </message> @@ -1304,12 +1309,12 @@ Exemplu: https://serverul.meu:8787</translation> <translation>%1 È™i-a redactat ciocănitul.</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>Te-ai alăturat camerei.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>Ciocănit refuzat de la %1.</translation> </message> @@ -1333,7 +1338,17 @@ Exemplu: https://serverul.meu:8787</translation> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1351,7 +1366,7 @@ Exemplu: https://serverul.meu:8787</translation> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1360,6 +1375,11 @@ Exemplu: https://serverul.meu:8787</translation> <source>Reply</source> <translation>Răspuns</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1484,7 +1504,12 @@ Exemplu: https://serverul.meu:8787</translation> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1507,7 +1532,7 @@ Exemplu: https://serverul.meu:8787</translation> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1526,11 +1551,40 @@ Exemplu: https://serverul.meu:8787</translation> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation type="unfinished">Selectează un avatar</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished">Toate fiÈ™ierele (*)</translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation type="unfinished">FiÈ™ierul selectat nu este imagine</translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation type="unfinished">Eroare întâmpinată la citirea fiÈ™ierului: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Minimizează în bara de notificări</translation> </message> @@ -1550,12 +1604,17 @@ Exemplu: https://serverul.meu:8787</translation> <translation>Avatare rotunde</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1608,6 +1667,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation>Arată butoanele în cronologie</translation> </message> @@ -1718,7 +1800,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1728,7 +1810,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>Factor de dimensiune</translation> </message> @@ -1803,7 +1885,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>Amprentă Dispozitiv</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Chei de sesiune</translation> </message> @@ -1823,17 +1905,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation>CRIPTARE</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>GENERAL</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation>INTERFAȚĂ</translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1903,7 +1985,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished">Toate fiÈ™ierele (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>Deschide fiÈ™ierul de sesiuni</translation> </message> @@ -1999,7 +2081,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>Ieri</translation> </message> diff --git a/resources/langs/nheko_ru.ts b/resources/langs/nheko_ru.ts index 21b31b3335f4665e6138b21a7c25ccfa455a2d21..112e8c8c698fd3668aadf73a19e51016a493cd7c 100644 --- a/resources/langs/nheko_ru.ts +++ b/resources/langs/nheko_ru.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Ð’Ñ‹ приÑоединилиÑÑŒ к Ñтой комнате.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Ðе удалоÑÑŒ приглаÑить пользователÑ: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>Приглашенный пользователь: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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>-- Зашифрованное Ñобытие (Ðет найдено ключей Ð´Ð»Ñ Ð´ÐµÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ) --</translation> @@ -568,7 +568,7 @@ <translation>Ð’Ñе файлы (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation>Ðе удалоÑÑŒ загрузить медиа. ПожалуйÑта попробуйте ещё раз</translation> </message> @@ -801,12 +801,12 @@ Example: https://server.my:8787</source> <translation>ÐапиÑать Ñообщение…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation>Ðмоджи</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation>Отправить</translation> </message> @@ -1003,15 +1003,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Закрыть</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>нет Ñохраненной верÑии</translation> </message> @@ -1153,7 +1158,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Ошибка Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ÑообщениÑ: %1</translation> </message> @@ -1304,12 +1309,12 @@ Example: https://server.my:8787</source> <translation>%1 отредактировал его "Ñтук".</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>Ð’Ñ‹ приÑоединилиÑÑŒ к Ñтой комнате.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>Отверг "Ñтук" от %1</translation> </message> @@ -1333,7 +1338,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation>Отреагировать</translation> </message> @@ -1351,7 +1366,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation>Отреагировать</translation> </message> @@ -1360,6 +1375,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation>Ответить</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1484,7 +1504,12 @@ Example: https://server.my:8787</source> <translation>СтатуÑ: </translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation>УÑтановить 'presence'автоматичеÑки</translation> </message> @@ -1507,7 +1532,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation>Верифицировать</translation> </message> @@ -1526,11 +1551,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation>Выгнать пользователÑ</translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <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">Ошибка во Ð²Ñ€ÐµÐ¼Ñ Ð¿Ñ€Ð¾Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Сворачивать в ÑиÑтемную панель</translation> </message> @@ -1550,12 +1604,17 @@ Example: https://server.my:8787</source> <translation>Округлый Ðватар</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation>профиль: %1</translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation>ЗВОÐКИ</translation> </message> @@ -1608,6 +1667,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation>Отображать кнопки в таймлайне</translation> </message> @@ -1723,7 +1805,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>ДелитьÑÑ ÐºÐ»ÑŽÑ‡Ð°Ð¼Ð¸ Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐµÐ½Ð½Ñ‹Ð¼Ð¸ учаÑтниками и уÑтройÑтвами</translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1733,7 +1815,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>МаÑштаб</translation> </message> @@ -1808,7 +1890,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>Отпечаток уÑтройÑтва</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Ключи ÑеанÑа</translation> </message> @@ -1828,17 +1910,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation>ШИФРОВÐÐИЕ</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>ГЛÐÐ’ÐОЕ</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation>ИÐТЕРФЕЙС</translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation>СенÑорный режим</translation> </message> @@ -1908,7 +1990,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>Ð’Ñе файлы (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>Открыть файл ÑеанÑов</translation> </message> @@ -2005,7 +2087,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>Вчера</translation> </message> diff --git a/resources/langs/nheko_si.ts b/resources/langs/nheko_si.ts index 6366b35ac802bdc51f9d1e00be9a237ed42ea293..d665081c8a51d93cb0d77e9d1276422f57673e4f 100644 --- a/resources/langs/nheko_si.ts +++ b/resources/langs/nheko_si.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation type="unfinished"></translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation type="unfinished"></translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -797,12 +797,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -999,15 +999,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation type="unfinished"></translation> </message> @@ -1149,7 +1154,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation type="unfinished"></translation> </message> @@ -1299,12 +1304,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1328,7 +1333,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1346,7 +1361,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1355,6 +1370,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1479,7 +1499,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1502,7 +1527,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1521,11 +1546,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <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> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation type="unfinished"></translation> </message> @@ -1545,12 +1599,17 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1603,6 +1662,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1713,7 +1795,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1723,7 +1805,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation type="unfinished"></translation> </message> @@ -1798,7 +1880,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation type="unfinished"></translation> </message> @@ -1818,17 +1900,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation type="unfinished"></translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1898,7 +1980,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation type="unfinished"></translation> </message> @@ -1994,7 +2076,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation type="unfinished"></translation> </message> diff --git a/resources/langs/nheko_sv.ts b/resources/langs/nheko_sv.ts index 18266ad4b3fe59f79fe4b69b8a3f8d074caf2ead..49a825aadcbd3e7d507efe567c84e1ee5449d13e 100644 --- a/resources/langs/nheko_sv.ts +++ b/resources/langs/nheko_sv.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>Du gick med i detta rum.</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>Kunde inte bjuda in användare: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>Bjöd in användare: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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>-- Krypterat Event (Inga nycklar kunde hittas för dekryptering) --</translation> @@ -568,7 +568,7 @@ <translation>Alla Filer (*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation>Kunde inte ladda upp media. Vänligen försök igen.</translation> </message> @@ -801,12 +801,12 @@ Exempel: https://server.my:8787</translation> <translation>Skriv ett meddelande…</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation>Emoji</translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation>Skicka</translation> </message> @@ -1003,15 +1003,20 @@ Exempel: https://server.my:8787</translation> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation>Stäng</translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation>ingen version lagrad</translation> </message> @@ -1153,7 +1158,7 @@ Exempel: https://server.my:8787</translation> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation>Kunde inte maskera meddelande: %1</translation> </message> @@ -1303,12 +1308,12 @@ Exempel: https://server.my:8787</translation> <translation>%1 maskerade sin knackning.</translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation>Du gick med i detta rum.</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation>Avvisade knackningen frÃ¥n %1.</translation> </message> @@ -1332,7 +1337,17 @@ Exempel: https://server.my:8787</translation> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation>Reagera</translation> </message> @@ -1350,7 +1365,7 @@ Exempel: https://server.my:8787</translation> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation>Reagera</translation> </message> @@ -1359,6 +1374,11 @@ Exempel: https://server.my:8787</translation> <source>Reply</source> <translation>Svara</translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1483,7 +1503,12 @@ Exempel: https://server.my:8787</translation> <translation>Status:</translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation>Sätt närvaro automatiskt</translation> </message> @@ -1506,7 +1531,7 @@ Exempel: https://server.my:8787</translation> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation>Bekräfta</translation> </message> @@ -1525,11 +1550,40 @@ Exempel: https://server.my:8787</translation> <source>Kick the user</source> <translation>Sparka ut användaren</translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <source>Select an avatar</source> + <translation type="unfinished">Välj en avatar</translation> + </message> + <message> + <location line="+0"/> + <source>All Files (*)</source> + <translation type="unfinished">Alla Filer (*)</translation> + </message> + <message> + <location line="+12"/> + <source>The selected file is not an image</source> + <translation type="unfinished">Den valda filen är inte en bild</translation> + </message> + <message> + <location line="+5"/> + <source>Error while reading file: %1</source> + <translation type="unfinished">Kunde inte läsa filen: %1</translation> + </message> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>Minimera till systemtrÃ¥g</translation> </message> @@ -1549,12 +1603,17 @@ Exempel: https://server.my:8787</translation> <translation>Cirkulära avatarer</translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation>profil: %1</translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation>SAMTAL</translation> </message> @@ -1609,6 +1668,29 @@ PÃ¥verkar endast krypterade chattar.</translation> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation>Visa knappar i tidslinje</translation> </message> @@ -1725,7 +1807,7 @@ Detta gör vanligtvis att ikonen i aktivitetsfältet animeras pÃ¥ nÃ¥got sätt.< <translation>Dela nycklar med verifierade användare och enheter</translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation>SPARAD</translation> </message> @@ -1735,7 +1817,7 @@ Detta gör vanligtvis att ikonen i aktivitetsfältet animeras pÃ¥ nÃ¥got sätt.< <translation>EJ SPARAD</translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation>Storleksfaktor</translation> </message> @@ -1810,7 +1892,7 @@ Detta gör vanligtvis att ikonen i aktivitetsfältet animeras pÃ¥ nÃ¥got sätt.< <translation>Enhetsfingeravtryck</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>Sessionsnycklar</translation> </message> @@ -1830,17 +1912,17 @@ Detta gör vanligtvis att ikonen i aktivitetsfältet animeras pÃ¥ nÃ¥got sätt.< <translation>KRYPTERING</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>ALLMÄNT</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation>GRÄNSSNITT</translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation>Touchskärmsläge</translation> </message> @@ -1910,7 +1992,7 @@ Detta gör vanligtvis att ikonen i aktivitetsfältet animeras pÃ¥ nÃ¥got sätt.< <translation>Alla Filer (*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>Öppna sessionsfil</translation> </message> @@ -2006,7 +2088,7 @@ Detta gör vanligtvis att ikonen i aktivitetsfältet animeras pÃ¥ nÃ¥got sätt.< <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation>IgÃ¥r</translation> </message> diff --git a/resources/langs/nheko_zh_CN.ts b/resources/langs/nheko_zh_CN.ts index ce25bcbe1b44a8394c1b80dddacffcf59fa4aa55..b371ce70401c032112468e7c34f1430dfa216177 100644 --- a/resources/langs/nheko_zh_CN.ts +++ b/resources/langs/nheko_zh_CN.ts @@ -51,7 +51,7 @@ <context> <name>Cache</name> <message> - <location filename="../../src/Cache.cpp" line="+1978"/> + <location filename="../../src/Cache.cpp" line="+2084"/> <source>You joined this room.</source> <translation>æ‚¨å·²åŠ å…¥æ¤æˆ¿é—´</translation> </message> @@ -120,13 +120,13 @@ <context> <name>ChatPage</name> <message> - <location filename="../../src/ChatPage.cpp" line="+211"/> + <location filename="../../src/ChatPage.cpp" line="+215"/> <source>Failed to invite user: %1</source> <translation>邀请用户失败: %1</translation> </message> <message> <location line="+4"/> - <location line="+796"/> + <location line="+797"/> <source>Invited user: %1</source> <translation>邀请已å‘é€: %1</translation> </message> @@ -479,7 +479,7 @@ <context> <name>EventStore</name> <message> - <location filename="../../src/timeline/EventStore.cpp" line="+559"/> + <location filename="../../src/timeline/EventStore.cpp" line="+612"/> <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> @@ -568,7 +568,7 @@ <translation type="unfinished">所有文件(*)</translation> </message> <message> - <location line="+340"/> + <location line="+384"/> <source>Failed to upload media. Please try again.</source> <translation type="unfinished"></translation> </message> @@ -797,12 +797,12 @@ Example: https://server.my:8787</source> <translation>写一æ¡æ¶ˆæ¯â€¦</translation> </message> <message> - <location line="+170"/> + <location line="+186"/> <source>Emoji</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Send</source> <translation type="unfinished"></translation> </message> @@ -999,15 +999,20 @@ Example: https://server.my:8787</source> <context> <name>ReplyPopup</name> <message> - <location filename="../qml/ReplyPopup.qml" line="+43"/> + <location filename="../qml/ReplyPopup.qml" line="+45"/> <source>Close</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+13"/> + <source>Cancel edit</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>RoomInfo</name> <message> - <location filename="../../src/Cache.cpp" line="+1868"/> + <location filename="../../src/Cache.cpp" line="+1861"/> <source>no version stored</source> <translation type="unfinished"></translation> </message> @@ -1149,7 +1154,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineModel</name> <message> - <location filename="../../src/timeline/TimelineModel.cpp" line="+860"/> + <location filename="../../src/timeline/TimelineModel.cpp" line="+895"/> <source>Message redaction failed: %1</source> <translation type="unfinished">åˆ é™¤æ¶ˆæ¯å¤±è´¥ï¼š%1</translation> </message> @@ -1298,12 +1303,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-771"/> + <location line="-795"/> <source>You joined this room.</source> <translation type="unfinished">æ‚¨å·²åŠ å…¥æ¤æˆ¿é—´</translation> </message> <message> - <location line="+773"/> + <location line="+797"/> <source>Rejected the knock from %1.</source> <translation type="unfinished"></translation> </message> @@ -1327,7 +1332,17 @@ Example: https://server.my:8787</source> <context> <name>TimelineRow</name> <message> - <location filename="../qml/TimelineRow.qml" line="+97"/> + <location filename="../qml/TimelineRow.qml" line="+99"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+0"/> + <source>Edited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1345,7 +1360,7 @@ Example: https://server.my:8787</source> <context> <name>TimelineView</name> <message> - <location filename="../qml/TimelineView.qml" line="+83"/> + <location filename="../qml/TimelineView.qml" line="+85"/> <source>React</source> <translation type="unfinished"></translation> </message> @@ -1354,6 +1369,11 @@ Example: https://server.my:8787</source> <source>Reply</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+7"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> <message> <location line="+5"/> <source>Read receipts</source> @@ -1478,7 +1498,12 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> + <location line="+8"/> + <source>User Profile Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> <source>Set presence automatically</source> <translation type="unfinished"></translation> </message> @@ -1501,7 +1526,7 @@ Example: https://server.my:8787</source> <context> <name>UserProfile</name> <message> - <location filename="../qml/UserProfile.qml" line="+54"/> + <location filename="../qml/UserProfile.qml" line="+133"/> <source>Verify</source> <translation type="unfinished"></translation> </message> @@ -1520,11 +1545,40 @@ Example: https://server.my:8787</source> <source>Kick the user</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../../src/ui/UserProfile.cpp" line="+296"/> + <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> +</context> +<context> + <name>UserSettings</name> + <message> + <location filename="../../src/UserSettingsPage.cpp" line="+345"/> + <location filename="../../src/UserSettingsPage.h" line="+183"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>UserSettingsPage</name> <message> - <location filename="../../src/UserSettingsPage.cpp" line="+794"/> + <location line="+496"/> <source>Minimize to tray</source> <translation>最å°åŒ–至托盘</translation> </message> @@ -1544,12 +1598,17 @@ Example: https://server.my:8787</source> <translation type="unfinished"></translation> </message> <message> - <location line="-195"/> + <location line="-210"/> <source>profile: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+112"/> + <location line="+96"/> + <source>Default</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+31"/> <source>CALLS</source> <translation type="unfinished"></translation> </message> @@ -1602,6 +1661,29 @@ Only affects messages in encrypted chats.</source> </message> <message> <location line="+2"/> + <source>Privacy Screen</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>When the window loses focus, the timeline will +be blurred.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Privacy screen timeout (in seconds [0 - 3600])</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Set timeout (in seconds) for how long after window loses +focus before the screen will be blurred. +Set to 0 to blur immediately after focus loss. Max value of 1 hour (3600 seconds)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Show buttons in timeline</source> <translation type="unfinished"></translation> </message> @@ -1712,7 +1794,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="+395"/> + <location line="+407"/> <source>CACHED</source> <translation type="unfinished"></translation> </message> @@ -1722,7 +1804,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished"></translation> </message> <message> - <location line="-449"/> + <location line="-461"/> <source>Scale factor</source> <translation type="unfinished"></translation> </message> @@ -1797,7 +1879,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation>设备指纹</translation> </message> <message> - <location line="-155"/> + <location line="-164"/> <source>Session Keys</source> <translation>会è¯å¯†é’¥</translation> </message> @@ -1817,17 +1899,17 @@ This usually causes the application icon in the task bar to animate in some fash <translation>åŠ å¯†</translation> </message> <message> - <location line="-100"/> + <location line="-115"/> <source>GENERAL</source> <translation>通用</translation> </message> <message> - <location line="+57"/> + <location line="+64"/> <source>INTERFACE</source> <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+194"/> <source>Touchscreen mode</source> <translation type="unfinished"></translation> </message> @@ -1897,7 +1979,7 @@ This usually causes the application icon in the task bar to animate in some fash <translation type="unfinished">所有文件(*)</translation> </message> <message> - <location line="+225"/> + <location line="+237"/> <source>Open Sessions File</source> <translation>打开会è¯æ–‡ä»¶</translation> </message> @@ -1993,7 +2075,7 @@ This usually causes the application icon in the task bar to animate in some fash <context> <name>descriptiveTime</name> <message> - <location filename="../../src/Utils.cpp" line="+147"/> + <location filename="../../src/Utils.cpp" line="+145"/> <source>Yesterday</source> <translation type="unfinished"></translation> </message> diff --git a/resources/nheko.desktop b/resources/nheko.desktop index 4404e460721e0b55df850c3084799f39db0645b0..00d7fda52987bc16829115b0e07a57e0e237368f 100644 --- a/resources/nheko.desktop +++ b/resources/nheko.desktop @@ -2,7 +2,7 @@ Name=nheko Version=1.0 Comment=Desktop client for Matrix -Exec=nheko +Exec=nheko %u Icon=nheko Type=Application Categories=Network;InstantMessaging;Qt; diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml index a459fe5a894c16f14f1d5607c88b2734326bd240..f01911bba8d4b762dc4d3c0cc159ce3eafa2fb4e 100644 --- a/resources/qml/Avatar.qml +++ b/resources/qml/Avatar.qml @@ -90,4 +90,9 @@ Rectangle { } } + CursorShape { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + } + } diff --git a/resources/qml/EncryptionIndicator.qml b/resources/qml/EncryptionIndicator.qml index 46ca62c5f9428cc457875a6fcecf68a721388d3f..00efe9e436b01de125057bc10142079c87248d26 100644 --- a/resources/qml/EncryptionIndicator.qml +++ b/resources/qml/EncryptionIndicator.qml @@ -1,4 +1,4 @@ -import QtQuick 2.5 +import QtQuick 2.12 import QtQuick.Controls 2.1 import im.nheko 1.0 @@ -24,14 +24,11 @@ Rectangle { color: "transparent" width: 16 height: 16 - ToolTip.visible: ma.containsMouse && indicator.visible + ToolTip.visible: ma.hovered && indicator.visible ToolTip.text: getEncryptionTooltip() - MouseArea { + HoverHandler { id: ma - - anchors.fill: parent - hoverEnabled: true } Image { diff --git a/resources/qml/ImageButton.qml b/resources/qml/ImageButton.qml index 9c0faef3e443adb8c50bec4a49799918987231a9..159c750f77404236dc61519778819ae87602f19c 100644 --- a/resources/qml/ImageButton.qml +++ b/resources/qml/ImageButton.qml @@ -1,6 +1,7 @@ import "./ui" import QtQuick 2.3 import QtQuick.Controls 2.3 +import im.nheko 1.0 // for cursor shape AbstractButton { id: button @@ -23,11 +24,10 @@ AbstractButton { source: image != "" ? ("image://colorimage/" + image + "?" + ((button.hovered && changeColorOnHover) ? highlightColor : buttonTextColor)) : "" } - MouseArea { + CursorShape { id: mouseArea anchors.fill: parent - onPressed: mouse.accepted = false cursorShape: Qt.PointingHandCursor } diff --git a/resources/qml/MatrixText.qml b/resources/qml/MatrixText.qml index bb3b42968de8c1e677f903faf5dd64758c6c03db..4ea1551840643f1ab529535ba3c966a93ea749ef 100644 --- a/resources/qml/MatrixText.qml +++ b/resources/qml/MatrixText.qml @@ -8,6 +8,7 @@ TextEdit { focus: false wrapMode: Text.Wrap selectByMouse: !Settings.mobileMode + enabled: selectByMouse color: colors.text onLinkActivated: { if (/^https:\/\/matrix.to\/#\/(@.*)$/.test(link)) { @@ -25,12 +26,9 @@ TextEdit { ToolTip.visible: hoveredLink ToolTip.text: hoveredLink - MouseArea { - id: ma - + CursorShape { anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + cursorShape: hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor } } diff --git a/resources/qml/MessageInput.qml b/resources/qml/MessageInput.qml index 5d3358729553d8d124d49a67b5f50e8b1d3c1d05..b5c966606299d78f99cde0c0316312e3ce592385 100644 --- a/resources/qml/MessageInput.qml +++ b/resources/qml/MessageInput.qml @@ -139,6 +139,7 @@ Rectangle { if (TimelineManager.timeline) TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text); + forceActiveFocus(); } onCursorRectangleChanged: textInput.ensureVisible(cursorRectangle) onCursorPositionChanged: { @@ -163,6 +164,10 @@ Rectangle { TimelineManager.timeline.input.paste(false); event.accepted = true; } else if (event.key == Qt.Key_Space) { + // close popup if user enters space after colon + if (cursorPosition == completerTriggeredAt + 1) + popup.close(); + if (popup.opened && popup.count <= 0) popup.close(); @@ -256,16 +261,28 @@ Rectangle { Connections { ignoreUnknownSignals: true - onInsertText: messageInput.insert(messageInput.cursorPosition, text) + onInsertText: { + messageInput.insert(messageInput.cursorPosition, text); + } + onTextChanged: { + messageInput.text = newText; + messageInput.cursorPosition = newText.length; + } target: TimelineManager.timeline ? TimelineManager.timeline.input : null } Connections { ignoreUnknownSignals: true onReplyChanged: messageInput.forceActiveFocus() + onEditChanged: messageInput.forceActiveFocus() target: TimelineManager.timeline } + Connections { + target: TimelineManager + onFocusInput: messageInput.forceActiveFocus() + } + MouseArea { // workaround for wrong cursor shape on some platforms anchors.fill: parent @@ -293,6 +310,7 @@ Rectangle { ToolTip.text: qsTr("Emoji") onClicked: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(emojiButton, function(emoji) { messageInput.insert(messageInput.cursorPosition, emoji); + TimelineManager.focusMessageInput(); }) } diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index 29115b00517dde2ee839915e1b048649ad41333f..e1641a36106288a243ad962318830e440ffd8085 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -1,200 +1,230 @@ import "./delegates" import QtGraphicalEffects 1.0 -import QtQuick 2.9 +import QtQuick 2.12 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.2 import QtQuick.Window 2.2 import im.nheko 1.0 -ListView { - id: chat +ScrollView { + contentWidth: availableWidth + clip: false + palette: colors + padding: 8 - property int delegateMaxWidth: (Settings.timelineMaxWidth > 100 && (parent.width - Settings.timelineMaxWidth) > scrollbar.width * 2) ? Settings.timelineMaxWidth : (parent.width - scrollbar.width * 2 - 8) + ListView { + id: chat - Layout.fillWidth: true - Layout.fillHeight: true - cacheBuffer: 400 - model: TimelineManager.timeline - boundsBehavior: Flickable.StopAtBounds - pixelAligned: true - spacing: 4 - verticalLayoutDirection: ListView.BottomToTop - onCountChanged: { - // Mark timeline as read - if (atYEnd) - model.currentIndex = 0; + property int delegateMaxWidth: ((Settings.timelineMaxWidth > 100 && Settings.timelineMaxWidth < parent.availableWidth) ? Settings.timelineMaxWidth : parent.availableWidth) - parent.padding - } + model: TimelineManager.timeline + boundsBehavior: Flickable.StopAtBounds + pixelAligned: true + spacing: 4 + verticalLayoutDirection: ListView.BottomToTop + onCountChanged: { + // Mark timeline as read + if (atYEnd) + model.currentIndex = 0; - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode - } + } - Shortcut { - sequence: StandardKey.MoveToPreviousPage - onActivated: { - chat.contentY = chat.contentY - chat.height / 2; - chat.returnToBounds(); + ScrollHelper { + flickable: parent + anchors.fill: parent + enabled: !Settings.mobileMode } - } - Shortcut { - sequence: StandardKey.MoveToNextPage - onActivated: { - chat.contentY = chat.contentY + chat.height / 2; - chat.returnToBounds(); + Shortcut { + sequence: StandardKey.MoveToPreviousPage + onActivated: { + chat.contentY = chat.contentY - chat.height / 2; + chat.returnToBounds(); + } } - } - Shortcut { - sequence: StandardKey.Cancel - onActivated: chat.model.reply = undefined - } + Shortcut { + sequence: StandardKey.MoveToNextPage + onActivated: { + chat.contentY = chat.contentY + chat.height / 2; + chat.returnToBounds(); + } + } - Shortcut { - sequence: "Alt+Up" - onActivated: chat.model.reply = chat.model.indexToId(chat.model.reply ? chat.model.idToIndex(chat.model.reply) + 1 : 0) - } + Shortcut { + sequence: StandardKey.Cancel + onActivated: { + if (chat.model.reply) + chat.model.reply = undefined; + else + chat.model.edit = undefined; + } + } - Shortcut { - sequence: "Alt+Down" - onActivated: { - var idx = chat.model.reply ? chat.model.idToIndex(chat.model.reply) - 1 : -1; - chat.model.reply = idx >= 0 ? chat.model.indexToId(idx) : undefined; + Shortcut { + sequence: "Alt+Up" + onActivated: chat.model.reply = chat.model.indexToId(chat.model.reply ? chat.model.idToIndex(chat.model.reply) + 1 : 0) } - } - Component { - id: sectionHeader - - Column { - topPadding: 4 - bottomPadding: 4 - spacing: 8 - visible: modelData && (modelData.previousMessageUserId !== modelData.userId || modelData.previousMessageDay !== modelData.day) - width: parentWidth - height: ((modelData && modelData.previousMessageDay !== modelData.day) ? dateBubble.height + 8 + userName.height : userName.height) + 8 - - Label { - id: dateBubble - - anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined - visible: modelData && modelData.previousMessageDay !== modelData.day - text: modelData ? chat.model.formatDateSeparator(modelData.timestamp) : "" - color: colors.text - height: Math.round(fontMetrics.height * 1.4) - width: contentWidth * 1.2 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - - background: Rectangle { - radius: parent.height / 2 - color: colors.window - } + Shortcut { + sequence: "Alt+Down" + onActivated: { + var idx = chat.model.reply ? chat.model.idToIndex(chat.model.reply) - 1 : -1; + chat.model.reply = idx >= 0 ? chat.model.indexToId(idx) : undefined; + } + } + Shortcut { + sequence: "Ctrl+E" + onActivated: { + chat.model.edit = chat.model.reply; } + } - Row { - height: userName.height - spacing: 8 + Connections { + target: TimelineManager + onFocusChanged: readTimer.running = TimelineManager.isWindowFocused + } - Avatar { - id: messageUserAvatar - width: avatarSize - height: avatarSize - url: modelData ? chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") : "" - displayName: modelData ? modelData.userName : "" - userid: modelData ? modelData.userId : "" - onClicked: chat.model.openUserProfile(modelData.userId) - } + Timer { + id: readTimer - Connections { - target: chat.model - onRoomAvatarUrlChanged: { - messageUserAvatar.url = modelData ? chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") : "" + // force current read index to update + onTriggered: chat.model.setCurrentIndex(chat.model.currentIndex) + interval: 1000 + } + + Component { + id: sectionHeader + + Column { + topPadding: 4 + bottomPadding: 4 + spacing: 8 + visible: modelData && (modelData.previousMessageUserId !== modelData.userId || modelData.previousMessageDay !== modelData.day) + width: parentWidth + height: ((modelData && modelData.previousMessageDay !== modelData.day) ? dateBubble.height + 8 + userName.height : userName.height) + 8 + + Label { + id: dateBubble + + anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined + visible: modelData && modelData.previousMessageDay !== modelData.day + text: modelData ? chat.model.formatDateSeparator(modelData.timestamp) : "" + color: colors.text + height: Math.round(fontMetrics.height * 1.4) + width: contentWidth * 1.2 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + background: Rectangle { + radius: parent.height / 2 + color: colors.window } + } - Label { - id: userName + Row { + height: userName.height + spacing: 8 - text: modelData ? TimelineManager.escapeEmoji(modelData.userName) : "" - color: TimelineManager.userColor(modelData ? modelData.userId : "", colors.window) - textFormat: Text.RichText + Avatar { + id: messageUserAvatar - MouseArea { - anchors.fill: parent - Layout.alignment: Qt.AlignHCenter + width: avatarSize + height: avatarSize + url: modelData ? chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") : "" + displayName: modelData ? modelData.userName : "" + userid: modelData ? modelData.userId : "" onClicked: chat.model.openUserProfile(modelData.userId) - cursorShape: Qt.PointingHandCursor - propagateComposedEvents: true } - } + Connections { + target: chat.model + onRoomAvatarUrlChanged: { + messageUserAvatar.url = modelData ? chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") : ""; + } + } - Label { - color: colors.buttonText - text: modelData ? TimelineManager.userStatus(modelData.userId) : "" - textFormat: Text.PlainText - elide: Text.ElideRight - width: chat.delegateMaxWidth - parent.spacing * 2 - userName.implicitWidth - avatarSize - font.italic: true - } + Label { + id: userName - } + text: modelData ? TimelineManager.escapeEmoji(modelData.userName) : "" + color: TimelineManager.userColor(modelData ? modelData.userId : "", colors.window) + textFormat: Text.RichText - } + TapHandler { + //cursorShape: Qt.PointingHandCursor - } + onSingleTapped: chat.model.openUserProfile(modelData.userId) + } - ScrollBar.vertical: ScrollBar { - id: scrollbar - } + CursorShape { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + } - delegate: Item { - id: wrapper + } - anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined - width: chat.delegateMaxWidth - height: section ? section.height + timelinerow.height : timelinerow.height + Label { + color: colors.buttonText + text: modelData ? TimelineManager.userStatus(modelData.userId) : "" + textFormat: Text.PlainText + elide: Text.ElideRight + width: chat.delegateMaxWidth - parent.spacing * 2 - userName.implicitWidth - avatarSize + font.italic: true + } - Loader { - id: section + } - property var modelData: model - property int parentWidth: parent.width + } - active: model.previousMessageUserId !== undefined && model.previousMessageUserId !== model.userId || model.previousMessageDay !== model.day - //asynchronous: true - sourceComponent: sectionHeader - visible: status == Loader.Ready } - TimelineRow { - id: timelinerow + delegate: Item { + id: wrapper - y: section.active && section.visible ? section.y + section.height : 0 - } + anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined + width: chat.delegateMaxWidth + height: section ? section.height + timelinerow.height : timelinerow.height - Connections { - target: chat - onMovementEnded: { - if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height) - chat.model.currentIndex = index; + Loader { + id: section + property var modelData: model + property int parentWidth: parent.width + + active: model.previousMessageUserId !== undefined && model.previousMessageUserId !== model.userId || model.previousMessageDay !== model.day + //asynchronous: true + sourceComponent: sectionHeader + visible: status == Loader.Ready } + + TimelineRow { + id: timelinerow + + y: section.active && section.visible ? section.y + section.height : 0 + } + + Connections { + target: chat + onMovementEnded: { + if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height) + chat.model.currentIndex = index; + + } + } + } - } + footer: BusyIndicator { + anchors.horizontalCenter: parent.horizontalCenter + running: chat.model && chat.model.paginationInProgress + height: 50 + width: 50 + z: 3 + } - footer: BusyIndicator { - anchors.horizontalCenter: parent.horizontalCenter - running: chat.model && chat.model.paginationInProgress - height: 50 - width: 50 - z: 3 } } diff --git a/resources/qml/ReplyPopup.qml b/resources/qml/ReplyPopup.qml index 4659e0752793ccea03e36b0d1f3d04a76352df94..c07c2c44f5c4fa52d44adc676f0a17c9a48be268 100644 --- a/resources/qml/ReplyPopup.qml +++ b/resources/qml/ReplyPopup.qml @@ -10,15 +10,16 @@ Rectangle { property var room: TimelineManager.timeline Layout.fillWidth: true - visible: room && room.reply + visible: room && (room.reply || room.edit) // Height of child, plus margins, plus border - implicitHeight: replyPreview.height + 10 + implicitHeight: (room && room.reply ? replyPreview.height : closeEditButton.height) + 10 color: colors.window z: 3 Reply { id: replyPreview + visible: room && room.reply anchors.left: parent.left anchors.leftMargin: 2 * 22 + 3 * 16 anchors.right: closeReplyButton.left @@ -32,8 +33,9 @@ Rectangle { ImageButton { id: closeReplyButton + visible: room && room.reply anchors.right: parent.right - anchors.rightMargin: 15 + anchors.rightMargin: 16 anchors.top: replyPreview.top hoverEnabled: true width: 16 @@ -44,4 +46,17 @@ Rectangle { onClicked: room.reply = undefined } + Button { + id: closeEditButton + + visible: room && room.edit + anchors.left: parent.left + anchors.rightMargin: 16 + anchors.topMargin: 10 + anchors.top: parent.top + //height: 16 + text: qsTr("Cancel edit") + onClicked: room.edit = undefined + } + } diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml index 95a025cf6f2fb120fcea53e80c91385ad6d5282c..b731d29d015722d5a37c4f1021f328ef6d5fde90 100644 --- a/resources/qml/TimelineRow.qml +++ b/resources/qml/TimelineRow.qml @@ -1,6 +1,6 @@ import "./delegates" import "./emoji" -import QtQuick 2.6 +import QtQuick 2.12 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.2 import QtQuick.Window 2.2 @@ -12,27 +12,24 @@ Item { height: row.height Rectangle { - color: (Settings.messageHoverHighlight && hoverHandler.containsMouse) ? colors.alternateBase : "transparent" + color: (Settings.messageHoverHighlight && hoverHandler.hovered) ? colors.alternateBase : "transparent" anchors.fill: row } - MouseArea { + HoverHandler { id: hoverHandler - anchors.fill: parent - propagateComposedEvents: true - preventStealing: false - hoverEnabled: true - acceptedButtons: Qt.AllButtons - onClicked: { - if (mouse.button === Qt.RightButton) - messageContextMenu.show(model.id, model.type, model.isEncrypted, row); - else - mouse.accepted = false; - } - onPressAndHold: { - messageContextMenu.show(model.id, model.type, model.isEncrypted, row, mapToItem(timelineRoot, mouse.x, mouse.y)); - } + acceptedDevices: PointerDevice.GenericPointer + } + + TapHandler { + acceptedButtons: Qt.RightButton + onSingleTapped: messageContextMenu.show(model.id, model.type, model.isEncrypted, model.isEditable, row, mapToItem(timelineRoot, eventPoint.position.x, eventPoint.position.y)) + } + + TapHandler { + onLongPressed: messageContextMenu.show(model.id, model.type, model.isEncrypted, model.isEditable, row, mapToItem(timelineRoot, point.position.x, point.position.y)) + onDoubleTapped: chat.model.reply = model.id } RowLayout { @@ -85,6 +82,25 @@ Item { width: 16 } + ImageButton { + id: editButton + + visible: (Settings.buttonsInTimeline && model.isEditable) || model.isEdited + buttonTextColor: chat.model.edit == model.id ? colors.highlight : colors.buttonText + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.preferredHeight: 16 + width: 16 + hoverEnabled: true + image: ":/icons/icons/ui/edit.png" + ToolTip.visible: hovered + ToolTip.text: model.isEditable ? qsTr("Edit") : qsTr("Edited") + onClicked: { + if (model.isEditable) + chat.model.editAction(model.id); + + } + } + EmojiButton { id: reactButton @@ -124,7 +140,7 @@ Item { image: ":/icons/icons/ui/vertical-ellipsis.png" ToolTip.visible: hovered ToolTip.text: qsTr("Options") - onClicked: messageContextMenu.show(model.id, model.type, model.isEncrypted, optionsButton) + onClicked: messageContextMenu.show(model.id, model.type, model.isEncrypted, model.isEditable, optionsButton) } Label { @@ -132,15 +148,11 @@ Item { text: model.timestamp.toLocaleTimeString("HH:mm") width: Math.max(implicitWidth, text.length * fontMetrics.maximumCharacterWidth) color: inactiveColors.text - ToolTip.visible: ma.containsMouse + ToolTip.visible: ma.hovered ToolTip.text: Qt.formatDateTime(model.timestamp, Qt.DefaultLocaleLongDate) - MouseArea { + HoverHandler { id: ma - - anchors.fill: parent - hoverEnabled: true - propagateComposedEvents: true } } diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 7a33f25f0442bd54b57bf03095906ba66eb45afa..7db9d041873aed8a088fb69e6cbab0dda92f9d99 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -74,11 +74,13 @@ Page { property string eventId property int eventType property bool isEncrypted + property bool isEditable - function show(eventId_, eventType_, isEncrypted_, showAt_, position) { + function show(eventId_, eventType_, isEncrypted_, isEditable_, showAt_, position) { eventId = eventId_; eventType = eventType_; isEncrypted = isEncrypted_; + isEditable = isEditable_; if (position) popup(position, showAt_); else @@ -99,6 +101,13 @@ Page { onClicked: TimelineManager.timeline.replyAction(messageContextMenu.eventId) } + MenuItem { + visible: messageContextMenu.isEditable + height: visible ? implicitHeight : 0 + text: qsTr("Edit") + onClicked: TimelineManager.timeline.editAction(messageContextMenu.eventId) + } + MenuItem { text: qsTr("Read receipts") onTriggered: TimelineManager.timeline.readReceiptsAction(messageContextMenu.eventId) diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index e8d410739cb25cea835a10e4699d60ca13fe0468..003f6b3ad7c7bc4dd845dbbc06caf55fabf3d14a 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -49,6 +49,7 @@ ApplicationWindow { Text { id: errorText + text: "Error Text" color: "red" visible: opacity > 0 @@ -58,24 +59,28 @@ ApplicationWindow { SequentialAnimation { id: hideErrorAnimation + running: false + PauseAnimation { duration: 4000 } + NumberAnimation { target: errorText property: 'opacity' to: 0 duration: 1000 } + } - Connections{ + Connections { target: profile onDisplayError: { - errorText.text = errorMessage - errorText.opacity = 1 - hideErrorAnimation.restart() + errorText.text = errorMessage; + errorText.opacity = 1; + hideErrorAnimation.restart(); } } diff --git a/resources/qml/delegates/FileMessage.qml b/resources/qml/delegates/FileMessage.qml index ffd1e82b70b36de46f249e6d51c357a277de5c66..4bc202ebc73116237eacf35844a48190a91f6562 100644 --- a/resources/qml/delegates/FileMessage.qml +++ b/resources/qml/delegates/FileMessage.qml @@ -1,4 +1,4 @@ -import QtQuick 2.6 +import QtQuick 2.12 import QtQuick.Layouts 1.2 import im.nheko 1.0 @@ -31,7 +31,15 @@ Item { MouseArea { anchors.fill: parent - onClicked: TimelineManager.timeline.saveMedia(model.data.id) + cursorShape: Qt.PointingHandCursor + } + + TapHandler { + onSingleTapped: TimelineManager.timeline.saveMedia(model.data.id) + } + + CursorShape { + anchors.fill: parent cursorShape: Qt.PointingHandCursor } diff --git a/resources/qml/delegates/ImageMessage.qml b/resources/qml/delegates/ImageMessage.qml index e8e325f06906e9c5ba80f2d10c2e6ead7a403351..3bb9eb05dfaa61a0cc89b47a46b0bc488e2dd7aa 100644 --- a/resources/qml/delegates/ImageMessage.qml +++ b/resources/qml/delegates/ImageMessage.qml @@ -1,4 +1,4 @@ -import QtQuick 2.6 +import QtQuick 2.12 import im.nheko 1.0 Item { @@ -32,20 +32,20 @@ Item { smooth: true mipmap: true - MouseArea { - id: mouseArea - + TapHandler { enabled: model.data.type == MtxEvent.ImageMessage && img.status == Image.Ready - hoverEnabled: true - anchors.fill: parent - onClicked: TimelineManager.openImageOverlay(model.data.url, model.data.id) + onSingleTapped: TimelineManager.openImageOverlay(model.data.url, model.data.id) + } + + HoverHandler { + id: mouseArea } Item { id: overlay anchors.fill: parent - visible: mouseArea.containsMouse + visible: mouseArea.hovered Rectangle { id: container diff --git a/resources/qml/delegates/NoticeMessage.qml b/resources/qml/delegates/NoticeMessage.qml index 67a690552bd391a59d1e2c920ca962c4831a1ff8..c38cb555680354bbb0661c32f883c2be68895665 100644 --- a/resources/qml/delegates/NoticeMessage.qml +++ b/resources/qml/delegates/NoticeMessage.qml @@ -1,6 +1,6 @@ TextMessage { font.italic: true color: colors.buttonText - height: isReply ? Math.min(chat.height / 8, implicitHeight) : undefined + height: isReply ? Math.min(timelineRoot.height / 8, implicitHeight) : undefined clip: isReply } diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml index 1534da2eff3010d302f0f1799410275a35352854..70f39e434c759b7b6478df2097303e5972e89590 100644 --- a/resources/qml/delegates/PlayableMediaMessage.qml +++ b/resources/qml/delegates/PlayableMediaMessage.qml @@ -1,5 +1,5 @@ import QtMultimedia 5.6 -import QtQuick 2.6 +import QtQuick 2.12 import QtQuick.Controls 2.1 import QtQuick.Layouts 1.2 import im.nheko 1.0 @@ -140,9 +140,8 @@ Rectangle { fillMode: Image.Pad } - MouseArea { - anchors.fill: parent - onClicked: { + TapHandler { + onSingleTapped: { switch (button.state) { case "": TimelineManager.timeline.cacheMedia(model.data.id); @@ -159,6 +158,10 @@ Rectangle { break; } } + } + + CursorShape { + anchors.fill: parent cursorShape: Qt.PointingHandCursor } diff --git a/resources/qml/delegates/Reply.qml b/resources/qml/delegates/Reply.qml index ff1fa6578c7c101fb20e401d3ceec317ce028bba..28c4bf6e240e6cd290d2b9384ec5eeca7e380fa4 100644 --- a/resources/qml/delegates/Reply.qml +++ b/resources/qml/delegates/Reply.qml @@ -1,4 +1,4 @@ -import QtQuick 2.6 +import QtQuick 2.12 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.2 import QtQuick.Window 2.2 @@ -13,10 +13,12 @@ Item { width: parent.width height: replyContainer.height - MouseArea { + TapHandler { + onSingleTapped: chat.positionViewAtIndex(chat.model.idToIndex(modelData.id), ListView.Contain) + } + + CursorShape { anchors.fill: parent - preventStealing: false - onClicked: chat.positionViewAtIndex(chat.model.idToIndex(modelData.id), ListView.Contain) cursorShape: Qt.PointingHandCursor } @@ -43,10 +45,8 @@ Item { color: replyComponent.userColor textFormat: Text.RichText - MouseArea { - anchors.fill: parent - onClicked: chat.model.openUserProfile(reply.modelData.userId) - cursorShape: Qt.PointingHandCursor + TapHandler { + onSingleTapped: chat.model.openUserProfile(reply.modelData.userId) } } diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index 3ff771dcdb5b62f56523a9732e208ed5dffcb9a4..82d0d0e4c4fe4ff2c5b38569cf71f08112cf85b9 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -4,9 +4,10 @@ import im.nheko 1.0 MatrixText { property string formatted: model.data.formattedBody - text: "<span style='white-space: pre-wrap'><style type=\"text/css\">a { color:" + colors.link + ";}\ncode { background-color: " + colors.alternateBase + ";}</style>" + formatted.replace("<pre>", "<pre style='white-space: pre-wrap; background-color: " + colors.alternateBase + "'>") + "</span>" + text: "<style type=\"text/css\">a { color:" + colors.link + ";}\ncode { background-color: " + colors.alternateBase + ";}</style>" + formatted.replace("<pre>", "<pre style='white-space: pre-wrap; background-color: " + colors.alternateBase + "'>") width: parent ? parent.width : undefined height: isReply ? Math.round(Math.min(timelineRoot.height / 8, implicitHeight)) : undefined clip: isReply + selectByMouse: !Settings.mobileMode && !isReply font.pointSize: (Settings.enlargeEmojiOnlyMessages && model.data.isOnlyEmoji > 0 && model.data.isOnlyEmoji < 4) ? Settings.fontSize * 3 : Settings.fontSize } diff --git a/resources/qml/emoji/EmojiButton.qml b/resources/qml/emoji/EmojiButton.qml index 928d6226fee2a26d155426324b5b983f64398952..dd7530a6d1b3b0e14982c528cd956814271ed16e 100644 --- a/resources/qml/emoji/EmojiButton.qml +++ b/resources/qml/emoji/EmojiButton.qml @@ -14,5 +14,6 @@ ImageButton { image: ":/icons/icons/ui/smile.png" onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.show(emojiButton, function(emoji) { TimelineManager.queueReactionMessage(event_id, emoji); + TimelineManager.focusMessageInput(); }) } diff --git a/src/Cache.cpp b/src/Cache.cpp index 3f2bf73a9e84a78f9562cd4e2b1609c0228aad45..8cf66d212c3a0145e92a1afe6d3844f96dceb72d 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -108,6 +108,11 @@ Cache::isHiddenEvent(lmdb::txn &txn, const std::string &room_id) { using namespace mtx::events; + + // Always hide edits + if (mtx::accessors::relations(e).replaces()) + return true; + if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) { MegolmSessionIndex index; index.room_id = room_id; @@ -1197,25 +1202,24 @@ Cache::calculateRoomReadStatus(const std::string &room_id) const auto last_event_id = getLastEventId(txn, room_id); const auto localUser = utils::localUser().toStdString(); + std::string fullyReadEventId; + if (auto ev = getAccountData(txn, mtx::events::EventType::FullyRead, room_id)) { + if (auto fr = std::get_if< + mtx::events::AccountDataEvent<mtx::events::account_data::FullyRead>>( + &ev.value())) { + fullyReadEventId = fr->content.event_id; + } + } txn.commit(); - if (last_event_id.empty()) - return false; - - // Retrieve all read receipts for that event. - const auto receipts = - readReceipts(QString::fromStdString(last_event_id), QString::fromStdString(room_id)); - - if (receipts.size() == 0) + if (last_event_id.empty() || fullyReadEventId.empty()) return true; - // Check if the local user has a read receipt for it. - for (auto it = receipts.cbegin(); it != receipts.cend(); it++) { - if (it->second == localUser) - return false; - } + if (last_event_id == fullyReadEventId) + return false; - return true; + // Retrieve all read receipts for that event. + return getEventIndex(room_id, last_event_id) > getEventIndex(room_id, fullyReadEventId); } void @@ -1891,6 +1895,108 @@ Cache::getTimelineIndex(const std::string &room_id, std::string_view event_id) return *val.data<uint64_t>(); } +std::optional<uint64_t> +Cache::getEventIndex(const std::string &room_id, std::string_view event_id) +{ + if (event_id.empty()) + return {}; + + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + + lmdb::dbi orderDb{0}; + try { + orderDb = getEventToOrderDb(txn, room_id); + } catch (lmdb::runtime_error &e) { + nhlog::db()->error("Can't open db for room '{}', probably doesn't exist yet. ({})", + room_id, + e.what()); + return {}; + } + + lmdb::val indexVal{event_id.data(), event_id.size()}, val; + + bool success = lmdb::dbi_get(txn, orderDb, indexVal, val); + if (!success) { + return {}; + } + + return *val.data<uint64_t>(); +} + +std::optional<std::pair<uint64_t, std::string>> +Cache::lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id) +{ + if (event_id.empty()) + return {}; + + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + + lmdb::dbi orderDb{0}; + lmdb::dbi eventOrderDb{0}; + lmdb::dbi timelineDb{0}; + try { + orderDb = getEventToOrderDb(txn, room_id); + eventOrderDb = getEventOrderDb(txn, room_id); + timelineDb = getMessageToOrderDb(txn, room_id); + } catch (lmdb::runtime_error &e) { + nhlog::db()->error("Can't open db for room '{}', probably doesn't exist yet. ({})", + room_id, + e.what()); + return {}; + } + + lmdb::val eventIdVal{event_id.data(), event_id.size()}, indexVal; + + bool success = lmdb::dbi_get(txn, orderDb, eventIdVal, indexVal); + if (!success) { + return {}; + } + uint64_t prevIdx = *indexVal.data<uint64_t>(); + std::string prevId{eventIdVal.data(), eventIdVal.size()}; + + auto cursor = lmdb::cursor::open(txn, eventOrderDb); + cursor.get(indexVal, MDB_SET); + while (cursor.get(indexVal, eventIdVal, MDB_NEXT)) { + std::string evId = + json::parse(std::string_view(eventIdVal.data(), eventIdVal.size()))["event_id"] + .get<std::string>(); + lmdb::val temp; + if (lmdb::dbi_get(txn, timelineDb, lmdb::val(evId.data(), evId.size()), temp)) { + return std::pair{prevIdx, std::string(prevId)}; + } else { + prevIdx = *indexVal.data<uint64_t>(); + prevId = std::move(evId); + } + } + + return std::pair{prevIdx, std::string(prevId)}; +} + +std::optional<uint64_t> +Cache::getArrivalIndex(const std::string &room_id, std::string_view event_id) +{ + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + + lmdb::dbi orderDb{0}; + try { + orderDb = getEventToOrderDb(txn, room_id); + } catch (lmdb::runtime_error &e) { + nhlog::db()->error("Can't open db for room '{}', probably doesn't exist yet. ({})", + room_id, + e.what()); + return {}; + } + + lmdb::val indexVal{event_id.data(), event_id.size()}, val; + + bool success = lmdb::dbi_get(txn, orderDb, indexVal, val); + if (!success) { + return {}; + } + + return *val.data<uint64_t>(); +} + std::optional<std::string> Cache::getTimelineEventId(const std::string &room_id, uint64_t index) { @@ -2713,23 +2819,19 @@ Cache::saveTimelineMessages(lmdb::txn &txn, lmdb::dbi_put(txn, evToOrderDb, event_id, txn_order); lmdb::dbi_del(txn, evToOrderDb, lmdb::val(txn_id)); - if (event.contains("content") && - event["content"].contains("m.relates_to")) { - auto temp = event["content"]["m.relates_to"]; - json relates_to_j = temp.contains("m.in_reply_to") && - temp["m.in_reply_to"].is_object() - ? temp["m.in_reply_to"]["event_id"] - : temp["event_id"]; - std::string relates_to = - relates_to_j.is_string() ? relates_to_j.get<std::string>() : ""; - - if (!relates_to.empty()) { - lmdb::dbi_del(txn, - relationsDb, - lmdb::val(relates_to), - lmdb::val(txn_id)); - lmdb::dbi_put( - txn, relationsDb, lmdb::val(relates_to), event_id); + auto relations = mtx::accessors::relations(e); + if (!relations.relations.empty()) { + for (const auto &r : relations.relations) { + if (!r.event_id.empty()) { + lmdb::dbi_del(txn, + relationsDb, + lmdb::val(r.event_id), + lmdb::val(txn_id)); + lmdb::dbi_put(txn, + relationsDb, + lmdb::val(r.event_id), + event_id); + } } } @@ -2808,19 +2910,16 @@ Cache::saveTimelineMessages(lmdb::txn &txn, lmdb::val(&msgIndex, sizeof(msgIndex))); } - if (event.contains("content") && - event["content"].contains("m.relates_to")) { - auto temp = event["content"]["m.relates_to"]; - json relates_to_j = temp.contains("m.in_reply_to") && - temp["m.in_reply_to"].is_object() - ? temp["m.in_reply_to"]["event_id"] - : temp["event_id"]; - std::string relates_to = - relates_to_j.is_string() ? relates_to_j.get<std::string>() : ""; - - if (!relates_to.empty()) - lmdb::dbi_put( - txn, relationsDb, lmdb::val(relates_to), event_id); + auto relations = mtx::accessors::relations(e); + if (!relations.relations.empty()) { + for (const auto &r : relations.relations) { + if (!r.event_id.empty()) { + lmdb::dbi_put(txn, + relationsDb, + lmdb::val(r.event_id), + event_id); + } + } } } } @@ -2901,17 +3000,14 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message txn, msg2orderDb, event_id, lmdb::val(&msgIndex, sizeof(msgIndex))); } - if (event.contains("content") && event["content"].contains("m.relates_to")) { - auto temp = event["content"]["m.relates_to"]; - json relates_to_j = - temp.contains("m.in_reply_to") && temp["m.in_reply_to"].is_object() - ? temp["m.in_reply_to"]["event_id"] - : temp["event_id"]; - std::string relates_to = - relates_to_j.is_string() ? relates_to_j.get<std::string>() : ""; - - if (!relates_to.empty()) - lmdb::dbi_put(txn, relationsDb, lmdb::val(relates_to), event_id); + auto relations = mtx::accessors::relations(e); + if (!relations.relations.empty()) { + for (const auto &r : relations.relations) { + if (!r.event_id.empty()) { + lmdb::dbi_put( + txn, relationsDb, lmdb::val(r.event_id), event_id); + } + } } } @@ -3222,9 +3318,12 @@ Cache::getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::st 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(); + json j = json::array({ + json::parse(std::string_view(data.data(), data.size())), + }); + mtx::responses::utils::parse_room_account_data_events(j, events); + if (events.size() == 1) + return events.front(); } } catch (...) { } @@ -4233,6 +4332,18 @@ readReceipts(const QString &event_id, const QString &room_id) return instance_->readReceipts(event_id, room_id); } +std::optional<uint64_t> +getEventIndex(const std::string &room_id, std::string_view event_id) +{ + return instance_->getEventIndex(room_id, event_id); +} + +std::optional<std::pair<uint64_t, std::string>> +lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id) +{ + return instance_->lastInvisibleEventAfter(room_id, event_id); +} + QByteArray image(const QString &url) { diff --git a/src/Cache.h b/src/Cache.h index 919567257387fd20f74e53eda8134bb945cce0fd..e60fc970e38c28e11e84966a3b818f1e5335c8b1 100644 --- a/src/Cache.h +++ b/src/Cache.h @@ -168,6 +168,12 @@ using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t> UserReceipts readReceipts(const QString &event_id, const QString &room_id); +//! get index of the event in the event db, not representing the visual index +std::optional<uint64_t> +getEventIndex(const std::string &room_id, std::string_view event_id); +std::optional<std::pair<uint64_t, std::string>> +lastInvisibleEventAfter(const std::string &room_id, std::string_view event_id); + QByteArray image(const QString &url); QByteArray diff --git a/src/Cache_p.h b/src/Cache_p.h index e2ce16683867d1758bafc97325d452cb959af938..431e7bc33abd998de66502f353f2fd24ff558971 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -204,7 +204,14 @@ public: std::optional<TimelineRange> getTimelineRange(const std::string &room_id); std::optional<uint64_t> getTimelineIndex(const std::string &room_id, std::string_view event_id); + std::optional<uint64_t> getEventIndex(const std::string &room_id, + std::string_view event_id); + std::optional<std::pair<uint64_t, std::string>> lastInvisibleEventAfter( + const std::string &room_id, + std::string_view event_id); std::optional<std::string> getTimelineEventId(const std::string &room_id, uint64_t index); + std::optional<uint64_t> getArrivalIndex(const std::string &room_id, + std::string_view event_id); std::string previousBatchToken(const std::string &room_id); uint64_t saveOldMessages(const std::string &room_id, const mtx::responses::Messages &res); diff --git a/src/CallDevices.cpp b/src/CallDevices.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b9809e5b18cefe9e087cb4e8aae001e2816b3dd --- /dev/null +++ b/src/CallDevices.cpp @@ -0,0 +1,437 @@ +#include <cstring> +#include <optional> +#include <string_view> + +#include "CallDevices.h" +#include "ChatPage.h" +#include "Logging.h" +#include "UserSettingsPage.h" + +#ifdef GSTREAMER_AVAILABLE +extern "C" +{ +#include "gst/gst.h" +} +#endif + +CallDevices::CallDevices() + : QObject() +{} + +#ifdef GSTREAMER_AVAILABLE +namespace { + +struct AudioSource +{ + std::string name; + GstDevice *device; +}; + +struct VideoSource +{ + struct Caps + { + std::string resolution; + std::vector<std::string> frameRates; + }; + std::string name; + GstDevice *device; + std::vector<Caps> caps; +}; + +std::vector<AudioSource> audioSources_; +std::vector<VideoSource> videoSources_; + +using FrameRate = std::pair<int, int>; +std::optional<FrameRate> +getFrameRate(const GValue *value) +{ + if (GST_VALUE_HOLDS_FRACTION(value)) { + gint num = gst_value_get_fraction_numerator(value); + gint den = gst_value_get_fraction_denominator(value); + return FrameRate{num, den}; + } + return std::nullopt; +} + +void +addFrameRate(std::vector<std::string> &rates, const FrameRate &rate) +{ + constexpr double minimumFrameRate = 15.0; + if (static_cast<double>(rate.first) / rate.second >= minimumFrameRate) + rates.push_back(std::to_string(rate.first) + "/" + std::to_string(rate.second)); +} + +void +setDefaultDevice(bool isVideo) +{ + auto settings = ChatPage::instance()->userSettings(); + if (isVideo && settings->camera().isEmpty()) { + const VideoSource &camera = videoSources_.front(); + settings->setCamera(QString::fromStdString(camera.name)); + settings->setCameraResolution( + QString::fromStdString(camera.caps.front().resolution)); + settings->setCameraFrameRate( + QString::fromStdString(camera.caps.front().frameRates.front())); + } else if (!isVideo && settings->microphone().isEmpty()) { + settings->setMicrophone(QString::fromStdString(audioSources_.front().name)); + } +} + +void +addDevice(GstDevice *device) +{ + if (!device) + return; + + gchar *name = gst_device_get_display_name(device); + gchar *type = gst_device_get_device_class(device); + bool isVideo = !std::strncmp(type, "Video", 5); + g_free(type); + nhlog::ui()->debug("WebRTC: {} device added: {}", isVideo ? "video" : "audio", name); + if (!isVideo) { + audioSources_.push_back({name, device}); + g_free(name); + setDefaultDevice(false); + return; + } + + GstCaps *gstcaps = gst_device_get_caps(device); + if (!gstcaps) { + nhlog::ui()->debug("WebRTC: unable to get caps for {}", name); + g_free(name); + return; + } + + VideoSource source{name, device, {}}; + g_free(name); + guint nCaps = gst_caps_get_size(gstcaps); + for (guint i = 0; i < nCaps; ++i) { + GstStructure *structure = gst_caps_get_structure(gstcaps, i); + const gchar *name = gst_structure_get_name(structure); + if (!std::strcmp(name, "video/x-raw")) { + gint widthpx, heightpx; + if (gst_structure_get(structure, + "width", + G_TYPE_INT, + &widthpx, + "height", + G_TYPE_INT, + &heightpx, + nullptr)) { + VideoSource::Caps caps; + caps.resolution = + std::to_string(widthpx) + "x" + std::to_string(heightpx); + const GValue *value = + gst_structure_get_value(structure, "framerate"); + if (auto fr = getFrameRate(value); fr) + addFrameRate(caps.frameRates, *fr); + else if (GST_VALUE_HOLDS_FRACTION_RANGE(value)) { + addFrameRate( + caps.frameRates, + *getFrameRate(gst_value_get_fraction_range_min(value))); + addFrameRate( + caps.frameRates, + *getFrameRate(gst_value_get_fraction_range_max(value))); + } else if (GST_VALUE_HOLDS_LIST(value)) { + guint nRates = gst_value_list_get_size(value); + for (guint j = 0; j < nRates; ++j) { + const GValue *rate = + gst_value_list_get_value(value, j); + if (auto fr = getFrameRate(rate); fr) + addFrameRate(caps.frameRates, *fr); + } + } + if (!caps.frameRates.empty()) + source.caps.push_back(std::move(caps)); + } + } + } + gst_caps_unref(gstcaps); + videoSources_.push_back(std::move(source)); + setDefaultDevice(true); +} + +#if GST_CHECK_VERSION(1, 18, 0) +template<typename T> +bool +removeDevice(T &sources, GstDevice *device, bool changed) +{ + if (auto it = std::find_if(sources.begin(), + sources.end(), + [device](const auto &s) { return s.device == device; }); + it != sources.end()) { + nhlog::ui()->debug(std::string("WebRTC: device ") + + (changed ? "changed: " : "removed: ") + "{}", + it->name); + gst_object_unref(device); + sources.erase(it); + return true; + } + return false; +} + +void +removeDevice(GstDevice *device, bool changed) +{ + if (device) { + if (removeDevice(audioSources_, device, changed) || + removeDevice(videoSources_, device, changed)) + return; + } +} + +gboolean +newBusMessage(GstBus *bus G_GNUC_UNUSED, GstMessage *msg, gpointer user_data G_GNUC_UNUSED) +{ + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_DEVICE_ADDED: { + GstDevice *device; + gst_message_parse_device_added(msg, &device); + addDevice(device); + emit CallDevices::instance().devicesChanged(); + break; + } + case GST_MESSAGE_DEVICE_REMOVED: { + GstDevice *device; + gst_message_parse_device_removed(msg, &device); + removeDevice(device, false); + emit CallDevices::instance().devicesChanged(); + break; + } + case GST_MESSAGE_DEVICE_CHANGED: { + GstDevice *device; + GstDevice *oldDevice; + gst_message_parse_device_changed(msg, &device, &oldDevice); + removeDevice(oldDevice, true); + addDevice(device); + break; + } + default: + break; + } + return TRUE; +} +#endif + +template<typename T> +std::vector<std::string> +deviceNames(T &sources, const std::string &defaultDevice) +{ + std::vector<std::string> ret; + ret.reserve(sources.size()); + for (const auto &s : sources) + ret.push_back(s.name); + + // move default device to top of the list + if (auto it = std::find(ret.begin(), ret.end(), defaultDevice); it != ret.end()) + std::swap(ret.front(), *it); + + return ret; +} + +std::optional<VideoSource> +getVideoSource(const std::string &cameraName) +{ + if (auto it = std::find_if(videoSources_.cbegin(), + videoSources_.cend(), + [&cameraName](const auto &s) { return s.name == cameraName; }); + it != videoSources_.cend()) { + return *it; + } + return std::nullopt; +} + +std::pair<int, int> +tokenise(std::string_view str, char delim) +{ + std::pair<int, int> ret; + ret.first = std::atoi(str.data()); + auto pos = str.find_first_of(delim); + ret.second = std::atoi(str.data() + pos + 1); + return ret; +} + +} + +void +CallDevices::init() +{ +#if GST_CHECK_VERSION(1, 18, 0) + static GstDeviceMonitor *monitor = nullptr; + if (!monitor) { + monitor = gst_device_monitor_new(); + GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw"); + gst_device_monitor_add_filter(monitor, "Audio/Source", caps); + gst_device_monitor_add_filter(monitor, "Audio/Duplex", caps); + gst_caps_unref(caps); + caps = gst_caps_new_empty_simple("video/x-raw"); + gst_device_monitor_add_filter(monitor, "Video/Source", caps); + gst_device_monitor_add_filter(monitor, "Video/Duplex", caps); + gst_caps_unref(caps); + + GstBus *bus = gst_device_monitor_get_bus(monitor); + gst_bus_add_watch(bus, newBusMessage, nullptr); + gst_object_unref(bus); + if (!gst_device_monitor_start(monitor)) { + nhlog::ui()->error("WebRTC: failed to start device monitor"); + return; + } + } +#endif +} + +void +CallDevices::refresh() +{ +#if !GST_CHECK_VERSION(1, 18, 0) + + static GstDeviceMonitor *monitor = nullptr; + if (!monitor) { + monitor = gst_device_monitor_new(); + GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw"); + gst_device_monitor_add_filter(monitor, "Audio/Source", caps); + gst_device_monitor_add_filter(monitor, "Audio/Duplex", caps); + gst_caps_unref(caps); + caps = gst_caps_new_empty_simple("video/x-raw"); + gst_device_monitor_add_filter(monitor, "Video/Source", caps); + gst_device_monitor_add_filter(monitor, "Video/Duplex", caps); + gst_caps_unref(caps); + } + + auto clearDevices = [](auto &sources) { + std::for_each( + sources.begin(), sources.end(), [](auto &s) { gst_object_unref(s.device); }); + sources.clear(); + }; + clearDevices(audioSources_); + clearDevices(videoSources_); + + GList *devices = gst_device_monitor_get_devices(monitor); + if (devices) { + for (GList *l = devices; l != nullptr; l = l->next) + addDevice(GST_DEVICE_CAST(l->data)); + g_list_free(devices); + } + emit devicesChanged(); +#endif +} + +bool +CallDevices::haveMic() const +{ + return !audioSources_.empty(); +} + +bool +CallDevices::haveCamera() const +{ + return !videoSources_.empty(); +} + +std::vector<std::string> +CallDevices::names(bool isVideo, const std::string &defaultDevice) const +{ + return isVideo ? deviceNames(videoSources_, defaultDevice) + : deviceNames(audioSources_, defaultDevice); +} + +std::vector<std::string> +CallDevices::resolutions(const std::string &cameraName) const +{ + std::vector<std::string> ret; + if (auto s = getVideoSource(cameraName); s) { + ret.reserve(s->caps.size()); + for (const auto &c : s->caps) + ret.push_back(c.resolution); + } + return ret; +} + +std::vector<std::string> +CallDevices::frameRates(const std::string &cameraName, const std::string &resolution) const +{ + if (auto s = getVideoSource(cameraName); s) { + if (auto it = + std::find_if(s->caps.cbegin(), + s->caps.cend(), + [&](const auto &c) { return c.resolution == resolution; }); + it != s->caps.cend()) + return it->frameRates; + } + return {}; +} + +GstDevice * +CallDevices::audioDevice() const +{ + std::string name = ChatPage::instance()->userSettings()->microphone().toStdString(); + if (auto it = std::find_if(audioSources_.cbegin(), + audioSources_.cend(), + [&name](const auto &s) { return s.name == name; }); + it != audioSources_.cend()) { + nhlog::ui()->debug("WebRTC: microphone: {}", name); + return it->device; + } else { + nhlog::ui()->error("WebRTC: unknown microphone: {}", name); + return nullptr; + } +} + +GstDevice * +CallDevices::videoDevice(std::pair<int, int> &resolution, std::pair<int, int> &frameRate) const +{ + auto settings = ChatPage::instance()->userSettings(); + std::string name = settings->camera().toStdString(); + if (auto s = getVideoSource(name); s) { + nhlog::ui()->debug("WebRTC: camera: {}", name); + resolution = tokenise(settings->cameraResolution().toStdString(), 'x'); + frameRate = tokenise(settings->cameraFrameRate().toStdString(), '/'); + nhlog::ui()->debug( + "WebRTC: camera resolution: {}x{}", resolution.first, resolution.second); + nhlog::ui()->debug( + "WebRTC: camera frame rate: {}/{}", frameRate.first, frameRate.second); + return s->device; + } else { + nhlog::ui()->error("WebRTC: unknown camera: {}", name); + return nullptr; + } +} + +#else + +void +CallDevices::refresh() +{} + +bool +CallDevices::haveMic() const +{ + return false; +} + +bool +CallDevices::haveCamera() const +{ + return false; +} + +std::vector<std::string> +CallDevices::names(bool, const std::string &) const +{ + return {}; +} + +std::vector<std::string> +CallDevices::resolutions(const std::string &) const +{ + return {}; +} + +std::vector<std::string> +CallDevices::frameRates(const std::string &, const std::string &) const +{ + return {}; +} + +#endif diff --git a/src/CallDevices.h b/src/CallDevices.h new file mode 100644 index 0000000000000000000000000000000000000000..2b4129f11be08c9754385ae916a0e228c52ce974 --- /dev/null +++ b/src/CallDevices.h @@ -0,0 +1,45 @@ +#pragma once + +#include <string> +#include <utility> +#include <vector> + +#include <QObject> + +typedef struct _GstDevice GstDevice; + +class CallDevices : public QObject +{ + Q_OBJECT + +public: + static CallDevices &instance() + { + static CallDevices instance; + return instance; + } + + void refresh(); + bool haveMic() const; + bool haveCamera() const; + std::vector<std::string> names(bool isVideo, const std::string &defaultDevice) const; + std::vector<std::string> resolutions(const std::string &cameraName) const; + std::vector<std::string> frameRates(const std::string &cameraName, + const std::string &resolution) const; + +signals: + void devicesChanged(); + +private: + CallDevices(); + + friend class WebRTCSession; + void init(); + GstDevice *audioDevice() const; + GstDevice *videoDevice(std::pair<int, int> &resolution, + std::pair<int, int> &frameRate) const; + +public: + CallDevices(CallDevices const &) = delete; + void operator=(CallDevices const &) = delete; +}; diff --git a/src/CallManager.cpp b/src/CallManager.cpp index 0841a079d9d70c6e46052e9f047fc7642ad30090..7acd9592b695d4a2738b33b5c6af9e5e95e0ae3e 100644 --- a/src/CallManager.cpp +++ b/src/CallManager.cpp @@ -7,6 +7,7 @@ #include <QUrl> #include "Cache.h" +#include "CallDevices.h" #include "CallManager.h" #include "ChatPage.h" #include "Logging.h" @@ -114,21 +115,10 @@ CallManager::CallManager(QObject *parent) emit newCallState(); }); - connect(&session_, &WebRTCSession::devicesChanged, this, [this]() { - if (ChatPage::instance()->userSettings()->microphone().isEmpty()) { - auto mics = session_.getDeviceNames(false, std::string()); - if (!mics.empty()) - ChatPage::instance()->userSettings()->setMicrophone( - QString::fromStdString(mics.front())); - } - if (ChatPage::instance()->userSettings()->camera().isEmpty()) { - auto cameras = session_.getDeviceNames(true, std::string()); - if (!cameras.empty()) - ChatPage::instance()->userSettings()->setCamera( - QString::fromStdString(cameras.front())); - } - emit devicesChanged(); - }); + connect(&CallDevices::instance(), + &CallDevices::devicesChanged, + this, + &CallManager::devicesChanged); connect(&player_, &QMediaPlayer::mediaStatusChanged, @@ -292,7 +282,7 @@ CallManager::handleEvent(const RoomEvent<CallInvite> &callInviteEvent) haveCallInvite_ = true; isVideo_ = isVideo; inviteSDP_ = callInviteEvent.content.sdp; - session_.refreshDevices(); + CallDevices::instance().refresh(); emit newInviteState(); } @@ -409,7 +399,7 @@ CallManager::devices(bool isVideo) const const QString &defaultDevice = isVideo ? ChatPage::instance()->userSettings()->camera() : ChatPage::instance()->userSettings()->microphone(); std::vector<std::string> devices = - session_.getDeviceNames(isVideo, defaultDevice.toStdString()); + CallDevices::instance().names(isVideo, defaultDevice.toStdString()); ret.reserve(devices.size()); std::transform(devices.cbegin(), devices.cend(), diff --git a/src/CallManager.h b/src/CallManager.h index 7d388efdac337148412bf7e4c0308c98e9e93555..97cffbc885e08fce0e865f17fe640424540b951e 100644 --- a/src/CallManager.h +++ b/src/CallManager.h @@ -8,6 +8,7 @@ #include <QString> #include <QTimer> +#include "CallDevices.h" #include "WebRTCSession.h" #include "mtx/events/collections.hpp" #include "mtx/events/voip.hpp" @@ -53,7 +54,7 @@ public: public slots: void sendInvite(const QString &roomid, bool isVideo); void syncEvent(const mtx::events::collections::TimelineEvents &event); - void refreshDevices() { session_.refreshDevices(); } + void refreshDevices() { CallDevices::instance().refresh(); } void toggleMicMute(); void toggleCameraView() { session_.toggleCameraView(); } void acceptInvite(); diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index db80ecd58e7ddeacb573adbef2bee74a8a9027ad..45802789981b91171c109e43c72323eafaf15c0b 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -448,15 +448,14 @@ void ChatPage::deleteConfigs() { QSettings settings; + + if (UserSettings::instance()->profile() != "") { + settings.beginGroup("profile"); + settings.beginGroup(UserSettings::instance()->profile()); + } settings.beginGroup("auth"); settings.remove(""); - settings.endGroup(); - settings.beginGroup("client"); - settings.remove(""); - settings.endGroup(); - settings.beginGroup("notifications"); - settings.remove(""); - settings.endGroup(); + settings.endGroup(); // auth http::client()->shutdown(); cache::deleteData(); @@ -669,8 +668,6 @@ ChatPage::sendNotifications(const mtx::responses::Notifications &res) if (!cache::isNotificationSent(event_id)) { const auto room_id = QString::fromStdString(item.room_id); - const auto user_id = - QString::fromStdString(mtx::accessors::sender(item.event)); // We should only sent one notification per event. cache::markSentNotification(event_id); @@ -690,15 +687,9 @@ ChatPage::sendNotifications(const mtx::responses::Notifications &res) QString::fromStdString(info.avatar_url), 96, this, - [this, room_id, event_id, item, user_id, info]( - QPixmap image) { + [this, item](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()); + item, image.toImage()); }); } } diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp index 51ef79fd152687ba0c057604451d43de999f8d3e..c6277a9d320fcdf012165a5a3d5fec3e8a8f720c 100644 --- a/src/DeviceVerificationFlow.cpp +++ b/src/DeviceVerificationFlow.cpp @@ -105,8 +105,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, if (msg.transaction_id.has_value()) { if (msg.transaction_id.value() != this->transaction_id) return; - } else if (msg.relates_to.has_value()) { - if (msg.relates_to.value().event_id != this->relation.event_id) + } else if (msg.relations.references()) { + if (msg.relations.references() != this->relation.event_id) return; } if ((msg.key_agreement_protocol == "curve25519-hkdf-sha256") && @@ -136,8 +136,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, if (msg.transaction_id.has_value()) { if (msg.transaction_id.value() != this->transaction_id) return; - } else if (msg.relates_to.has_value()) { - if (msg.relates_to.value().event_id != this->relation.event_id) + } else if (msg.relations.references()) { + if (msg.relations.references() != this->relation.event_id) return; } error_ = User; @@ -152,8 +152,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, if (msg.transaction_id.has_value()) { if (msg.transaction_id.value() != this->transaction_id) return; - } else if (msg.relates_to.has_value()) { - if (msg.relates_to.value().event_id != this->relation.event_id) + } else if (msg.relations.references()) { + if (msg.relations.references() != this->relation.event_id) return; } @@ -217,8 +217,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, if (msg.transaction_id.has_value()) { if (msg.transaction_id.value() != this->transaction_id) return; - } else if (msg.relates_to.has_value()) { - if (msg.relates_to.value().event_id != this->relation.event_id) + } else if (msg.relations.references()) { + if (msg.relations.references() != this->relation.event_id) return; } @@ -385,8 +385,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, if (msg.transaction_id.has_value()) { if (msg.transaction_id.value() != this->transaction_id) return; - } else if ((msg.relates_to.has_value() && sender)) { - if (msg.relates_to.value().event_id != this->relation.event_id) + } else if (msg.relations.references()) { + if (msg.relations.references() != this->relation.event_id) return; else { this->deviceId = QString::fromStdString(msg.from_device); @@ -402,8 +402,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, if (msg.transaction_id.has_value()) { if (msg.transaction_id.value() != this->transaction_id) return; - } else if (msg.relates_to.has_value()) { - if (msg.relates_to.value().event_id != this->relation.event_id) + } else if (msg.relations.references()) { + if (msg.relations.references() != this->relation.event_id) return; } nhlog::ui()->info("Flow done on other side"); @@ -526,8 +526,8 @@ DeviceVerificationFlow::handleStartMessage(const mtx::events::msg::KeyVerificati if (msg.transaction_id.has_value()) { if (msg.transaction_id.value() != this->transaction_id) return; - } else if (msg.relates_to.has_value()) { - if (msg.relates_to.value().event_id != this->relation.event_id) + } else if (msg.relations.references()) { + if (msg.relations.references() != this->relation.event_id) return; } if ((std::find(msg.key_agreement_protocols.begin(), @@ -625,8 +625,10 @@ DeviceVerificationFlow::startVerificationRequest() req.transaction_id = this->transaction_id; this->canonical_json = nlohmann::json(req); } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) { - req.relates_to = this->relation; - this->canonical_json = nlohmann::json(req); + req.relations.relations.push_back(this->relation); + // Set synthesized to surpress the nheko relation extensions + req.relations.synthesized = true; + this->canonical_json = nlohmann::json(req); } send(req); setState(WaitingForOtherToAccept); diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h index 34b78962c3040b56ad737172cad3072dcbb477e1..6c61354522411e0095ce8e8cd1c647838f531998 100644 --- a/src/DeviceVerificationFlow.h +++ b/src/DeviceVerificationFlow.h @@ -206,7 +206,7 @@ private: std::vector<int> sasList; UserKeyCache their_keys; TimelineModel *model_; - mtx::common::RelatesTo relation; + mtx::common::Relation relation; State state_ = PromptStartVerification; Error error_ = UnknownMethod; @@ -230,8 +230,12 @@ private: static_cast<int>(err->status_code)); }); } else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) { - if constexpr (!std::is_same_v<T, mtx::events::msg::KeyVerificationRequest>) - msg.relates_to = this->relation; + if constexpr (!std::is_same_v<T, + mtx::events::msg::KeyVerificationRequest>) { + msg.relations.relations.push_back(this->relation); + // Set synthesized to surpress the nheko relation extensions + msg.relations.synthesized = true; + } (model_)->sendMessageEvent(msg, mtx::events::to_device_content_to_type<T>); } diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp index 3ae781f048f730cb60539cb79f9968c890327f76..e6bc61b0b8cd7a72b06a2daba79c3662e1e44a66 100644 --- a/src/EventAccessors.cpp +++ b/src/EventAccessors.cpp @@ -34,6 +34,20 @@ struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> template<template<class...> class Op, class... Args> using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t; +struct IsStateEvent +{ + template<class T> + bool operator()(const mtx::events::StateEvent<T> &) + { + return true; + } + template<class T> + bool operator()(const mtx::events::Event<T> &) + { + return false; + } +}; + struct EventMsgType { template<class E> @@ -250,31 +264,31 @@ struct EventFilesize } }; -struct EventInReplyTo +struct EventRelations { template<class Content> - using related_ev_id_t = decltype(Content::relates_to.in_reply_to.event_id); + using related_ev_id_t = decltype(Content::relations); template<class T> - std::string operator()(const mtx::events::Event<T> &e) + mtx::common::Relations operator()(const mtx::events::Event<T> &e) { if constexpr (is_detected<related_ev_id_t, T>::value) { - return e.content.relates_to.in_reply_to.event_id; + return e.content.relations; } - return ""; + return {}; } }; -struct EventRelatesTo +struct SetEventRelations { + mtx::common::Relations new_relations; template<class Content> - using related_ev_id_t = decltype(Content::relates_to.event_id); + using related_ev_id_t = decltype(Content::relations); template<class T> - std::string operator()(const mtx::events::Event<T> &e) + void operator()(mtx::events::Event<T> &e) { if constexpr (is_detected<related_ev_id_t, T>::value) { - return e.content.relates_to.event_id; + e.content.relations = std::move(new_relations); } - return ""; } }; @@ -434,15 +448,17 @@ mtx::accessors::mimetype(const mtx::events::collections::TimelineEvents &event) { return std::visit(EventMimeType{}, event); } -std::string -mtx::accessors::in_reply_to_event(const mtx::events::collections::TimelineEvents &event) +mtx::common::Relations +mtx::accessors::relations(const mtx::events::collections::TimelineEvents &event) { - return std::visit(EventInReplyTo{}, event); + return std::visit(EventRelations{}, event); } -std::string -mtx::accessors::relates_to_event_id(const mtx::events::collections::TimelineEvents &event) + +void +mtx::accessors::set_relations(mtx::events::collections::TimelineEvents &event, + mtx::common::Relations relations) { - return std::visit(EventRelatesTo{}, event); + std::visit(SetEventRelations{std::move(relations)}, event); } std::string @@ -474,3 +490,9 @@ mtx::accessors::serialize_event(const mtx::events::collections::TimelineEvents & { return std::visit([](const auto &e) { return nlohmann::json(e); }, event); } + +bool +mtx::accessors::is_state_event(const mtx::events::collections::TimelineEvents &event) +{ + return std::visit(IsStateEvent{}, event); +} diff --git a/src/EventAccessors.h b/src/EventAccessors.h index 0cdc5f89e19b2833a5ae634d569f3b8588841b3f..7bf695fc8e52dec6bbe5fe15c65f51dd728e46c3 100644 --- a/src/EventAccessors.h +++ b/src/EventAccessors.h @@ -17,6 +17,9 @@ room_id(const mtx::events::collections::TimelineEvents &event); std::string sender(const mtx::events::collections::TimelineEvents &event); +bool +is_state_event(const mtx::events::collections::TimelineEvents &event); + QDateTime origin_server_ts(const mtx::events::collections::TimelineEvents &event); @@ -53,10 +56,10 @@ std::string blurhash(const mtx::events::collections::TimelineEvents &event); std::string mimetype(const mtx::events::collections::TimelineEvents &event); -std::string -in_reply_to_event(const mtx::events::collections::TimelineEvents &event); -std::string -relates_to_event_id(const mtx::events::collections::TimelineEvents &event); +mtx::common::Relations +relations(const mtx::events::collections::TimelineEvents &event); +void +set_relations(mtx::events::collections::TimelineEvents &event, mtx::common::Relations relations); std::string transaction_id(const mtx::events::collections::TimelineEvents &event); diff --git a/src/Olm.cpp b/src/Olm.cpp index 4ccf8ab9be1505b0371ef6b32a22ac3e6c8158f4..54be4751ae3869499bf7bb761bcb5c4eb5019177 100644 --- a/src/Olm.cpp +++ b/src/Olm.cpp @@ -575,29 +575,19 @@ encrypt_group_message(const std::string &room_id, const std::string &device_id, if (!sendSessionTo.empty()) olm::send_encrypted_to_device_messages(sendSessionTo, megolm_payload); - mtx::common::ReplyRelatesTo relation; - mtx::common::RelatesTo r_relation; - // relations shouldn't be encrypted... - if (body["content"].contains("m.relates_to")) { - if (body["content"]["m.relates_to"].contains("m.in_reply_to")) { - relation = body["content"]["m.relates_to"]; - } else if (body["content"]["m.relates_to"].contains("event_id")) { - r_relation = body["content"]["m.relates_to"]; - } - } + mtx::common::Relations relations = mtx::common::parse_relations(body["content"]); auto payload = olm::client()->encrypt_group_message(session.get(), body.dump()); // Prepare the m.room.encrypted event. msg::Encrypted data; - data.ciphertext = std::string((char *)payload.data(), payload.size()); - data.sender_key = olm::client()->identity_keys().curve25519; - data.session_id = mtx::crypto::session_id(session.get()); - data.device_id = device_id; - data.algorithm = MEGOLM_ALGO; - data.relates_to = relation; - data.r_relates_to = r_relation; + data.ciphertext = std::string((char *)payload.data(), payload.size()); + data.sender_key = olm::client()->identity_keys().curve25519; + data.session_id = mtx::crypto::session_id(session.get()); + data.device_id = device_id; + data.algorithm = MEGOLM_ALGO; + data.relations = relations; group_session_data.message_index = olm_outbound_group_session_message_index(session.get()); nhlog::crypto()->debug("next message_index {}", group_session_data.message_index); @@ -910,8 +900,7 @@ decryptEvent(const MegolmSessionIndex &index, body["unsigned"] = event.unsigned_data; // relations are unencrypted in content... - if (json old_ev = event; old_ev["content"].count("m.relates_to") != 0) - body["content"]["m.relates_to"] = old_ev["content"]["m.relates_to"]; + mtx::common::add_relations(body["content"], event.content.relations); mtx::events::collections::TimelineEvent te; try { diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index 96c07d7c54517027e929e00b091ceba52403cbe1..b6fdf5043f444436e8b64e54b42014a5479632a7 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -39,12 +39,12 @@ #include <QtQml> #include "Cache.h" +#include "CallDevices.h" #include "Config.h" #include "MatrixClient.h" #include "Olm.h" #include "UserSettingsPage.h" #include "Utils.h" -#include "WebRTCSession.h" #include "ui/FlatButton.h" #include "ui/ToggleButton.h" @@ -115,8 +115,8 @@ UserSettings::load(std::optional<QString> profile) cameraFrameRate_ = settings.value("user/camera_frame_rate", QString()).toString(); useStunServer_ = settings.value("user/use_stun_server", false).toBool(); - if (profile) - profile_ = *profile; + if (profile) // set to "" if it's the default to maintain compatibility + profile_ = (*profile == "default") ? "" : *profile; else profile_ = settings.value("user/currentProfile", "").toString(); @@ -341,7 +341,13 @@ UserSettings::setEmojiFontFamily(QString family) { if (family == emojiFont_) return; - emojiFont_ = family; + + if (family == tr("Default")) { + emojiFont_ = "default"; + } else { + emojiFont_ = family; + } + emit emojiFontChanged(family); save(); } @@ -725,11 +731,15 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge // TODO: Is there a way to limit to just emojis, rather than // all emoji fonts? auto emojiFamilies = fontDb.families(QFontDatabase::Symbol); + emojiFontSelectionCombo_->addItem(tr("Default")); for (const auto &family : emojiFamilies) { emojiFontSelectionCombo_->addItem(family); } - fontSelectionCombo_->setCurrentIndex(fontSelectionCombo_->findText(settings_->font())); + QString currentFont = settings_->font(); + if (currentFont != "default" || currentFont != "") { + fontSelectionCombo_->setCurrentIndex(fontSelectionCombo_->findText(currentFont)); + } emojiFontSelectionCombo_->setCurrentIndex( emojiFontSelectionCombo_->findText(settings_->emojiFont())); @@ -1060,7 +1070,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge [this](const QString &camera) { settings_->setCamera(camera); std::vector<std::string> resolutions = - WebRTCSession::instance().getResolutions(camera.toStdString()); + CallDevices::instance().resolutions(camera.toStdString()); cameraResolutionCombo_->clear(); for (const auto &resolution : resolutions) cameraResolutionCombo_->addItem(QString::fromStdString(resolution)); @@ -1070,9 +1080,8 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), [this](const QString &resolution) { settings_->setCameraResolution(resolution); - std::vector<std::string> frameRates = - WebRTCSession::instance().getFrameRates(settings_->camera().toStdString(), - resolution.toStdString()); + std::vector<std::string> frameRates = CallDevices::instance().frameRates( + settings_->camera().toStdString(), resolution.toStdString()); cameraFrameRateCombo_->clear(); for (const auto &frameRate : frameRates) cameraFrameRateCombo_->addItem(QString::fromStdString(frameRate)); @@ -1231,9 +1240,8 @@ UserSettingsPage::showEvent(QShowEvent *) timelineMaxWidthSpin_->setValue(settings_->timelineMaxWidth()); privacyScreenTimeout_->setValue(settings_->privacyScreenTimeout()); - WebRTCSession::instance().refreshDevices(); - auto mics = - WebRTCSession::instance().getDeviceNames(false, settings_->microphone().toStdString()); + CallDevices::instance().refresh(); + auto mics = CallDevices::instance().names(false, settings_->microphone().toStdString()); microphoneCombo_->clear(); for (const auto &m : mics) microphoneCombo_->addItem(QString::fromStdString(m)); @@ -1241,8 +1249,7 @@ UserSettingsPage::showEvent(QShowEvent *) auto cameraResolution = settings_->cameraResolution(); auto cameraFrameRate = settings_->cameraFrameRate(); - auto cameras = - WebRTCSession::instance().getDeviceNames(true, settings_->camera().toStdString()); + auto cameras = CallDevices::instance().names(true, settings_->camera().toStdString()); cameraCombo_->clear(); for (const auto &c : cameras) cameraCombo_->addItem(QString::fromStdString(c)); diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h index b65e1efcf36c6b7426c0a0001ca91d9a2d9e1842..49de94b3b8f37a92eff6db5337224434370334c4 100644 --- a/src/UserSettingsPage.h +++ b/src/UserSettingsPage.h @@ -177,7 +177,14 @@ public: int timelineMaxWidth() const { return timelineMaxWidth_; } double fontSize() const { return baseFontSize_; } QString font() const { return font_; } - QString emojiFont() const { return emojiFont_; } + QString emojiFont() const + { + if (emojiFont_ == "Default") { + return tr("Default"); + } + + return emojiFont_; + } Presence presence() const { return presence_; } QString ringtone() const { return ringtone_; } QString microphone() const { return microphone_; } diff --git a/src/Utils.cpp b/src/Utils.cpp index 5af5748e9136d4d67bbbb7ff977eee232edab0da..991fa5507f23b917262b4724d4665df307fe239c 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -20,6 +20,7 @@ #include "Cache.h" #include "Config.h" #include "MatrixClient.h" +#include "UserSettingsPage.h" using TimelineEvent = mtx::events::collections::TimelineEvents; @@ -65,14 +66,12 @@ utils::replaceEmoji(const QString &body) QVector<uint> utf32_string = body.toUcs4(); - QSettings settings; - QString userFontFamily = settings.value("user/emoji_font_family", "emoji").toString(); - bool insideFontBlock = false; for (auto &code : utf32_string) { if (utils::codepointIsEmoji(code)) { if (!insideFontBlock) { - fmtBody += QString("<font face=\"" + userFontFamily + "\">"); + fmtBody += QString("<font face=\"" + + UserSettings::instance()->emojiFont() + "\">"); insideFontBlock = true; } @@ -505,13 +504,7 @@ utils::getQuoteBody(const RelatedInfo &related) QString utils::linkColor() { - QSettings settings; - // Default to system theme if QT_QPA_PLATFORMTHEME var is set. - QString defaultTheme = - QProcessEnvironment::systemEnvironment().value("QT_QPA_PLATFORMTHEME", "").isEmpty() - ? "light" - : "system"; - const auto theme = settings.value("user/theme", defaultTheme).toString(); + const auto theme = UserSettings::instance()->theme(); if (theme == "light") { return "#0077b5"; diff --git a/src/WebRTCSession.cpp b/src/WebRTCSession.cpp index d306007d15196492f2b620f3a817441be6d0d10d..b6d980587f30c9c5958b551d3fa44790dc75fe7c 100644 --- a/src/WebRTCSession.cpp +++ b/src/WebRTCSession.cpp @@ -35,6 +35,7 @@ using webrtc::State; WebRTCSession::WebRTCSession() : QObject() + , devices_(CallDevices::instance()) { qRegisterMetaType<webrtc::State>(); qmlRegisterUncreatableMetaObject( @@ -68,9 +69,7 @@ WebRTCSession::init(std::string *errorMessage) gchar *version = gst_version_string(); nhlog::ui()->info("WebRTC: initialised {}", version); g_free(version); -#if GST_CHECK_VERSION(1, 18, 0) - startDeviceMonitor(); -#endif + devices_.init(); return true; #else (void)errorMessage; @@ -81,195 +80,17 @@ WebRTCSession::init(std::string *errorMessage) #ifdef GSTREAMER_AVAILABLE namespace { -struct AudioSource -{ - std::string name; - GstDevice *device; -}; - -struct VideoSource -{ - struct Caps - { - std::string resolution; - std::vector<std::string> frameRates; - }; - std::string name; - GstDevice *device; - std::vector<Caps> caps; -}; - std::string localsdp_; std::vector<mtx::events::msg::CallCandidates::Candidate> localcandidates_; bool haveAudioStream_; bool haveVideoStream_; -std::vector<AudioSource> audioSources_; -std::vector<VideoSource> videoSources_; GstPad *insetSinkPad_ = nullptr; -using FrameRate = std::pair<int, int>; -std::optional<FrameRate> -getFrameRate(const GValue *value) -{ - if (GST_VALUE_HOLDS_FRACTION(value)) { - gint num = gst_value_get_fraction_numerator(value); - gint den = gst_value_get_fraction_denominator(value); - return FrameRate{num, den}; - } - return std::nullopt; -} - -void -addFrameRate(std::vector<std::string> &rates, const FrameRate &rate) -{ - constexpr double minimumFrameRate = 15.0; - if (static_cast<double>(rate.first) / rate.second >= minimumFrameRate) - rates.push_back(std::to_string(rate.first) + "/" + std::to_string(rate.second)); -} - -std::pair<int, int> -tokenise(std::string_view str, char delim) -{ - std::pair<int, int> ret; - ret.first = std::atoi(str.data()); - auto pos = str.find_first_of(delim); - ret.second = std::atoi(str.data() + pos + 1); - return ret; -} - -void -addDevice(GstDevice *device) -{ - if (!device) - return; - - gchar *name = gst_device_get_display_name(device); - gchar *type = gst_device_get_device_class(device); - bool isVideo = !std::strncmp(type, "Video", 5); - g_free(type); - nhlog::ui()->debug("WebRTC: {} device added: {}", isVideo ? "video" : "audio", name); - if (!isVideo) { - audioSources_.push_back({name, device}); - g_free(name); - return; - } - - GstCaps *gstcaps = gst_device_get_caps(device); - if (!gstcaps) { - nhlog::ui()->debug("WebRTC: unable to get caps for {}", name); - g_free(name); - return; - } - - VideoSource source{name, device, {}}; - g_free(name); - guint nCaps = gst_caps_get_size(gstcaps); - for (guint i = 0; i < nCaps; ++i) { - GstStructure *structure = gst_caps_get_structure(gstcaps, i); - const gchar *name = gst_structure_get_name(structure); - if (!std::strcmp(name, "video/x-raw")) { - gint widthpx, heightpx; - if (gst_structure_get(structure, - "width", - G_TYPE_INT, - &widthpx, - "height", - G_TYPE_INT, - &heightpx, - nullptr)) { - VideoSource::Caps caps; - caps.resolution = - std::to_string(widthpx) + "x" + std::to_string(heightpx); - const GValue *value = - gst_structure_get_value(structure, "framerate"); - if (auto fr = getFrameRate(value); fr) - addFrameRate(caps.frameRates, *fr); - else if (GST_VALUE_HOLDS_FRACTION_RANGE(value)) { - const GValue *minRate = - gst_value_get_fraction_range_min(value); - if (auto fr = getFrameRate(minRate); fr) - addFrameRate(caps.frameRates, *fr); - const GValue *maxRate = - gst_value_get_fraction_range_max(value); - if (auto fr = getFrameRate(maxRate); fr) - addFrameRate(caps.frameRates, *fr); - } else if (GST_VALUE_HOLDS_LIST(value)) { - guint nRates = gst_value_list_get_size(value); - for (guint j = 0; j < nRates; ++j) { - const GValue *rate = - gst_value_list_get_value(value, j); - if (auto fr = getFrameRate(rate); fr) - addFrameRate(caps.frameRates, *fr); - } - } - if (!caps.frameRates.empty()) - source.caps.push_back(std::move(caps)); - } - } - } - gst_caps_unref(gstcaps); - videoSources_.push_back(std::move(source)); -} - -#if GST_CHECK_VERSION(1, 18, 0) -template<typename T> -bool -removeDevice(T &sources, GstDevice *device, bool changed) -{ - if (auto it = std::find_if(sources.begin(), - sources.end(), - [device](const auto &s) { return s.device == device; }); - it != sources.end()) { - nhlog::ui()->debug(std::string("WebRTC: device ") + - (changed ? "changed: " : "removed: ") + "{}", - it->name); - gst_object_unref(device); - sources.erase(it); - return true; - } - return false; -} - -void -removeDevice(GstDevice *device, bool changed) -{ - if (device) { - if (removeDevice(audioSources_, device, changed) || - removeDevice(videoSources_, device, changed)) - return; - } -} -#endif - gboolean newBusMessage(GstBus *bus G_GNUC_UNUSED, GstMessage *msg, gpointer user_data) { WebRTCSession *session = static_cast<WebRTCSession *>(user_data); switch (GST_MESSAGE_TYPE(msg)) { -#if GST_CHECK_VERSION(1, 18, 0) - case GST_MESSAGE_DEVICE_ADDED: { - GstDevice *device; - gst_message_parse_device_added(msg, &device); - addDevice(device); - emit WebRTCSession::instance().devicesChanged(); - break; - } - case GST_MESSAGE_DEVICE_REMOVED: { - GstDevice *device; - gst_message_parse_device_removed(msg, &device); - removeDevice(device, false); - emit WebRTCSession::instance().devicesChanged(); - break; - } - case GST_MESSAGE_DEVICE_CHANGED: { - GstDevice *device; - GstDevice *oldDevice; - gst_message_parse_device_changed(msg, &device, &oldDevice); - removeDevice(oldDevice, true); - addDevice(device); - break; - } -#endif case GST_MESSAGE_EOS: nhlog::ui()->error("WebRTC: end of stream"); session->end(); @@ -724,27 +545,6 @@ getMediaAttributes(const GstSDPMessage *sdp, return false; } -template<typename T> -std::vector<std::string> -deviceNames(T &sources, const std::string &defaultDevice) -{ - std::vector<std::string> ret; - ret.reserve(sources.size()); - std::transform(sources.cbegin(), - sources.cend(), - std::back_inserter(ret), - [](const auto &s) { return s.name; }); - - // move default device to top of the list - if (auto it = std::find_if(ret.begin(), - ret.end(), - [&defaultDevice](const auto &s) { return s == defaultDevice; }); - it != ret.end()) - std::swap(ret.front(), *it); - - return ret; -} - } bool @@ -995,19 +795,11 @@ WebRTCSession::startPipeline(int opusPayloadType, int vp8PayloadType) bool WebRTCSession::createPipeline(int opusPayloadType, int vp8PayloadType) { - std::string microphoneSetting = - ChatPage::instance()->userSettings()->microphone().toStdString(); - auto it = - std::find_if(audioSources_.cbegin(), - audioSources_.cend(), - [µphoneSetting](const auto &s) { return s.name == microphoneSetting; }); - if (it == audioSources_.cend()) { - nhlog::ui()->error("WebRTC: unknown microphone: {}", microphoneSetting); + GstDevice *device = devices_.audioDevice(); + if (!device) return false; - } - nhlog::ui()->debug("WebRTC: microphone: {}", microphoneSetting); - GstElement *source = gst_device_create_element(it->device, nullptr); + GstElement *source = gst_device_create_element(device, nullptr); GstElement *volume = gst_element_factory_make("volume", "srclevel"); GstElement *convert = gst_element_factory_make("audioconvert", nullptr); GstElement *resample = gst_element_factory_make("audioresample", nullptr); @@ -1070,30 +862,16 @@ bool WebRTCSession::addVideoPipeline(int vp8PayloadType) { // allow incoming video calls despite localUser having no webcam - if (videoSources_.empty()) + if (!devices_.haveCamera()) return !isOffering_; - QSharedPointer<UserSettings> settings = ChatPage::instance()->userSettings(); - std::string cameraSetting = settings->camera().toStdString(); - auto it = std::find_if(videoSources_.cbegin(), - videoSources_.cend(), - [&cameraSetting](const auto &s) { return s.name == cameraSetting; }); - if (it == videoSources_.cend()) { - nhlog::ui()->error("WebRTC: unknown camera: {}", cameraSetting); + std::pair<int, int> resolution; + std::pair<int, int> frameRate; + GstDevice *device = devices_.videoDevice(resolution, frameRate); + if (!device) return false; - } - std::string resSetting = settings->cameraResolution().toStdString(); - const std::string &res = resSetting.empty() ? it->caps.front().resolution : resSetting; - std::string frSetting = settings->cameraFrameRate().toStdString(); - const std::string &fr = frSetting.empty() ? it->caps.front().frameRates.front() : frSetting; - auto resolution = tokenise(res, 'x'); - auto frameRate = tokenise(fr, '/'); - nhlog::ui()->debug("WebRTC: camera: {}", cameraSetting); - nhlog::ui()->debug("WebRTC: camera resolution: {}x{}", resolution.first, resolution.second); - nhlog::ui()->debug("WebRTC: camera frame rate: {}/{}", frameRate.first, frameRate.second); - - GstElement *source = gst_device_create_element(it->device, nullptr); + GstElement *source = gst_device_create_element(device, nullptr); GstElement *videoconvert = gst_element_factory_make("videoconvert", nullptr); GstElement *capsfilter = gst_element_factory_make("capsfilter", "camerafilter"); GstCaps *caps = gst_caps_new_simple("video/x-raw", @@ -1239,111 +1017,6 @@ WebRTCSession::end() emit stateChanged(State::DISCONNECTED); } -#if GST_CHECK_VERSION(1, 18, 0) -void -WebRTCSession::startDeviceMonitor() -{ - if (!initialised_) - return; - - static GstDeviceMonitor *monitor = nullptr; - if (!monitor) { - monitor = gst_device_monitor_new(); - GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw"); - gst_device_monitor_add_filter(monitor, "Audio/Source", caps); - gst_caps_unref(caps); - caps = gst_caps_new_empty_simple("video/x-raw"); - gst_device_monitor_add_filter(monitor, "Video/Source", caps); - gst_caps_unref(caps); - - GstBus *bus = gst_device_monitor_get_bus(monitor); - gst_bus_add_watch(bus, newBusMessage, nullptr); - gst_object_unref(bus); - if (!gst_device_monitor_start(monitor)) { - nhlog::ui()->error("WebRTC: failed to start device monitor"); - return; - } - } -} -#endif - -void -WebRTCSession::refreshDevices() -{ -#if GST_CHECK_VERSION(1, 18, 0) - return; -#else - if (!initialised_) - return; - - static GstDeviceMonitor *monitor = nullptr; - if (!monitor) { - monitor = gst_device_monitor_new(); - GstCaps *caps = gst_caps_new_empty_simple("audio/x-raw"); - gst_device_monitor_add_filter(monitor, "Audio/Source", caps); - gst_caps_unref(caps); - caps = gst_caps_new_empty_simple("video/x-raw"); - gst_device_monitor_add_filter(monitor, "Video/Source", caps); - gst_caps_unref(caps); - } - - auto clearDevices = [](auto &sources) { - std::for_each( - sources.begin(), sources.end(), [](auto &s) { gst_object_unref(s.device); }); - sources.clear(); - }; - clearDevices(audioSources_); - clearDevices(videoSources_); - - GList *devices = gst_device_monitor_get_devices(monitor); - if (devices) { - for (GList *l = devices; l != nullptr; l = l->next) - addDevice(GST_DEVICE_CAST(l->data)); - g_list_free(devices); - } - emit devicesChanged(); -#endif -} - -std::vector<std::string> -WebRTCSession::getDeviceNames(bool isVideo, const std::string &defaultDevice) const -{ - return isVideo ? deviceNames(videoSources_, defaultDevice) - : deviceNames(audioSources_, defaultDevice); -} - -std::vector<std::string> -WebRTCSession::getResolutions(const std::string &cameraName) const -{ - std::vector<std::string> ret; - if (auto it = std::find_if(videoSources_.cbegin(), - videoSources_.cend(), - [&cameraName](const auto &s) { return s.name == cameraName; }); - it != videoSources_.cend()) { - ret.reserve(it->caps.size()); - for (const auto &c : it->caps) - ret.push_back(c.resolution); - } - return ret; -} - -std::vector<std::string> -WebRTCSession::getFrameRates(const std::string &cameraName, const std::string &resolution) const -{ - if (auto i = std::find_if(videoSources_.cbegin(), - videoSources_.cend(), - [&](const auto &s) { return s.name == cameraName; }); - i != videoSources_.cend()) { - if (auto j = - std::find_if(i->caps.cbegin(), - i->caps.cend(), - [&](const auto &s) { return s.resolution == resolution; }); - j != i->caps.cend()) - return j->frameRates; - } - return {}; -} - #else bool @@ -1400,25 +1073,4 @@ void WebRTCSession::end() {} -void -WebRTCSession::refreshDevices() -{} - -std::vector<std::string> -WebRTCSession::getDeviceNames(bool, const std::string &) const -{ - return {}; -} - -std::vector<std::string> -WebRTCSession::getResolutions(const std::string &) const -{ - return {}; -} - -std::vector<std::string> -WebRTCSession::getFrameRates(const std::string &, const std::string &) const -{ - return {}; -} #endif diff --git a/src/WebRTCSession.h b/src/WebRTCSession.h index 2f0fb70ef8fcca8684c54055d76a1b5591a3e5fc..0fe8a864853599a97da5f425782c73132bebb75d 100644 --- a/src/WebRTCSession.h +++ b/src/WebRTCSession.h @@ -5,6 +5,7 @@ #include <QObject> +#include "CallDevices.h" #include "mtx/events/voip.hpp" typedef struct _GstElement GstElement; @@ -59,13 +60,6 @@ public: void setTurnServers(const std::vector<std::string> &uris) { turnServers_ = uris; } - void refreshDevices(); - std::vector<std::string> getDeviceNames(bool isVideo, - const std::string &defaultDevice) const; - std::vector<std::string> getResolutions(const std::string &cameraName) const; - std::vector<std::string> getFrameRates(const std::string &cameraName, - const std::string &resolution) const; - void setVideoItem(QQuickItem *item) { videoItem_ = item; } QQuickItem *getVideoItem() const { return videoItem_; } @@ -76,7 +70,6 @@ signals: const std::vector<mtx::events::msg::CallCandidates::Candidate> &); void newICECandidate(const mtx::events::msg::CallCandidates::Candidate &); void stateChanged(webrtc::State); - void devicesChanged(); private slots: void setState(webrtc::State state) { state_ = state; } @@ -84,6 +77,7 @@ private slots: private: WebRTCSession(); + CallDevices &devices_; bool initialised_ = false; bool haveVoicePlugins_ = false; bool haveVideoPlugins_ = false; @@ -101,7 +95,6 @@ private: bool startPipeline(int opusPayloadType, int vp8PayloadType); bool createPipeline(int opusPayloadType, int vp8PayloadType); bool addVideoPipeline(int vp8PayloadType); - void startDeviceMonitor(); public: WebRTCSession(WebRTCSession const &) = delete; diff --git a/src/main.cpp b/src/main.cpp index a890a6fd5b7d477951af1e1f9d75b06ee9d58b96..0c7c9f6062d6daee40d0c498b23a38865a2396d0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -128,7 +128,7 @@ main(int argc, char *argv[]) // parsed before the SingleApplication userdata is set. QString userdata{""}; QString matrixUri; - for (int i = 0; i < argc; ++i) { + for (int i = 1; i < argc; ++i) { QString arg{argv[i]}; if (arg.startsWith("--profile=")) { arg.remove("--profile="); @@ -214,7 +214,7 @@ main(int argc, char *argv[]) QFont font; QString userFontFamily = settings.lock()->font(); - if (!userFontFamily.isEmpty()) { + if (!userFontFamily.isEmpty() && userFontFamily != "default") { font.setFamily(userFontFamily); } font.setPointSizeF(settings.lock()->fontSize()); diff --git a/src/notifications/Manager.h b/src/notifications/Manager.h index 4c9852ccf1942cf80e621563fa5df3cffb165df7..950740ba80739dab658505a8e08c2ab7c3599e65 100644 --- a/src/notifications/Manager.h +++ b/src/notifications/Manager.h @@ -4,7 +4,9 @@ #include <QObject> #include <QString> -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) +#include <mtx/responses/notifications.hpp> + +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_HAIKU) #include <QtDBus/QDBusArgument> #include <QtDBus/QDBusInterface> #endif @@ -27,12 +29,7 @@ class NotificationsManager : public QObject public: NotificationsManager(QObject *parent = nullptr); - void postNotification(const QString &roomId, - const QString &eventId, - const QString &roomName, - const QString &senderName, - const QString &text, - const QImage &icon); + void postNotification(const mtx::responses::Notification ¬ification, const QImage &icon); signals: void notificationClicked(const QString roomId, const QString eventId); @@ -41,7 +38,7 @@ signals: public slots: void removeNotification(const QString &roomId, const QString &eventId); -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_HAIKU) public: void closeNotifications(QString roomId); @@ -61,7 +58,7 @@ private slots: void notificationReplied(uint id, QString reply); }; -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_HAIKU) QDBusArgument & operator<<(QDBusArgument &arg, const QImage &image); const QDBusArgument & diff --git a/src/notifications/ManagerLinux.cpp b/src/notifications/ManagerLinux.cpp index 8f7261e64e9a274139be4e594f95397639517360..fb424b2a2396cb663a8e4f88851ef4b4820b5d31 100644 --- a/src/notifications/ManagerLinux.cpp +++ b/src/notifications/ManagerLinux.cpp @@ -8,6 +8,12 @@ #include <QDebug> #include <QImage> +#include "Cache.h" +#include "EventAccessors.h" +#include "MatrixClient.h" +#include "Utils.h" +#include <mtx/responses/notifications.hpp> + NotificationsManager::NotificationsManager(QObject *parent) : QObject(parent) , dbus("org.freedesktop.Notifications", @@ -45,22 +51,31 @@ NotificationsManager::NotificationsManager(QObject *parent) * Licensed under the GNU General Public License, version 3 */ void -NotificationsManager::postNotification(const QString &roomid, - const QString &eventid, - const QString &roomname, - const QString &sender, - const QString &text, +NotificationsManager::postNotification(const mtx::responses::Notification ¬ification, const QImage &icon) { + const auto room_id = QString::fromStdString(notification.room_id); + const auto event_id = QString::fromStdString(mtx::accessors::event_id(notification.event)); + const auto sender = cache::displayName( + room_id, QString::fromStdString(mtx::accessors::sender(notification.event))); + const auto text = utils::event_body(notification.event); + QVariantMap hints; hints["image-data"] = icon; hints["sound-name"] = "message-new-instant"; QList<QVariant> argumentList; - argumentList << "nheko"; // app_name - argumentList << (uint)0; // replace_id - argumentList << ""; // app_icon - argumentList << roomname; // summary - argumentList << sender + ": " + text; // body + argumentList << "nheko"; // app_name + argumentList << (uint)0; // replace_id + argumentList << ""; // app_icon + argumentList << QString::fromStdString( + cache::singleRoomInfo(notification.room_id).name); // summary + + // body + if (mtx::accessors::msg_type(notification.event) == mtx::events::MessageType::Emote) + argumentList << "* " + sender + " " + text; + else + argumentList << sender + ": " + text; + // The list of actions has always the action name and then a localized version of that // action. Currently we just use an empty string for that. // TODO(Nico): Look into what to actually put there. @@ -76,12 +91,12 @@ NotificationsManager::postNotification(const QString &roomid, QDBusPendingCall call = notifyApp.asyncCallWithArgumentList("Notify", argumentList); auto watcher = new QDBusPendingCallWatcher{call, this}; connect( - watcher, &QDBusPendingCallWatcher::finished, this, [watcher, this, roomid, eventid]() { + watcher, &QDBusPendingCallWatcher::finished, this, [watcher, this, room_id, event_id]() { if (watcher->reply().type() == QDBusMessage::ErrorMessage) qDebug() << "D-Bus Error:" << watcher->reply().errorMessage(); else notificationIds[watcher->reply().arguments().first().toUInt()] = - roomEventId{roomid, eventid}; + roomEventId{room_id, event_id}; watcher->deleteLater(); }); } diff --git a/src/notifications/ManagerMac.mm b/src/notifications/ManagerMac.mm index c09e894c841c48240ae7eb6d5a7407792500e2f0..5609d3dea7588001c25590f30c17e56c57700609 100644 --- a/src/notifications/ManagerMac.mm +++ b/src/notifications/ManagerMac.mm @@ -3,6 +3,12 @@ #include <Foundation/Foundation.h> #include <QtMac> +#include "Cache.h" +#include "EventAccessors.h" +#include "MatrixClient.h" +#include "Utils.h" +#include <mtx/responses/notifications.hpp> + @interface NSUserNotification (CFIPrivate) - (void)set_identityImage:(NSImage *)image; @end @@ -13,23 +19,22 @@ NotificationsManager::NotificationsManager(QObject *parent): QObject(parent) } void -NotificationsManager::postNotification( - const QString &roomId, - const QString &eventId, - const QString &roomName, - const QString &senderName, - const QString &text, - const QImage &icon) +NotificationsManager::postNotification(const mtx::responses::Notification ¬ification, + const QImage &icon) { - Q_UNUSED(roomId); - Q_UNUSED(eventId); Q_UNUSED(icon); + const auto sender = cache::displayName(QString::fromStdString(notification.room_id), QString::fromStdString(mtx::accessors::sender(notification.event))); + const auto text = utils::event_body(notification.event); + NSUserNotification * notif = [[NSUserNotification alloc] init]; - notif.title = roomName.toNSString(); - notif.subtitle = QString("%1 sent a message").arg(senderName).toNSString(); - notif.informativeText = text.toNSString(); + notif.title = QString::fromStdString(cache::singleRoomInfo(notification.room_id).name).toNSString(); + notif.subtitle = QString("%1 sent a message").arg(sender).toNSString(); + if (mtx::accessors::msg_type(notification.event) == mtx::events::MessageType::Emote) + notif.informativeText = QString("* ").append(sender).append(" ").append(text).toNSString(); + else + notif.informativeText = text.toNSString(); notif.soundName = NSUserNotificationDefaultSoundName; [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification: notif]; diff --git a/src/notifications/ManagerWin.cpp b/src/notifications/ManagerWin.cpp index cc61c6455e7f6319fae08b970bd0a09403eefd32..85abe642180d1b2ac7597b0d8775645d24e763af 100644 --- a/src/notifications/ManagerWin.cpp +++ b/src/notifications/ManagerWin.cpp @@ -1,6 +1,12 @@ #include "notifications/Manager.h" #include "wintoastlib.h" +#include "Cache.h" +#include "EventAccessors.h" +#include "MatrixClient.h" +#include "Utils.h" +#include <mtx/responses/notifications.hpp> + using namespace WinToastLib; class CustomHandler : public IWinToastHandler @@ -23,7 +29,7 @@ init() WinToast::instance()->setAppName(L"Nheko"); WinToast::instance()->setAppUserModelId(WinToast::configureAUMI(L"nheko", L"nheko")); if (!WinToast::instance()->initialize()) - std::wcout << "Your system in not compatible with toast notifications\n"; + std::wcout << "Your system is not compatible with toast notifications\n"; } } @@ -32,17 +38,18 @@ NotificationsManager::NotificationsManager(QObject *parent) {} void -NotificationsManager::postNotification(const QString &room_id, - const QString &event_id, - const QString &room_name, - const QString &sender, - const QString &text, +NotificationsManager::postNotification(const mtx::responses::Notification ¬ification, const QImage &icon) { - Q_UNUSED(room_id) - Q_UNUSED(event_id) Q_UNUSED(icon) + const auto room_name = + QString::fromStdString(cache::singleRoomInfo(notification.room_id).name); + const auto sender = + cache::displayName(QString::fromStdString(notification.room_id), + QString::fromStdString(mtx::accessors::sender(notification.event))); + const auto text = utils::event_body(notification.event); + if (!isInitialized) init(); @@ -53,7 +60,13 @@ NotificationsManager::postNotification(const QString &room_id, else templ.setTextField(QString("%1").arg(sender).toStdWString(), WinToastTemplate::FirstLine); - templ.setTextField(QString("%1").arg(text).toStdWString(), WinToastTemplate::SecondLine); + if (mtx::accessors::msg_type(notification.event) == mtx::events::MessageType::Emote) + templ.setTextField( + QString("* ").append(sender).append(" ").append(text).toStdWString(), + WinToastTemplate::SecondLine); + else + templ.setTextField(QString("%1").arg(text).toStdWString(), + WinToastTemplate::SecondLine); // TODO: implement room or user avatar // templ.setImagePath(L"C:/example.png"); diff --git a/src/timeline/DelegateChooser.cpp b/src/timeline/DelegateChooser.cpp index 1f5fae7e89a58eb3b8c66f468192899fe5be1daf..8598fa7725d2e1c53cd30b98ec48389574fad979 100644 --- a/src/timeline/DelegateChooser.cpp +++ b/src/timeline/DelegateChooser.cpp @@ -123,10 +123,6 @@ DelegateChooser::DelegateIncubator::statusChanged(QQmlIncubator::Status status) } chooser.child_->setParentItem(&chooser); - connect(chooser.child_, &QQuickItem::heightChanged, &chooser, [this]() { - chooser.setHeight(chooser.child_->height()); - }); - chooser.setHeight(chooser.child_->height()); QQmlEngine::setObjectOwnership(chooser.child_, QQmlEngine::ObjectOwnership::JavaScriptOwnership); emit chooser.childChanged(); diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index be4bc09e10de36928c6dcbbf3c7d6aa1d5246562..94d43a835a09d773f18de40312ead6f0a388bddd 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -293,16 +293,16 @@ EventStore::handleSync(const mtx::responses::Timeline &events) } for (const auto &event : events.events) { - std::string relates_to; + std::set<std::string> relates_to; if (auto redaction = std::get_if<mtx::events::RedactionEvent<mtx::events::msg::Redaction>>( &event)) { // fixup reactions auto redacted = events_by_id_.object({room_id_, redaction->redacts}); if (redacted) { - auto id = mtx::accessors::relates_to_event_id(*redacted); - if (!id.empty()) { - auto idx = idToIndex(id); + auto id = mtx::accessors::relations(*redacted); + if (id.annotates()) { + auto idx = idToIndex(id.annotates()->event_id); if (idx) { events_by_id_.remove( {room_id_, redaction->redacts}); @@ -312,20 +312,17 @@ EventStore::handleSync(const mtx::responses::Timeline &events) } } - relates_to = redaction->redacts; - } else if (auto reaction = - std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>( - &event)) { - relates_to = reaction->content.relates_to.event_id; + relates_to.insert(redaction->redacts); } else { - relates_to = mtx::accessors::in_reply_to_event(event); + for (const auto &r : mtx::accessors::relations(event).relations) + relates_to.insert(r.event_id); } - if (!relates_to.empty()) { - auto idx = cache::client()->getTimelineIndex(room_id_, relates_to); + for (const auto &relates_to_id : relates_to) { + auto idx = cache::client()->getTimelineIndex(room_id_, relates_to_id); if (idx) { - events_by_id_.remove({room_id_, relates_to}); - decryptedEvents_.remove({room_id_, relates_to}); + events_by_id_.remove({room_id_, relates_to_id}); + decryptedEvents_.remove({room_id_, relates_to_id}); events_.remove({room_id_, *idx}); emit dataChanged(toExternalIdx(*idx), toExternalIdx(*idx)); } @@ -408,6 +405,52 @@ EventStore::handle_room_verification(mtx::events::collections::TimelineEvents ev event); } +std::vector<mtx::events::collections::TimelineEvents> +EventStore::edits(const std::string &event_id) +{ + auto event_ids = cache::client()->relatedEvents(room_id_, event_id); + + auto original_event = get(event_id, "", false, false); + if (!original_event) + return {}; + + auto original_sender = mtx::accessors::sender(*original_event); + auto original_relations = mtx::accessors::relations(*original_event); + + std::vector<mtx::events::collections::TimelineEvents> edits; + for (const auto &id : event_ids) { + auto related_event = get(id, event_id, false, false); + if (!related_event) + continue; + + auto related_ev = *related_event; + + auto edit_rel = mtx::accessors::relations(related_ev); + if (edit_rel.replaces() == event_id && + original_sender == mtx::accessors::sender(related_ev)) { + if (edit_rel.synthesized && original_relations.reply_to() && + !edit_rel.reply_to()) { + edit_rel.relations.push_back( + {mtx::common::RelationType::InReplyTo, + original_relations.reply_to().value()}); + mtx::accessors::set_relations(related_ev, std::move(edit_rel)); + } + edits.push_back(std::move(related_ev)); + } + } + + auto c = cache::client(); + std::sort(edits.begin(), + edits.end(), + [this, c](const mtx::events::collections::TimelineEvents &a, + const mtx::events::collections::TimelineEvents &b) { + return c->getArrivalIndex(this->room_id_, mtx::accessors::event_id(a)) < + c->getArrivalIndex(this->room_id_, mtx::accessors::event_id(b)); + }); + + return edits; +} + QVariantList EventStore::reactions(const std::string &event_id) { @@ -430,13 +473,14 @@ EventStore::reactions(const std::string &event_id) if (auto reaction = std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>( related_event); - reaction && reaction->content.relates_to.key) { - auto &agg = aggregation[reaction->content.relates_to.key.value()]; + reaction && reaction->content.relations.annotates() && + reaction->content.relations.annotates()->key) { + auto key = reaction->content.relations.annotates()->key.value(); + auto &agg = aggregation[key]; if (agg.count == 0) { Reaction temp{}; - temp.key_ = - QString::fromStdString(reaction->content.relates_to.key.value()); + temp.key_ = QString::fromStdString(key); reactions.push_back(temp); } @@ -489,7 +533,13 @@ EventStore::get(int idx, bool decrypt) if (!event_id) return nullptr; - auto event = cache::client()->getEvent(room_id_, *event_id); + std::optional<mtx::events::collections::TimelineEvent> event; + auto edits_ = edits(*event_id); + if (edits_.empty()) + event = cache::client()->getEvent(room_id_, *event_id); + else + event = {edits_.back()}; + if (!event) return nullptr; else @@ -691,8 +741,7 @@ EventStore::decryptEvent(const IdIndex &idx, body["unsigned"] = e.unsigned_data; // relations are unencrypted in content... - if (json old_ev = e; old_ev["content"].count("m.relates_to") != 0) - body["content"]["m.relates_to"] = old_ev["content"]["m.relates_to"]; + mtx::common::add_relations(body["content"], e.content.relations); json event_array = json::array(); event_array.push_back(body); @@ -717,7 +766,7 @@ EventStore::decryptEvent(const IdIndex &idx, } mtx::events::collections::TimelineEvents * -EventStore::get(std::string_view id, std::string_view related_to, bool decrypt) +EventStore::get(std::string_view id, std::string_view related_to, bool decrypt, bool resolve_edits) { if (this->thread() != QThread::currentThread()) nhlog::db()->warn("{} called from a different thread!", __func__); @@ -725,7 +774,16 @@ EventStore::get(std::string_view id, std::string_view related_to, bool decrypt) if (id.empty()) return nullptr; - IdIndex index{room_id_, std::string(id.data(), id.size())}; + IdIndex index{room_id_, std::string(id)}; + if (resolve_edits) { + auto edits_ = edits(index.id); + if (!edits_.empty()) { + index.id = mtx::accessors::event_id(edits_.back()); + auto event_ptr = + new mtx::events::collections::TimelineEvents(std::move(edits_.back())); + events_by_id_.insert(index, event_ptr); + } + } auto event_ptr = events_by_id_.object(index); if (!event_ptr) { diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h index f8eff9a9516e7396357a6a2b5279064dbb298e0b..ced7bdc0b5fc81e749105e96754e4a2130aad123 100644 --- a/src/timeline/EventStore.h +++ b/src/timeline/EventStore.h @@ -66,7 +66,8 @@ public: // relatedFetched event mtx::events::collections::TimelineEvents *get(std::string_view id, std::string_view related_to, - bool decrypt = true); + bool decrypt = true, + bool resolve_edits = true); // always returns a proper event as long as the idx is valid mtx::events::collections::TimelineEvents *get(int idx, bool decrypt = true); @@ -110,6 +111,7 @@ public slots: void clearTimeline(); private: + std::vector<mtx::events::collections::TimelineEvents> edits(const std::string &event_id); mtx::events::collections::TimelineEvents *decryptEvent( const IdIndex &idx, const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &e); diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index b31c1f76bdabbed33b259c00164566888a9a44ef..08cbd15b0a3804ee914f1457dc977e3d46ee111e 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -268,7 +268,18 @@ InputBar::message(QString msg, MarkdownOverride useMarkdown) text.format = "org.matrix.custom.html"; } - if (!room->reply().isEmpty()) { + if (!room->edit().isEmpty()) { + if (!room->reply().isEmpty()) { + text.relations.relations.push_back( + {mtx::common::RelationType::InReplyTo, room->reply().toStdString()}); + room->resetReply(); + } + + text.relations.relations.push_back( + {mtx::common::RelationType::Replace, room->edit().toStdString()}); + room->resetEdit(); + + } else if (!room->reply().isEmpty()) { auto related = room->relatedInfo(room->reply()); QString body; @@ -294,7 +305,8 @@ InputBar::message(QString msg, MarkdownOverride useMarkdown) text.formatted_body = utils::getFormattedQuoteBody(related, msg.toHtmlEscaped()).toStdString(); - text.relates_to.in_reply_to.event_id = related.related_event; + text.relations.relations.push_back( + {mtx::common::RelationType::InReplyTo, related.related_event}); room->resetReply(); } @@ -316,9 +328,15 @@ InputBar::emote(QString msg) } if (!room->reply().isEmpty()) { - emote.relates_to.in_reply_to.event_id = room->reply().toStdString(); + emote.relations.relations.push_back( + {mtx::common::RelationType::InReplyTo, room->reply().toStdString()}); room->resetReply(); } + if (!room->edit().isEmpty()) { + emote.relations.relations.push_back( + {mtx::common::RelationType::Replace, room->edit().toStdString()}); + room->resetEdit(); + } room->sendMessageEvent(emote, mtx::events::EventType::RoomMessage); } @@ -346,9 +364,15 @@ InputBar::image(const QString &filename, image.url = url.toStdString(); if (!room->reply().isEmpty()) { - image.relates_to.in_reply_to.event_id = room->reply().toStdString(); + image.relations.relations.push_back( + {mtx::common::RelationType::InReplyTo, room->reply().toStdString()}); room->resetReply(); } + if (!room->edit().isEmpty()) { + image.relations.relations.push_back( + {mtx::common::RelationType::Replace, room->edit().toStdString()}); + room->resetEdit(); + } room->sendMessageEvent(image, mtx::events::EventType::RoomMessage); } @@ -371,9 +395,15 @@ InputBar::file(const QString &filename, file.url = url.toStdString(); if (!room->reply().isEmpty()) { - file.relates_to.in_reply_to.event_id = room->reply().toStdString(); + file.relations.relations.push_back( + {mtx::common::RelationType::InReplyTo, room->reply().toStdString()}); room->resetReply(); } + if (!room->edit().isEmpty()) { + file.relations.relations.push_back( + {mtx::common::RelationType::Replace, room->edit().toStdString()}); + room->resetEdit(); + } room->sendMessageEvent(file, mtx::events::EventType::RoomMessage); } @@ -397,9 +427,15 @@ InputBar::audio(const QString &filename, audio.url = url.toStdString(); if (!room->reply().isEmpty()) { - audio.relates_to.in_reply_to.event_id = room->reply().toStdString(); + audio.relations.relations.push_back( + {mtx::common::RelationType::InReplyTo, room->reply().toStdString()}); room->resetReply(); } + if (!room->edit().isEmpty()) { + audio.relations.relations.push_back( + {mtx::common::RelationType::Replace, room->edit().toStdString()}); + room->resetEdit(); + } room->sendMessageEvent(audio, mtx::events::EventType::RoomMessage); } @@ -422,9 +458,15 @@ InputBar::video(const QString &filename, video.url = url.toStdString(); if (!room->reply().isEmpty()) { - video.relates_to.in_reply_to.event_id = room->reply().toStdString(); + video.relations.relations.push_back( + {mtx::common::RelationType::InReplyTo, room->reply().toStdString()}); room->resetReply(); } + if (!room->edit().isEmpty()) { + video.relations.relations.push_back( + {mtx::common::RelationType::Replace, room->edit().toStdString()}); + room->resetEdit(); + } room->sendMessageEvent(video, mtx::events::EventType::RoomMessage); } @@ -518,6 +560,8 @@ InputBar::showPreview(const QMimeData &source, QString path, const QStringList & [this](const QByteArray data, const QString &mime, const QString &fn) { setUploading(true); + setText(""); + auto payload = std::string(data.data(), data.size()); std::optional<mtx::crypto::EncryptedFile> encryptedFile; if (cache::isRoomEncrypted(room->roomId().toStdString())) { diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index f173bbc06302927b06e26c0d162d8343b21398b2..696a0dd9c144f391bb1a214c900e4f3acc8f455b 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -41,6 +41,7 @@ public slots: QString text() const; QString previousText(); QString nextText(); + void setText(QString newText) { emit textChanged(newText); } void send(); void paste(bool fromMouse); @@ -58,6 +59,7 @@ private slots: signals: void insertText(QString text); + void textChanged(QString newText); void uploadingChanged(bool value); private: diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index efeba146458a9d8a7ccdae649b94949c1b9b99e3..6caac132a3ce12b7f27be23242ba403c660b9551 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -288,6 +288,8 @@ TimelineModel::roleNames() const {ProportionalHeight, "proportionalHeight"}, {Id, "id"}, {State, "state"}, + {IsEdited, "isEdited"}, + {IsEditable, "isEditable"}, {IsEncrypted, "isEncrypted"}, {IsRoomEncrypted, "isRoomEncrypted"}, {ReplyTo, "replyTo"}, @@ -360,7 +362,7 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r const static QRegularExpression replyFallback( "<mx-reply>.*</mx-reply>", QRegularExpression::DotMatchesEverythingOption); - bool isReply = !in_reply_to_event(event).empty(); + bool isReply = relations(event).reply_to().has_value(); auto formattedBody_ = QString::fromStdString(formatted_body(event)); if (formattedBody_.isEmpty()) { @@ -409,8 +411,12 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r return QVariant(prop > 0 ? prop : 1.); } - case Id: - return QVariant(QString::fromStdString(event_id(event))); + case Id: { + if (auto replaces = relations(event).replaces()) + return QVariant(QString::fromStdString(replaces.value())); + else + return QVariant(QString::fromStdString(event_id(event))); + } case State: { auto id = QString::fromStdString(event_id(event)); auto containsOthers = [](const auto &vec) { @@ -430,6 +436,11 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r else return qml_mtx_events::Received; } + case IsEdited: + return QVariant(relations(event).replaces().has_value()); + case IsEditable: + return QVariant(!is_state_event(event) && mtx::accessors::sender(event) == + http::client()->user_id().to_string()); case IsEncrypted: { auto id = event_id(event); auto encrypted_event = events.get(id, id, false); @@ -442,9 +453,9 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r return cache::isRoomEncrypted(room_id_.toStdString()); } case ReplyTo: - return QVariant(QString::fromStdString(in_reply_to_event(event))); + return QVariant(QString::fromStdString(relations(event).reply_to().value_or(""))); case Reactions: { - auto id = event_id(event); + auto id = relations(event).replaces().value_or(event_id(event)); return QVariant::fromValue(events.reactions(id)); } case RoomId: @@ -724,15 +735,30 @@ TimelineModel::updateLastMessage() void TimelineModel::setCurrentIndex(int index) { - if (!ChatPage::instance()->isActiveWindow()) - return; - auto oldIndex = idToIndex(currentId); currentId = indexToId(index); - emit currentIndexChanged(index); + if (index != oldIndex) + emit currentIndexChanged(index); + + if (!ChatPage::instance()->isActiveWindow()) + return; - if ((oldIndex > index || oldIndex == -1) && !currentId.startsWith("m")) { - readEvent(currentId.toStdString()); + if (!currentId.startsWith("m")) { + auto oldReadIndex = + cache::getEventIndex(roomId().toStdString(), currentReadId.toStdString()); + auto nextEventIndexAndId = + cache::lastInvisibleEventAfter(roomId().toStdString(), currentId.toStdString()); + + if (nextEventIndexAndId && + (!oldReadIndex || *oldReadIndex < nextEventIndexAndId->first)) { + readEvent(nextEventIndexAndId->second); + currentReadId = QString::fromStdString(nextEventIndexAndId->second); + + nhlog::net()->info("Marked as read {}, index {}, oldReadIndex {}", + nextEventIndexAndId->second, + nextEventIndexAndId->first, + *oldReadIndex); + } } } @@ -821,6 +847,12 @@ TimelineModel::replyAction(QString id) setReply(id); } +void +TimelineModel::editAction(QString id) +{ + setEdit(id); +} + RelatedInfo TimelineModel::relatedInfo(QString id) { @@ -1509,6 +1541,51 @@ TimelineModel::formatMemberEvent(QString id) return rendered; } +void +TimelineModel::setEdit(QString newEdit) +{ + if (edit_.startsWith('m')) + return; + + if (edit_ != newEdit) { + auto ev = events.get(newEdit.toStdString(), ""); + if (ev && mtx::accessors::sender(*ev) == http::client()->user_id().to_string()) { + auto e = *ev; + setReply(QString::fromStdString( + mtx::accessors::relations(e).reply_to().value_or(""))); + + auto msgType = mtx::accessors::msg_type(e); + if (msgType == mtx::events::MessageType::Text || + msgType == mtx::events::MessageType::Notice) { + input()->setText(relatedInfo(newEdit).quoted_body); + } else if (msgType == mtx::events::MessageType::Emote) { + input()->setText("/me " + relatedInfo(newEdit).quoted_body); + } else { + input()->setText(""); + } + + edit_ = newEdit; + } else { + resetReply(); + + input()->setText(""); + edit_ = ""; + } + emit editChanged(edit_); + } +} + +void +TimelineModel::resetEdit() +{ + if (!edit_.isEmpty()) { + edit_ = ""; + emit editChanged(edit_); + input()->setText(""); + resetReply(); + } +} + QString TimelineModel::roomName() const { diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index df067fd47de0d5b719af61f4e50e854f3ab2798f..5f599741ac4b5ae97a71a792de177cf0caaaa289 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -146,6 +146,7 @@ class TimelineModel : public QAbstractListModel Q_PROPERTY(std::vector<QString> typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY typingUsersChanged) Q_PROPERTY(QString reply READ reply WRITE setReply NOTIFY replyChanged RESET resetReply) + Q_PROPERTY(QString edit READ edit WRITE setEdit NOTIFY editChanged RESET resetEdit) Q_PROPERTY( bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged) Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) @@ -182,6 +183,8 @@ public: ProportionalHeight, Id, State, + IsEdited, + IsEditable, IsEncrypted, IsRoomEncrypted, ReplyTo, @@ -215,6 +218,7 @@ public: Q_INVOKABLE void viewDecryptedRawMessage(QString id) const; Q_INVOKABLE void openUserProfile(QString userid, bool global = false); Q_INVOKABLE void openRoomSettings(); + Q_INVOKABLE void editAction(QString id); Q_INVOKABLE void replyAction(QString id); Q_INVOKABLE void readReceiptsAction(QString id) const; Q_INVOKABLE void redactEvent(QString id); @@ -258,6 +262,9 @@ public slots: QString reply() const { return reply_; } void setReply(QString newReply) { + if (edit_.startsWith('m')) + return; + if (reply_ != newReply) { reply_ = newReply; emit replyChanged(reply_); @@ -270,6 +277,9 @@ public slots: emit replyChanged(reply_); } } + QString edit() const { return edit_; } + void setEdit(QString newEdit); + void resetEdit(); void setDecryptDescription(bool decrypt) { decryptDescription = decrypt; } void clearTimeline() { events.clearTimeline(); } void receivedSessionKey(const std::string &session_key) @@ -294,6 +304,7 @@ signals: void newEncryptedImage(mtx::crypto::EncryptedFile encryptionInfo); void typingUsersChanged(std::vector<QString> users); void replyChanged(QString reply); + void editChanged(QString reply); void paginationInProgressChanged(const bool); void newCallEvent(const mtx::events::collections::TimelineEvents &event); @@ -324,8 +335,8 @@ private: bool decryptDescription = true; bool m_paginationInProgress = false; - QString currentId; - QString reply_; + QString currentId, currentReadId; + QString reply_, edit_; std::vector<QString> typingUsers_; TimelineViewManager *manager_; diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 0ed680f856ad308008175e772a6658b2304674db..f2e6d571fa200bb838cce14d0d2708e50e72d3bf 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -21,6 +21,7 @@ #include "dialogs/ImageOverlay.h" #include "emoji/EmojiModel.h" #include "emoji/Provider.h" +#include "ui/NhekoCursorShape.h" #include "ui/NhekoDropArea.h" #include <iostream> //only for debugging @@ -118,6 +119,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice"); qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser"); qmlRegisterType<NhekoDropArea>("im.nheko", 1, 0, "NhekoDropArea"); + qmlRegisterType<NhekoCursorShape>("im.nheko", 1, 0, "CursorShape"); qmlRegisterUncreatableType<DeviceVerificationFlow>( "im.nheko", 1, 0, "DeviceVerificationFlow", "Can't create verification flow from QML!"); qmlRegisterUncreatableType<UserProfile>( @@ -176,10 +178,6 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par view->setResizeMode(QQuickWidget::SizeRootObjectToView); container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) - view->quickWindow()->setTextRenderType(QQuickWindow::NativeTextRendering); -#endif - connect(view, &QQuickWidget::statusChanged, this, [](QQuickWidget::Status status) { nhlog::ui()->debug("Status changed to {}", status); }); @@ -508,9 +506,11 @@ TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QSt // If selfReactedEvent is empty, that means we haven't previously reacted if (selfReactedEvent.isEmpty()) { mtx::events::msg::Reaction reaction; - reaction.relates_to.rel_type = mtx::common::RelationType::Annotation; - reaction.relates_to.event_id = reactedEvent.toStdString(); - reaction.relates_to.key = reactionKey.toStdString(); + mtx::common::Relation rel; + rel.rel_type = mtx::common::RelationType::Annotation; + rel.event_id = reactedEvent.toStdString(); + rel.key = reactionKey.toStdString(); + reaction.relations.relations.push_back(rel); timeline_->sendMessageEvent(reaction, mtx::events::EventType::Reaction); // Otherwise, we have previously reacted and the reaction should be redacted @@ -546,3 +546,9 @@ TimelineViewManager::queueCallMessage(const QString &roomid, { models.value(roomid)->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp); } + +void +TimelineViewManager::focusMessageInput() +{ + emit focusInput(); +} diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 3e58bb43dd73c655ec08b67c0523e044f62c616e..61fce5742870292bc230d9e4409d5514fdce6b4f 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -66,6 +66,7 @@ public: Q_INVOKABLE void openLink(QString link) const; + Q_INVOKABLE void focusMessageInput(); Q_INVOKABLE void openInviteUsersDialog(); Q_INVOKABLE void openMemberListDialog() const; Q_INVOKABLE void openLeaveRoomDialog() const; @@ -86,6 +87,7 @@ signals: void showRoomList(); void narrowViewChanged(); void focusChanged(); + void focusInput(); public slots: void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids); diff --git a/src/ui/NhekoCursorShape.cpp b/src/ui/NhekoCursorShape.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06b0a321bd5761559b7b6f69842d08ef6fad5d82 --- /dev/null +++ b/src/ui/NhekoCursorShape.cpp @@ -0,0 +1,25 @@ +#include "NhekoCursorShape.h" + +#include <QCursor> + +NhekoCursorShape::NhekoCursorShape(QQuickItem *parent) + : QQuickItem(parent) + , currentShape_(Qt::CursorShape::ArrowCursor) +{} + +Qt::CursorShape +NhekoCursorShape::cursorShape() const +{ + return cursor().shape(); +} + +void +NhekoCursorShape::setCursorShape(Qt::CursorShape cursorShape) +{ + if (currentShape_ == cursorShape) + return; + + currentShape_ = cursorShape; + setCursor(cursorShape); + emit cursorShapeChanged(); +} diff --git a/src/ui/NhekoCursorShape.h b/src/ui/NhekoCursorShape.h new file mode 100644 index 0000000000000000000000000000000000000000..2eab5e42a8631f566065609a56c015b395289ff3 --- /dev/null +++ b/src/ui/NhekoCursorShape.h @@ -0,0 +1,26 @@ +#pragma once + +// see +// https://stackoverflow.com/questions/27821054/how-to-change-cursor-shape-in-qml-when-mousearea-is-covered-with-another-mousear/29382092#29382092 + +#include <QQuickItem> + +class NhekoCursorShape : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY + cursorShapeChanged) + +public: + explicit NhekoCursorShape(QQuickItem *parent = 0); + +private: + Qt::CursorShape cursorShape() const; + void setCursorShape(Qt::CursorShape cursorShape); + + Qt::CursorShape currentShape_; + +signals: + void cursorShapeChanged(); +}; diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index 274ed9271f60528b6c53bb7f5c40d9bf91e8e964..77f6ced5211f04d5da672905634e7c821dc22898 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -314,9 +314,8 @@ UserProfile::changeAvatar() return; } - const auto bin = file.peek(file.size()); - const auto payload = std::string(bin.data(), bin.size()); - const auto dimensions = QImageReader(&file).size(); + const auto bin = file.peek(file.size()); + const auto payload = std::string(bin.data(), bin.size()); isLoading_ = true; emit loadingChanged(); @@ -328,7 +327,6 @@ UserProfile::changeAvatar() mime.name().toStdString(), QFileInfo(fileName).fileName().toStdString(), [this, - dimensions, payload, mimetype = mime.name().toStdString(), size = payload.size(), @@ -367,15 +365,15 @@ UserProfile::changeAvatar() void UserProfile::updateRoomMemberState(mtx::events::state::Member member) { - http::client()->send_state_event( - roomid_.toStdString(), - http::client()->user_id().to_string(), - member, - [this](mtx::responses::EventId, mtx::http::RequestErr err) { - if (err) - nhlog::net()->error("Failed to update room member state : ", - err->matrix_error.error); - }); + http::client()->send_state_event(roomid_.toStdString(), + http::client()->user_id().to_string(), + member, + [](mtx::responses::EventId, mtx::http::RequestErr err) { + if (err) + nhlog::net()->error( + "Failed to update room member state : ", + err->matrix_error.error); + }); } void